PageRenderTime 298ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 0ms

/contentbank/classes/content.php

https://github.com/alanbarrett/moodle
PHP | 345 lines | 163 code | 29 blank | 153 comment | 17 complexity | 04e914a5091d659305b29aa19f140f87 MD5 | raw file
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Content manager class
  18. *
  19. * @package core_contentbank
  20. * @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. namespace core_contentbank;
  24. use core_text;
  25. use stored_file;
  26. use stdClass;
  27. use coding_exception;
  28. use context;
  29. use moodle_url;
  30. use core\event\contentbank_content_updated;
  31. /**
  32. * Content manager class
  33. *
  34. * @package core_contentbank
  35. * @copyright 2020 Amaia Anabitarte <amaia@moodle.com>
  36. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37. */
  38. abstract class content {
  39. /** @var stdClass $content The content of the current instance. **/
  40. protected $content = null;
  41. /**
  42. * Content bank constructor
  43. *
  44. * @param stdClass $record A contentbank_content record.
  45. * @throws coding_exception If content type is not right.
  46. */
  47. public function __construct(stdClass $record) {
  48. // Content type should exist and be linked to plugin classname.
  49. $classname = $record->contenttype.'\\content';
  50. if (get_class($this) != $classname) {
  51. throw new coding_exception(get_string('contenttypenotfound', 'error', $record->contenttype));
  52. }
  53. $typeclass = $record->contenttype.'\\contenttype';
  54. if (!class_exists($typeclass)) {
  55. throw new coding_exception(get_string('contenttypenotfound', 'error', $record->contenttype));
  56. }
  57. // A record with the id must exist in 'contentbank_content' table.
  58. // To improve performance, we are only checking the id is set, but no querying the database.
  59. if (!isset($record->id)) {
  60. throw new coding_exception(get_string('invalidcontentid', 'error'));
  61. }
  62. $this->content = $record;
  63. }
  64. /**
  65. * Returns $this->content.
  66. *
  67. * @return stdClass $this->content.
  68. */
  69. public function get_content(): stdClass {
  70. return $this->content;
  71. }
  72. /**
  73. * Returns $this->content->contenttype.
  74. *
  75. * @return string $this->content->contenttype.
  76. */
  77. public function get_content_type(): string {
  78. return $this->content->contenttype;
  79. }
  80. /**
  81. * Return the contenttype instance of this content.
  82. *
  83. * @return contenttype The content type instance
  84. */
  85. public function get_content_type_instance(): contenttype {
  86. $context = context::instance_by_id($this->content->contextid);
  87. $contenttypeclass = "\\{$this->content->contenttype}\\contenttype";
  88. return new $contenttypeclass($context);
  89. }
  90. /**
  91. * Returns $this->content->timemodified.
  92. *
  93. * @return int $this->content->timemodified.
  94. */
  95. public function get_timemodified(): int {
  96. return $this->content->timemodified;
  97. }
  98. /**
  99. * Updates content_bank table with information in $this->content.
  100. *
  101. * @return boolean True if the content has been succesfully updated. False otherwise.
  102. * @throws \coding_exception if not loaded.
  103. */
  104. public function update_content(): bool {
  105. global $USER, $DB;
  106. // A record with the id must exist in 'contentbank_content' table.
  107. // To improve performance, we are only checking the id is set, but no querying the database.
  108. if (!isset($this->content->id)) {
  109. throw new coding_exception(get_string('invalidcontentid', 'error'));
  110. }
  111. $this->content->usermodified = $USER->id;
  112. $this->content->timemodified = time();
  113. $result = $DB->update_record('contentbank_content', $this->content);
  114. if ($result) {
  115. // Trigger an event for updating this content.
  116. $event = contentbank_content_updated::create_from_record($this->content);
  117. $event->trigger();
  118. }
  119. return $result;
  120. }
  121. /**
  122. * Set a new name to the content.
  123. *
  124. * @param string $name The name of the content.
  125. * @return bool True if the content has been succesfully updated. False otherwise.
  126. * @throws \coding_exception if not loaded.
  127. */
  128. public function set_name(string $name): bool {
  129. $name = trim($name);
  130. if (empty($name)) {
  131. return false;
  132. }
  133. // Clean name.
  134. $name = clean_param($name, PARAM_TEXT);
  135. if (core_text::strlen($name) > 255) {
  136. $name = core_text::substr($name, 0, 255);
  137. }
  138. $oldname = $this->content->name;
  139. $this->content->name = $name;
  140. $updated = $this->update_content();
  141. if (!$updated) {
  142. $this->content->name = $oldname;
  143. }
  144. return $updated;
  145. }
  146. /**
  147. * Returns the name of the content.
  148. *
  149. * @return string The name of the content.
  150. */
  151. public function get_name(): string {
  152. return $this->content->name;
  153. }
  154. /**
  155. * Set a new contextid to the content.
  156. *
  157. * @param int $contextid The new contextid of the content.
  158. * @return bool True if the content has been succesfully updated. False otherwise.
  159. */
  160. public function set_contextid(int $contextid): bool {
  161. if ($this->content->contextid == $contextid) {
  162. return true;
  163. }
  164. $oldcontextid = $this->content->contextid;
  165. $this->content->contextid = $contextid;
  166. $updated = $this->update_content();
  167. if ($updated) {
  168. // Move files to new context
  169. $fs = get_file_storage();
  170. $fs->move_area_files_to_new_context($oldcontextid, $contextid, 'contentbank', 'public', $this->content->id);
  171. } else {
  172. $this->content->contextid = $oldcontextid;
  173. }
  174. return $updated;
  175. }
  176. /**
  177. * Returns the contextid of the content.
  178. *
  179. * @return int The id of the content context.
  180. */
  181. public function get_contextid(): string {
  182. return $this->content->contextid;
  183. }
  184. /**
  185. * Returns the content ID.
  186. *
  187. * @return int The content ID.
  188. */
  189. public function get_id(): int {
  190. return $this->content->id;
  191. }
  192. /**
  193. * Change the content instanceid value.
  194. *
  195. * @param int $instanceid New instanceid for this content
  196. * @return boolean True if the instanceid has been succesfully updated. False otherwise.
  197. */
  198. public function set_instanceid(int $instanceid): bool {
  199. $this->content->instanceid = $instanceid;
  200. return $this->update_content();
  201. }
  202. /**
  203. * Returns the $instanceid of this content.
  204. *
  205. * @return int contentbank instanceid
  206. */
  207. public function get_instanceid(): int {
  208. return $this->content->instanceid;
  209. }
  210. /**
  211. * Change the content config values.
  212. *
  213. * @param string $configdata New config information for this content
  214. * @return boolean True if the configdata has been succesfully updated. False otherwise.
  215. */
  216. public function set_configdata(string $configdata): bool {
  217. $this->content->configdata = $configdata;
  218. return $this->update_content();
  219. }
  220. /**
  221. * Return the content config values.
  222. *
  223. * @return mixed Config information for this content (json decoded)
  224. */
  225. public function get_configdata() {
  226. return $this->content->configdata;
  227. }
  228. /**
  229. * Import a file as a valid content.
  230. *
  231. * By default, all content has a public file area to interact with the content bank
  232. * repository. This method should be overridden by contentypes which does not simply
  233. * upload to the public file area.
  234. *
  235. * If any, the method will return the final stored_file. This way it can be invoked
  236. * as parent::import_file in case any plugin want to store the file in the public area
  237. * and also parse it.
  238. *
  239. * @throws file_exception If file operations fail
  240. * @param stored_file $file File to store in the content file area.
  241. * @return stored_file|null the stored content file or null if the file is discarted.
  242. */
  243. public function import_file(stored_file $file): ?stored_file {
  244. $originalfile = $this->get_file();
  245. if ($originalfile) {
  246. $originalfile->replace_file_with($file);
  247. return $originalfile;
  248. } else {
  249. $itemid = $this->get_id();
  250. $fs = get_file_storage();
  251. $filerecord = [
  252. 'contextid' => $this->get_contextid(),
  253. 'component' => 'contentbank',
  254. 'filearea' => 'public',
  255. 'itemid' => $this->get_id(),
  256. 'filepath' => '/',
  257. 'filename' => $file->get_filename(),
  258. 'timecreated' => time(),
  259. ];
  260. return $fs->create_file_from_storedfile($filerecord, $file);
  261. }
  262. }
  263. /**
  264. * Returns the $file related to this content.
  265. *
  266. * @return stored_file File stored in content bank area related to the given itemid.
  267. * @throws \coding_exception if not loaded.
  268. */
  269. public function get_file(): ?stored_file {
  270. $itemid = $this->get_id();
  271. $fs = get_file_storage();
  272. $files = $fs->get_area_files(
  273. $this->content->contextid,
  274. 'contentbank',
  275. 'public',
  276. $itemid,
  277. 'itemid, filepath, filename',
  278. false
  279. );
  280. if (!empty($files)) {
  281. $file = reset($files);
  282. return $file;
  283. }
  284. return null;
  285. }
  286. /**
  287. * Returns the file url related to this content.
  288. *
  289. * @return string URL of the file stored in content bank area related to the given itemid.
  290. * @throws \coding_exception if not loaded.
  291. */
  292. public function get_file_url(): string {
  293. if (!$file = $this->get_file()) {
  294. return '';
  295. }
  296. $fileurl = moodle_url::make_pluginfile_url(
  297. $this->content->contextid,
  298. 'contentbank',
  299. 'public',
  300. $file->get_itemid(),
  301. $file->get_filepath(),
  302. $file->get_filename()
  303. );
  304. return $fileurl;
  305. }
  306. /**
  307. * Returns user has access permission for the content itself (based on what plugin needs).
  308. *
  309. * @return bool True if content could be accessed. False otherwise.
  310. */
  311. public function is_view_allowed(): bool {
  312. // There's no capability at content level to check,
  313. // but plugins can overwrite this method in case they want to check something related to content properties.
  314. return true;
  315. }
  316. }