Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | 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_reportbuilder\local\entities;
20
 
21
use context_course;
22
use context_helper;
23
use core_reportbuilder\local\filters\boolean_select;
24
use core_reportbuilder\local\filters\course_selector;
25
use core_reportbuilder\local\filters\date;
26
use core_reportbuilder\local\filters\select;
27
use core_reportbuilder\local\filters\text;
28
use core_reportbuilder\local\helpers\custom_fields;
29
use core_reportbuilder\local\helpers\format;
30
use core_reportbuilder\local\report\column;
31
use core_reportbuilder\local\report\filter;
32
use html_writer;
33
use lang_string;
34
use stdClass;
35
use theme_config;
36
 
37
defined('MOODLE_INTERNAL') || die();
38
 
39
global $CFG;
40
require_once($CFG->dirroot . '/course/lib.php');
41
 
42
/**
43
 * Course entity class implementation
44
 *
45
 * This entity defines all the course columns and filters to be used in any report.
46
 *
47
 * @package     core_reportbuilder
48
 * @copyright   2021 Sara Arjona <sara@moodle.com> based on Marina Glancy code.
49
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
50
 */
51
class course extends base {
52
 
53
    /**
54
     * Database tables that this entity uses
55
     *
56
     * @return string[]
57
     */
58
    protected function get_default_tables(): array {
59
        return [
60
            'course',
61
            'context',
62
            'tag_instance',
63
            'tag',
64
        ];
65
    }
66
 
67
    /**
68
     * The default title for this entity in the list of columns/filters in the report builder.
69
     *
70
     * @return lang_string
71
     */
72
    protected function get_default_entity_title(): lang_string {
73
        return new lang_string('entitycourse', 'core_reportbuilder');
74
    }
75
 
76
    /**
1441 ariadna 77
     * Initialise the entity
1 efrain 78
     *
79
     * @return base
80
     */
81
    public function initialise(): base {
1441 ariadna 82
        $tablealias = $this->get_table_alias('course');
1 efrain 83
 
1441 ariadna 84
        $customfields = (new custom_fields(
85
            "{$tablealias}.id",
86
            $this->get_entity_name(),
87
            'core_course',
88
            'course',
89
        ))
90
            ->add_joins($this->get_joins());
91
 
1 efrain 92
        $columns = array_merge($this->get_all_columns(), $customfields->get_columns());
93
        foreach ($columns as $column) {
94
            $this->add_column($column);
95
        }
96
 
1441 ariadna 97
        // All the filters defined by the entity can also be used as conditions.
1 efrain 98
        $filters = array_merge($this->get_all_filters(), $customfields->get_filters());
99
        foreach ($filters as $filter) {
100
            $this
101
                ->add_condition($filter)
102
                ->add_filter($filter);
103
        }
104
 
105
        return $this;
106
    }
107
 
108
    /**
109
     * Return syntax for joining on the context table
110
     *
111
     * @return string
112
     */
113
    public function get_context_join(): string {
114
        $coursealias = $this->get_table_alias('course');
115
        $contextalias = $this->get_table_alias('context');
116
 
117
        return "LEFT JOIN {context} {$contextalias}
118
            ON {$contextalias}.contextlevel = " . CONTEXT_COURSE . "
119
           AND {$contextalias}.instanceid = {$coursealias}.id";
120
    }
121
 
122
    /**
123
     * Course fields.
124
     *
125
     * @return array
126
     */
127
    protected function get_course_fields(): array {
128
        return [
129
            'fullname' => new lang_string('fullnamecourse'),
130
            'shortname' => new lang_string('shortnamecourse'),
131
            'idnumber' => new lang_string('idnumbercourse'),
132
            'summary' => new lang_string('coursesummary'),
133
            'format' => new lang_string('format'),
134
            'startdate' => new lang_string('startdate'),
135
            'enddate' => new lang_string('enddate'),
136
            'visible' => new lang_string('coursevisibility'),
137
            'groupmode' => new lang_string('groupmode', 'group'),
138
            'groupmodeforce' => new lang_string('groupmodeforce', 'group'),
139
            'lang' => new lang_string('forcelanguage'),
140
            'calendartype' => new lang_string('forcecalendartype', 'calendar'),
141
            'theme' => new lang_string('theme'),
142
            'enablecompletion' => new lang_string('enablecompletion', 'completion'),
143
            'downloadcontent' => new lang_string('downloadcoursecontent', 'course'),
144
            'timecreated' => new lang_string('timecreated', 'core_reportbuilder'),
145
            'timemodified' => new lang_string('timemodified', 'core_reportbuilder'),
146
        ];
147
    }
148
 
149
    /**
150
     * Return appropriate column type for given user field
151
     *
152
     * @param string $coursefield
153
     * @return int
154
     */
155
    protected function get_course_field_type(string $coursefield): int {
156
        switch ($coursefield) {
157
            case 'downloadcontent':
158
            case 'enablecompletion':
159
            case 'groupmodeforce':
160
            case 'visible':
161
                $fieldtype = column::TYPE_BOOLEAN;
162
                break;
163
            case 'startdate':
164
            case 'enddate':
165
            case 'timecreated':
166
            case 'timemodified':
167
                $fieldtype = column::TYPE_TIMESTAMP;
168
                break;
169
            case 'summary':
170
                $fieldtype = column::TYPE_LONGTEXT;
171
                break;
172
            default:
173
                $fieldtype = column::TYPE_TEXT;
174
                break;
175
        }
176
 
177
        return $fieldtype;
178
    }
179
 
180
    /**
181
     * Return joins necessary for retrieving tags
182
     *
183
     * @return string[]
184
     */
185
    public function get_tag_joins(): array {
186
        return $this->get_tag_joins_for_entity('core', 'course', $this->get_table_alias('course') . '.id');
187
    }
188
 
189
    /**
190
     * Returns list of all available columns.
191
     *
192
     * These are all the columns available to use in any report that uses this entity.
193
     *
194
     * @return column[]
195
     */
196
    protected function get_all_columns(): array {
197
        $coursefields = $this->get_course_fields();
198
        $tablealias = $this->get_table_alias('course');
199
        $contexttablealias = $this->get_table_alias('context');
200
 
201
        // Columns course full name with link, course short name with link and course id with link.
202
        $fields = [
203
            'coursefullnamewithlink' => 'fullname',
204
            'courseshortnamewithlink' => 'shortname',
205
            'courseidnumberewithlink' => 'idnumber',
206
        ];
207
        foreach ($fields as $key => $field) {
208
            $column = (new column(
209
                $key,
210
                new lang_string($key, 'core_reportbuilder'),
211
                $this->get_entity_name()
212
            ))
213
                ->add_joins($this->get_joins())
214
                ->set_type(column::TYPE_TEXT)
215
                ->add_fields("{$tablealias}.{$field} as $key, {$tablealias}.id")
216
                ->set_is_sortable(true)
217
                ->add_callback(static function(?string $value, stdClass $row): string {
218
                    if ($value === null) {
219
                        return '';
220
                    }
221
 
222
                    context_helper::preload_from_record($row);
223
 
224
                    return html_writer::link(course_get_url($row->id),
225
                        format_string($value, true, ['context' => context_course::instance($row->id)]));
226
                });
227
 
228
            // Join on the context table so that we can use it for formatting these columns later.
229
            if ($key === 'coursefullnamewithlink') {
230
                $column->add_join($this->get_context_join())
231
                    ->add_fields(context_helper::get_preload_record_columns_sql($contexttablealias));
232
            }
233
 
234
            $columns[] = $column;
235
        }
236
 
237
        foreach ($coursefields as $coursefield => $coursefieldlang) {
238
            $column = (new column(
239
                $coursefield,
240
                $coursefieldlang,
241
                $this->get_entity_name()
242
            ))
243
                ->add_joins($this->get_joins())
1441 ariadna 244
                ->set_type($this->get_course_field_type($coursefield))
245
                ->add_field("{$tablealias}.{$coursefield}")
1 efrain 246
                ->add_callback([$this, 'format'], $coursefield)
1441 ariadna 247
                ->set_is_sortable(true);
1 efrain 248
 
249
            // Join on the context table so that we can use it for formatting these columns later.
250
            if ($coursefield === 'summary' || $coursefield === 'shortname' || $coursefield === 'fullname') {
251
                $column->add_join($this->get_context_join())
252
                    ->add_field("{$tablealias}.id", 'courseid')
253
                    ->add_fields(context_helper::get_preload_record_columns_sql($contexttablealias));
254
            }
255
 
256
            $columns[] = $column;
257
        }
258
 
259
        return $columns;
260
    }
261
 
262
    /**
263
     * Returns list of all available filters
264
     *
265
     * @return array
266
     */
267
    protected function get_all_filters(): array {
268
        $filters = [];
269
        $tablealias = $this->get_table_alias('course');
270
 
271
        $fields = $this->get_course_fields();
272
        foreach ($fields as $field => $name) {
273
            $optionscallback = [static::class, 'get_options_for_' . $field];
274
            if (is_callable($optionscallback)) {
275
                $filterclass = select::class;
276
            } else if ($this->get_course_field_type($field) === column::TYPE_BOOLEAN) {
277
                $filterclass = boolean_select::class;
278
            } else if ($this->get_course_field_type($field) === column::TYPE_TIMESTAMP) {
279
                $filterclass = date::class;
280
            } else {
281
                $filterclass = text::class;
282
            }
283
 
284
            $filter = (new filter(
285
                $filterclass,
286
                $field,
287
                $name,
288
                $this->get_entity_name(),
1441 ariadna 289
                "{$tablealias}.{$field}"
1 efrain 290
            ))
291
                ->add_joins($this->get_joins());
292
 
293
            // Populate filter options by callback, if available.
294
            if (is_callable($optionscallback)) {
295
                $filter->set_options_callback($optionscallback);
296
            }
297
 
298
            $filters[] = $filter;
299
        }
300
 
301
        // We add our own custom course selector filter.
302
        $filters[] = (new filter(
303
            course_selector::class,
304
            'courseselector',
305
            new lang_string('courseselect', 'core_reportbuilder'),
306
            $this->get_entity_name(),
307
            "{$tablealias}.id"
308
        ))
309
            ->add_joins($this->get_joins());
310
 
311
        return $filters;
312
    }
313
 
314
    /**
315
     * Gets list of options if the filter supports it
316
     *
317
     * @param string $fieldname
318
     * @return null|array
319
     */
320
    protected function get_options_for(string $fieldname): ?array {
321
        static $cached = [];
322
        if (!array_key_exists($fieldname, $cached)) {
323
            $callable = [static::class, 'get_options_for_' . $fieldname];
324
            if (is_callable($callable)) {
325
                $cached[$fieldname] = $callable();
326
            } else {
327
                $cached[$fieldname] = null;
328
            }
329
        }
330
        return $cached[$fieldname];
331
    }
332
 
333
    /**
334
     * List of options for the field groupmode.
335
     *
336
     * @return array
337
     */
338
    public static function get_options_for_groupmode(): array {
339
        return [
340
            NOGROUPS => get_string('groupsnone', 'group'),
341
            SEPARATEGROUPS => get_string('groupsseparate', 'group'),
342
            VISIBLEGROUPS => get_string('groupsvisible', 'group'),
343
        ];
344
    }
345
 
346
    /**
347
     * List of options for the field format.
348
     *
349
     * @return array
350
     */
351
    public static function get_options_for_format(): array {
352
        global $CFG;
353
        require_once($CFG->dirroot.'/course/lib.php');
354
 
355
        $options = [];
356
 
357
        $courseformats = get_sorted_course_formats(true);
358
        foreach ($courseformats as $courseformat) {
359
            $options[$courseformat] = get_string('pluginname', "format_{$courseformat}");
360
        }
361
 
362
        return $options;
363
    }
364
 
365
    /**
366
     * List of options for the field theme.
367
     *
368
     * @return array
369
     */
370
    public static function get_options_for_theme(): array {
1441 ariadna 371
        return ['' => get_string('forceno')] + array_map(
1 efrain 372
            fn(theme_config $theme) => $theme->get_theme_name(),
373
            get_list_of_themes(),
374
        );
375
    }
376
 
377
    /**
378
     * List of options for the field lang.
379
     *
380
     * @return array
381
     */
382
    public static function get_options_for_lang(): array {
1441 ariadna 383
        return ['' => get_string('forceno')] + get_string_manager()->get_list_of_translations();
1 efrain 384
    }
385
 
386
    /**
387
     * List of options for the field.
388
     *
389
     * @return array
390
     */
391
    public static function get_options_for_calendartype(): array {
1441 ariadna 392
        return ['' => get_string('forceno')] + \core_calendar\type_factory::get_list_of_calendar_types();
1 efrain 393
    }
394
 
395
    /**
396
     * Formats the course field for display.
397
     *
398
     * @param mixed $value Current field value.
399
     * @param stdClass $row Complete row.
400
     * @param string $fieldname Name of the field to format.
401
     * @return string
402
     */
403
    public function format($value, stdClass $row, string $fieldname): string {
404
        if ($this->get_course_field_type($fieldname) === column::TYPE_TIMESTAMP) {
405
            return format::userdate($value, $row);
406
        }
407
 
408
        if ($this->get_course_field_type($fieldname) === column::TYPE_BOOLEAN) {
409
            return format::boolean_as_text($value);
410
        }
411
 
412
        // If the column has corresponding filter, determine the value from its options.
413
        $options = $this->get_options_for($fieldname);
1441 ariadna 414
        if ($options !== null && $value !== null && array_key_exists($value, $options)) {
1 efrain 415
            return $options[$value];
416
        }
417
 
418
        if (in_array($fieldname, ['fullname', 'shortname'])) {
419
            if (!$row->courseid) {
420
                return '';
421
            }
422
            context_helper::preload_from_record($row);
423
            $context = context_course::instance($row->courseid);
424
            return format_string($value, true, ['context' => $context->id, 'escape' => false]);
425
        }
426
 
427
        if (in_array($fieldname, ['summary'])) {
428
            if (!$row->courseid) {
429
                return '';
430
            }
431
            context_helper::preload_from_record($row);
432
            $context = context_course::instance($row->courseid);
433
            $summary = file_rewrite_pluginfile_urls($row->summary, 'pluginfile.php', $context->id, 'course', 'summary', null);
434
            return format_text($summary);
435
        }
436
 
437
        return s($value);
438
    }
439
}