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
declare(strict_types=1);
18
 
19
namespace core_files\reportbuilder\local\entities;
20
 
21
use context;
22
use context_helper;
23
use core_collator;
24
use core_filetypes;
25
use html_writer;
26
use lang_string;
27
use license_manager;
28
use stdClass;
29
use core_reportbuilder\local\entities\base;
30
use core_reportbuilder\local\helpers\format;
31
use core_reportbuilder\local\filters\{boolean_select, date, filesize, select, text};
32
use core_reportbuilder\local\report\{column, filter};
33
 
34
/**
35
 * File entity
36
 *
37
 * @package     core_files
38
 * @copyright   2022 Paul Holden <paulh@moodle.com>
39
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40
 */
41
class file extends base {
42
 
43
    /**
44
     * Database tables that this entity uses
45
     *
46
     * @return string[]
47
     */
48
    protected function get_default_tables(): array {
49
        return [
50
            'files',
51
            'context',
52
        ];
53
    }
54
 
55
    /**
56
     * The default title for this entity
57
     *
58
     * @return lang_string
59
     */
60
    protected function get_default_entity_title(): lang_string {
61
        return new lang_string('file');
62
    }
63
 
64
    /**
65
     * Initialise the entity
66
     *
67
     * @return base
68
     */
69
    public function initialise(): base {
70
        $columns = $this->get_all_columns();
71
        foreach ($columns as $column) {
72
            $this->add_column($column);
73
        }
74
 
75
        // All the filters defined by the entity can also be used as conditions.
76
        $filters = $this->get_all_filters();
77
        foreach ($filters as $filter) {
78
            $this
79
                ->add_filter($filter)
80
                ->add_condition($filter);
81
        }
82
 
83
        return $this;
84
    }
85
 
86
    /**
87
     * Returns list of all available columns
88
     *
89
     * @return column[]
90
     */
91
    protected function get_all_columns(): array {
92
        $filesalias = $this->get_table_alias('files');
93
        $contextalias = $this->get_table_alias('context');
94
 
95
        // Name.
96
        $columns[] = (new column(
97
            'name',
98
            new lang_string('filename', 'core_repository'),
99
            $this->get_entity_name()
100
        ))
101
            ->add_joins($this->get_joins())
102
            ->set_type(column::TYPE_TEXT)
103
            ->add_field("{$filesalias}.filename")
104
            ->set_is_sortable(true);
105
 
106
        // Size.
107
        $columns[] = (new column(
108
            'size',
109
            new lang_string('size'),
110
            $this->get_entity_name()
111
        ))
112
            ->add_joins($this->get_joins())
113
            ->set_type(column::TYPE_INTEGER)
114
            ->add_field("{$filesalias}.filesize")
115
            ->add_field("CASE WHEN {$filesalias}.filename = '.' THEN 1 ELSE 0 END", 'directory')
116
            ->set_is_sortable(true)
117
            ->add_callback(static function($filesize, stdClass $fileinfo): string {
118
                // Absent file size and/or directory should not return output.
119
                if ($fileinfo->filesize === null || $fileinfo->directory) {
120
                    return '';
121
                }
122
                return display_size($fileinfo->filesize);
123
            });
124
 
125
        // Path.
126
        $columns[] = (new column(
127
            'path',
128
            new lang_string('path'),
129
            $this->get_entity_name()
130
        ))
131
            ->add_joins($this->get_joins())
132
            ->set_type(column::TYPE_TEXT)
133
            ->add_field("{$filesalias}.filepath")
134
            ->set_is_sortable(true);
135
 
136
        // Type.
137
        $columns[] = (new column(
138
            'type',
139
            new lang_string('type', 'core_repository'),
140
            $this->get_entity_name()
141
        ))
142
            ->add_joins($this->get_joins())
143
            ->set_type(column::TYPE_TEXT)
144
            ->add_field("{$filesalias}.mimetype")
145
            ->add_field("CASE WHEN {$filesalias}.filename = '.' THEN 1 ELSE 0 END", 'directory')
146
            ->set_is_sortable(true)
147
            ->add_callback(static function($mimetype, stdClass $fileinfo): string {
148
                global $CFG;
149
                require_once("{$CFG->libdir}/filelib.php");
150
 
151
                // Absent mime type and/or directory has pre-determined output.
152
                if ($fileinfo->mimetype === null && !$fileinfo->directory) {
153
                    return '';
154
                } else if ($fileinfo->directory) {
155
                    return get_string('directory');
156
                }
157
 
158
                return get_mimetype_description($fileinfo->mimetype);
159
            });
160
 
161
        // Icon.
162
        $columns[] = (new column(
163
            'icon',
164
            new lang_string('icon'),
165
            $this->get_entity_name()
166
        ))
167
            ->add_joins($this->get_joins())
168
            ->set_type(column::TYPE_TEXT)
169
            ->add_field("{$filesalias}.mimetype")
170
            ->add_field("CASE WHEN {$filesalias}.filename = '.' THEN 1 ELSE 0 END", 'directory')
171
            ->set_disabled_aggregation_all()
172
            ->add_callback(static function($mimetype, stdClass $fileinfo): string {
173
                global $CFG, $OUTPUT;
174
                require_once("{$CFG->libdir}/filelib.php");
175
 
176
                if ($fileinfo->mimetype === null && !$fileinfo->directory) {
177
                    return '';
178
                }
179
 
180
                if ($fileinfo->directory) {
181
                    $icon = file_folder_icon();
182
                    $description = get_string('directory');
183
                } else {
184
                    $icon = file_file_icon($fileinfo);
185
                    $description = get_mimetype_description($fileinfo->mimetype);
186
                }
187
 
188
                return $OUTPUT->pix_icon($icon, $description, 'moodle', ['class' => 'iconsize-medium']);
189
            });
190
 
191
        // Author.
192
        $columns[] = (new column(
193
            'author',
194
            new lang_string('author', 'core_repository'),
195
            $this->get_entity_name()
196
        ))
197
            ->add_joins($this->get_joins())
198
            ->set_type(column::TYPE_TEXT)
199
            ->add_field("{$filesalias}.author")
200
            ->set_is_sortable(true);
201
 
202
        // License.
203
        $columns[] = (new column(
204
            'license',
205
            new lang_string('license', 'core_repository'),
206
            $this->get_entity_name()
207
        ))
208
            ->add_joins($this->get_joins())
209
            ->set_type(column::TYPE_TEXT)
210
            ->add_field("{$filesalias}.license")
211
            ->set_is_sortable(true)
212
            ->add_callback(static function(?string $license): string {
213
                global $CFG;
214
                require_once("{$CFG->libdir}/licenselib.php");
215
 
216
                $licenses = license_manager::get_licenses();
217
                if ($license === null || !array_key_exists($license, $licenses)) {
218
                    return '';
219
                }
220
                return $licenses[$license]->fullname;
221
            });
222
 
223
        // Context.
224
        $columns[] = (new column(
225
            'context',
226
            new lang_string('context'),
227
            $this->get_entity_name()
228
        ))
229
            ->add_joins($this->get_joins())
230
            ->set_type(column::TYPE_TEXT)
231
            ->add_join("LEFT JOIN {context} {$contextalias} ON {$contextalias}.id = {$filesalias}.contextid")
232
            ->add_fields("{$filesalias}.contextid, " . context_helper::get_preload_record_columns_sql($contextalias))
233
            // Sorting may not order alphabetically, but will at least group contexts together.
234
            ->set_is_sortable(true)
235
            ->set_is_deprecated('See \'context:name\' for replacement')
236
            ->add_callback(static function($contextid, stdClass $context): string {
237
                if ($contextid === null) {
238
                    return '';
239
                }
240
 
241
                context_helper::preload_from_record($context);
242
                return context::instance_by_id($contextid)->get_context_name();
243
            });
244
 
245
        // Context link.
246
        $columns[] = (new column(
247
            'contexturl',
248
            new lang_string('contexturl'),
249
            $this->get_entity_name()
250
        ))
251
            ->add_joins($this->get_joins())
252
            ->set_type(column::TYPE_TEXT)
253
            ->add_join("LEFT JOIN {context} {$contextalias} ON {$contextalias}.id = {$filesalias}.contextid")
254
            ->add_fields("{$filesalias}.contextid, " . context_helper::get_preload_record_columns_sql($contextalias))
255
            // Sorting may not order alphabetically, but will at least group contexts together.
256
            ->set_is_sortable(true)
257
            ->set_is_deprecated('See \'context:link\' for replacement')
258
            ->add_callback(static function($contextid, stdClass $context): string {
259
                if ($contextid === null) {
260
                    return '';
261
                }
262
 
263
                context_helper::preload_from_record($context);
264
                $context = context::instance_by_id($contextid);
265
 
266
                return html_writer::link($context->get_url(), $context->get_context_name());
267
            });
268
 
269
        // Content hash.
270
        $columns[] = (new column(
271
             'contenthash',
272
            new lang_string('contenthash', 'core_files'),
273
            $this->get_entity_name()
274
        ))
275
            ->add_joins($this->get_joins())
276
            ->set_type(column::TYPE_TEXT)
277
            ->add_field("{$filesalias}.contenthash")
278
            ->set_is_sortable(true);
279
 
280
        // Component.
281
        $columns[] = (new column(
282
            'component',
283
            new lang_string('plugin'),
284
            $this->get_entity_name()
285
        ))
286
            ->add_joins($this->get_joins())
287
            ->set_type(column::TYPE_TEXT)
288
            ->add_fields("{$filesalias}.component")
289
            ->set_is_sortable(true);
290
 
291
        // Area.
292
        $columns[] = (new column(
293
            'area',
294
            new lang_string('pluginarea'),
295
            $this->get_entity_name()
296
        ))
297
            ->add_joins($this->get_joins())
298
            ->set_type(column::TYPE_TEXT)
299
            ->add_fields("{$filesalias}.filearea")
300
            ->set_is_sortable(true);
301
 
302
        // Item ID.
303
        $columns[] = (new column(
304
            'itemid',
305
            new lang_string('pluginitemid'),
306
            $this->get_entity_name()
307
        ))
308
            ->add_joins($this->get_joins())
309
            ->set_type(column::TYPE_INTEGER)
310
            ->add_fields("{$filesalias}.itemid")
311
            ->set_is_sortable(true)
312
            ->set_disabled_aggregation_all();
313
 
314
        // Time created.
315
        $columns[] = (new column(
316
            'timecreated',
317
            new lang_string('timecreated', 'core_reportbuilder'),
318
            $this->get_entity_name()
319
        ))
320
            ->add_joins($this->get_joins())
321
            ->set_type(column::TYPE_TIMESTAMP)
322
            ->add_field("{$filesalias}.timecreated")
323
            ->add_callback([format::class, 'userdate'])
324
            ->set_is_sortable(true);
325
 
326
        return $columns;
327
    }
328
 
329
    /**
330
     * Return list of all available filters
331
     *
332
     * @return filter[]
333
     */
334
    protected function get_all_filters(): array {
335
        $filesalias = $this->get_table_alias('files');
336
 
337
        // Directory.
338
        $filters[] = (new filter(
339
            boolean_select::class,
340
            'directory',
341
            new lang_string('directory'),
342
            $this->get_entity_name(),
343
            "CASE WHEN {$filesalias}.filename = '.' THEN 1 ELSE 0 END"
344
        ))
345
            ->add_joins($this->get_joins());
346
 
347
        // Draft.
348
        $filters[] = (new filter(
349
            boolean_select::class,
350
            'draft',
351
            new lang_string('areauserdraft', 'core_repository'),
352
            $this->get_entity_name(),
353
            "CASE WHEN {$filesalias}.component = 'user' AND {$filesalias}.filearea = 'draft' THEN 1 ELSE 0 END"
354
        ))
355
            ->add_joins($this->get_joins());
356
 
357
        // Name.
358
        $filters[] = (new filter(
359
            text::class,
360
            'name',
361
            new lang_string('filename', 'core_repository'),
362
            $this->get_entity_name(),
363
            "{$filesalias}.filename"
364
        ))
365
            ->add_joins($this->get_joins());
366
 
367
        // Size.
368
        $filters[] = (new filter(
369
            filesize::class,
370
            'size',
371
            new lang_string('size'),
372
            $this->get_entity_name(),
373
            "{$filesalias}.filesize"
374
        ))
375
            ->add_joins($this->get_joins());
376
 
377
        // Type.
378
        $filters[] = (new filter(
379
            select::class,
380
            'type',
381
            new lang_string('type', 'core_repository'),
382
            $this->get_entity_name(),
383
            "{$filesalias}.mimetype"
384
        ))
385
            ->add_joins($this->get_joins())
386
            ->set_options_callback(static function(): array {
387
                $mimetypenames = array_column(core_filetypes::get_types(), 'type');
388
 
389
                // Convert the names into a map of name => description.
390
                $mimetypes = array_combine($mimetypenames, array_map(static function(string $mimetype): string {
391
                    return get_mimetype_description($mimetype);
392
                }, $mimetypenames));
393
 
394
                core_collator::asort($mimetypes);
395
                return $mimetypes;
396
            });
397
 
398
        // License (consider null = 'unknown/license not specified' for filtering purposes).
399
        $filters[] = (new filter(
400
            select::class,
401
            'license',
402
            new lang_string('license', 'core_repository'),
403
            $this->get_entity_name(),
404
            "COALESCE({$filesalias}.license, 'unknown')"
405
        ))
406
            ->add_joins($this->get_joins())
407
            ->set_options_callback(static function(): array {
408
                global $CFG;
409
                require_once("{$CFG->libdir}/licenselib.php");
410
 
411
                $licenses = license_manager::get_licenses();
412
 
413
                return array_map(static function(stdClass $license): string {
414
                    return $license->fullname;
415
                }, $licenses);
416
            });
417
 
418
        // Content hash.
419
        $filters[] = (new filter(
420
            text::class,
421
            'contenthash',
422
            new lang_string('contenthash', 'core_files'),
423
            $this->get_entity_name(),
424
            "{$filesalias}.contenthash"
425
        ))
426
            ->add_joins($this->get_joins());
427
 
428
        // Time created.
429
        $filters[] = (new filter(
430
            date::class,
431
            'timecreated',
432
            new lang_string('timecreated', 'core_reportbuilder'),
433
            $this->get_entity_name(),
434
            "{$filesalias}.timecreated"
435
        ))
436
            ->add_joins($this->get_joins())
437
            ->set_limited_operators([
438
                date::DATE_ANY,
439
                date::DATE_RANGE,
440
                date::DATE_LAST,
441
                date::DATE_CURRENT,
442
            ]);
443
 
444
        return $filters;
445
    }
446
}