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