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