Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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 int Visibility value. Public content is visible to all users with access to the content bank of the
45
     * appropriate context.
46
     */
47
    public const VISIBILITY_PUBLIC = 1;
48
 
49
    /**
50
     * @var int Visibility value. Unlisted content is only visible to the author and to users with
51
     * moodle/contentbank:viewunlistedcontent capability.
52
     */
53
    public const VISIBILITY_UNLISTED = 2;
54
 
55
    /** @var stdClass $content The content of the current instance. **/
56
    protected $content  = null;
57
 
58
    /**
59
     * Content bank constructor
60
     *
61
     * @param stdClass $record A contentbank_content record.
62
     * @throws coding_exception If content type is not right.
63
     */
64
    public function __construct(stdClass $record) {
65
        // Content type should exist and be linked to plugin classname.
66
        $classname = $record->contenttype.'\\content';
67
        if (get_class($this) != $classname) {
68
            throw new coding_exception(get_string('contenttypenotfound', 'error', $record->contenttype));
69
        }
70
        $typeclass = $record->contenttype.'\\contenttype';
71
        if (!class_exists($typeclass)) {
72
            throw new coding_exception(get_string('contenttypenotfound', 'error', $record->contenttype));
73
        }
74
        // A record with the id must exist in 'contentbank_content' table.
75
        // To improve performance, we are only checking the id is set, but no querying the database.
76
        if (!isset($record->id)) {
77
            throw new coding_exception(get_string('invalidcontentid', 'error'));
78
        }
79
        $this->content = $record;
80
    }
81
 
82
    /**
83
     * Returns $this->content.
84
     *
85
     * @return stdClass  $this->content.
86
     */
87
    public function get_content(): stdClass {
88
        return $this->content;
89
    }
90
 
91
    /**
92
     * Returns $this->content->contenttype.
93
     *
94
     * @return string  $this->content->contenttype.
95
     */
96
    public function get_content_type(): string {
97
        return $this->content->contenttype;
98
    }
99
 
100
    /**
101
     * Return the contenttype instance of this content.
102
     *
103
     * @return contenttype The content type instance
104
     */
105
    public function get_content_type_instance(): contenttype {
106
        $context = context::instance_by_id($this->content->contextid);
107
        $contenttypeclass = "\\{$this->content->contenttype}\\contenttype";
108
        return new $contenttypeclass($context);
109
    }
110
 
111
    /**
112
     * Returns $this->content->timemodified.
113
     *
114
     * @return int  $this->content->timemodified.
115
     */
116
    public function get_timemodified(): int {
117
        return $this->content->timemodified;
118
    }
119
 
120
    /**
121
     * Updates content_bank table with information in $this->content.
122
     *
123
     * @return boolean  True if the content has been succesfully updated. False otherwise.
124
     * @throws \coding_exception if not loaded.
125
     */
126
    public function update_content(): bool {
127
        global $USER, $DB;
128
 
129
        // A record with the id must exist in 'contentbank_content' table.
130
        // To improve performance, we are only checking the id is set, but no querying the database.
131
        if (!isset($this->content->id)) {
132
            throw new coding_exception(get_string('invalidcontentid', 'error'));
133
        }
134
        $this->content->usermodified = $USER->id;
135
        $this->content->timemodified = time();
136
        $result = $DB->update_record('contentbank_content', $this->content);
137
        if ($result) {
138
            // Trigger an event for updating this content.
139
            $event = contentbank_content_updated::create_from_record($this->content);
140
            $event->trigger();
141
        }
142
        return $result;
143
    }
144
 
145
    /**
146
     * Set a new name to the content.
147
     *
148
     * @param string $name  The name of the content.
149
     * @return bool  True if the content has been succesfully updated. False otherwise.
150
     * @throws \coding_exception if not loaded.
151
     */
152
    public function set_name(string $name): bool {
153
        $name = trim($name);
154
        if ($name === '') {
155
            return false;
156
        }
157
 
158
        // Clean name.
159
        $name = clean_param($name, PARAM_TEXT);
160
        if (core_text::strlen($name) > 255) {
161
            $name = core_text::substr($name, 0, 255);
162
        }
163
 
164
        $oldname = $this->content->name;
165
        $this->content->name = $name;
166
        $updated = $this->update_content();
167
        if (!$updated) {
168
            $this->content->name = $oldname;
169
        }
170
        return $updated;
171
    }
172
 
173
    /**
174
     * Returns the name of the content.
175
     *
176
     * @return string   The name of the content.
177
     */
178
    public function get_name(): string {
179
        return $this->content->name;
180
    }
181
 
182
    /**
183
     * Set a new contextid to the content.
184
     *
185
     * @param int $contextid  The new contextid of the content.
186
     * @return bool  True if the content has been succesfully updated. False otherwise.
187
     */
188
    public function set_contextid(int $contextid): bool {
189
        if ($this->content->contextid == $contextid) {
190
            return true;
191
        }
192
 
193
        $oldcontextid = $this->content->contextid;
194
        $this->content->contextid = $contextid;
195
        $updated = $this->update_content();
196
        if ($updated) {
197
            // Move files to new context
198
            $fs = get_file_storage();
199
            $fs->move_area_files_to_new_context($oldcontextid, $contextid, 'contentbank', 'public', $this->content->id);
200
        } else {
201
            $this->content->contextid = $oldcontextid;
202
        }
203
        return $updated;
204
    }
205
 
206
    /**
207
     * Returns the contextid of the content.
208
     *
209
     * @return int   The id of the content context.
210
     */
211
    public function get_contextid(): string {
212
        return $this->content->contextid;
213
    }
214
 
215
    /**
216
     * Returns the content ID.
217
     *
218
     * @return int   The content ID.
219
     */
220
    public function get_id(): int {
221
        return $this->content->id;
222
    }
223
 
224
    /**
225
     * Change the content instanceid value.
226
     *
227
     * @param int $instanceid    New instanceid for this content
228
     * @return boolean           True if the instanceid has been succesfully updated. False otherwise.
229
     */
230
    public function set_instanceid(int $instanceid): bool {
231
        $this->content->instanceid = $instanceid;
232
        return $this->update_content();
233
    }
234
 
235
    /**
236
     * Returns the $instanceid of this content.
237
     *
238
     * @return int   contentbank instanceid
239
     */
240
    public function get_instanceid(): int {
241
        return $this->content->instanceid;
242
    }
243
 
244
    /**
245
     * Change the content config values.
246
     *
247
     * @param string $configdata    New config information for this content
248
     * @return boolean              True if the configdata has been succesfully updated. False otherwise.
249
     */
250
    public function set_configdata(string $configdata): bool {
251
        $this->content->configdata = $configdata;
252
        return $this->update_content();
253
    }
254
 
255
    /**
256
     * Return the content config values.
257
     *
258
     * @return mixed   Config information for this content (json decoded)
259
     */
260
    public function get_configdata() {
261
        return $this->content->configdata;
262
    }
263
 
264
    /**
265
     * Sets a new content visibility and saves it to database.
266
     *
267
     * @param int $visibility Must be self::PUBLIC or self::UNLISTED
268
     * @return bool
269
     * @throws coding_exception
270
     */
271
    public function set_visibility(int $visibility): bool {
272
        if (!in_array($visibility, [self::VISIBILITY_PUBLIC, self::VISIBILITY_UNLISTED])) {
273
            return false;
274
        }
275
        $this->content->visibility = $visibility;
276
        return $this->update_content();
277
    }
278
 
279
    /**
280
     * Return true if the content may be shown to other users in the content bank.
281
     *
282
     * @return boolean
283
     */
284
    public function get_visibility(): int {
285
        return $this->content->visibility;
286
    }
287
 
288
    /**
289
     * Import a file as a valid content.
290
     *
291
     * By default, all content has a public file area to interact with the content bank
292
     * repository. This method should be overridden by contentypes which does not simply
293
     * upload to the public file area.
294
     *
295
     * If any, the method will return the final stored_file. This way it can be invoked
296
     * as parent::import_file in case any plugin want to store the file in the public area
297
     * and also parse it.
298
     *
299
     * @param stored_file $file File to store in the content file area.
300
     * @return stored_file|null the stored content file or null if the file is discarted.
301
     */
302
    public function import_file(stored_file $file): ?stored_file {
303
        $originalfile = $this->get_file();
304
        if ($originalfile) {
305
            $originalfile->replace_file_with($file);
306
            return $originalfile;
307
        } else {
308
            $fs = get_file_storage();
309
            $filerecord = [
310
                'contextid' => $this->get_contextid(),
311
                'component' => 'contentbank',
312
                'filearea' => 'public',
313
                'itemid' => $this->get_id(),
314
                'filepath' => '/',
315
                'filename' => $file->get_filename(),
316
                'timecreated' => time(),
317
            ];
318
            return $fs->create_file_from_storedfile($filerecord, $file);
319
        }
320
    }
321
 
322
    /**
323
     * Returns the $file related to this content.
324
     *
325
     * @return stored_file  File stored in content bank area related to the given itemid.
326
     * @throws \coding_exception if not loaded.
327
     */
328
    public function get_file(): ?stored_file {
329
        $itemid = $this->get_id();
330
        $fs = get_file_storage();
331
        $files = $fs->get_area_files(
332
            $this->content->contextid,
333
            'contentbank',
334
            'public',
335
            $itemid,
336
            'itemid, filepath, filename',
337
            false
338
        );
339
        if (!empty($files)) {
340
            $file = reset($files);
341
            return $file;
342
        }
343
        return null;
344
    }
345
 
346
    /**
347
     * Returns the places where the file associated to this content is used or an empty array if the content has no file.
348
     *
349
     * @return array of stored_file where current file content is used or empty array if it hasn't any file.
350
     * @since 3.11
351
     */
352
    public function get_uses(): ?array {
353
        $references = [];
354
 
355
        $file = $this->get_file();
356
        if ($file != null) {
357
            $fs = get_file_storage();
358
            $references = $fs->get_references_by_storedfile($file);
359
        }
360
 
361
        return $references;
362
    }
363
 
364
    /**
365
     * Returns the file url related to this content.
366
     *
367
     * @return string       URL of the file stored in content bank area related to the given itemid.
368
     * @throws \coding_exception if not loaded.
369
     */
370
    public function get_file_url(): string {
371
        if (!$file = $this->get_file()) {
372
            return '';
373
        }
374
        $fileurl = moodle_url::make_pluginfile_url(
375
            $this->content->contextid,
376
            'contentbank',
377
            'public',
378
            $file->get_itemid(),
379
            $file->get_filepath(),
380
            $file->get_filename()
381
        );
382
 
383
        return $fileurl;
384
    }
385
 
386
    /**
387
     * Returns user has access permission for the content itself (based on what plugin needs).
388
     *
389
     * @return bool     True if content could be accessed. False otherwise.
390
     */
391
    public function is_view_allowed(): bool {
392
        // Plugins can overwrite this method in case they want to check something related to content properties.
393
        global $USER;
394
        $context = \context::instance_by_id($this->get_contextid());
395
 
396
        return $USER->id == $this->content->usercreated ||
397
            $this->get_visibility() == self::VISIBILITY_PUBLIC ||
398
            has_capability('moodle/contentbank:viewunlistedcontent', $context);
399
    }
400
}