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_reportbuilder;
20
 
21
use action_menu_filler;
22
use coding_exception;
23
use html_writer;
24
use stdClass;
25
use core\output\checkbox_toggleall;
26
use core_reportbuilder\local\models\report;
27
use core_reportbuilder\local\report\action;
28
use core_reportbuilder\local\report\base;
29
use core_reportbuilder\local\report\column;
30
 
31
/**
32
 * Base class for system reports
33
 *
34
 * @package     core_reportbuilder
35
 * @copyright   2020 Paul Holden <paulh@moodle.com>
36
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37
 */
38
abstract class system_report extends base {
39
 
40
    /** @var array $parameters */
41
    private $parameters;
42
 
43
    /** @var string[] $basefields List of base fields */
44
    private $basefields = [];
45
 
46
    /** @var callable $checkboxcallback */
47
    private $checkboxcallback = null;
48
 
49
    /** @var bool $filterformdefault Whether to use the default filters form */
50
    private $filterformdefault = true;
51
 
52
    /** @var action|action_menu_filler[] $actions */
53
    private $actions = [];
54
 
55
    /** @var column $initialsortcolumn */
56
    private $initialsortcolumn;
57
 
58
    /** @var int $initialsortdirection */
59
    private $initialsortdirection;
60
 
61
    /**
62
     * System report constructor.
63
     *
64
     * @param report $report
65
     * @param array $parameters
66
     */
67
    final public function __construct(report $report, array $parameters) {
68
        $this->parameters = $parameters;
69
 
70
        parent::__construct($report);
71
    }
72
 
73
    /**
74
     * Provide default implementation of the report name. Extending classes can implement this method to provide their own name
75
     *
76
     * @return string
77
     */
78
    public static function get_name(): string {
79
        $classparts = explode('\\', get_called_class());
80
        $classname = end($classparts);
81
 
82
        // Try to make human readable, capitalized and with spaces.
83
        return ucfirst(str_replace('_', ' ', $classname));
84
    }
85
 
86
    /**
87
     * Validates access to view this report
88
     *
89
     * This is necessary to implement independently of the page that would typically embed the report because
90
     * subsequent pages are requested via AJAX requests, and access should be validated each time
91
     *
92
     * @return bool
93
     */
94
    abstract protected function can_view(): bool;
95
 
96
    /**
97
     * Validate access to the report
98
     *
99
     * @throws report_access_exception
100
     */
101
    final public function require_can_view(): void {
102
        if (!$this->can_view()) {
103
            throw new report_access_exception();
104
        }
105
    }
106
 
107
    /**
108
     * Report validation
109
     *
110
     * @throws report_access_exception If user cannot access the report
111
     * @throws coding_exception If no default column are specified
112
     */
113
    protected function validate(): void {
114
        parent::validate();
115
 
116
        $this->require_can_view();
117
 
118
        // Ensure the report has some default columns specified.
119
        if (empty($this->get_columns())) {
120
            throw new coding_exception('No columns added');
121
        }
122
    }
123
 
124
    /**
125
     * Add list of fields that have to be always included in SQL query for actions and row classes
126
     *
127
     * Base fields are only available in system reports because they are not compatible with aggregation
128
     *
129
     * @param string $sql SQL clause for the list of fields that only uses main table or base joins
130
     */
131
    final protected function add_base_fields(string $sql): void {
132
        $this->basefields[] = $sql;
133
    }
134
 
135
    /**
136
     * Return report base fields
137
     *
138
     * @return array
139
     */
140
    final public function get_base_fields(): array {
141
        return $this->basefields;
142
    }
143
 
144
    /**
145
     * Define toggle all checkbox for the report, required row data should be defined by calling {@see add_base_fields}
146
     *
147
     * @param callable $callback Callback to return value/label for each checkbox, implementing the following signature:
148
     *      function(stdClass $row): array containing value/label pair
149
     */
150
    final protected function set_checkbox_toggleall(callable $callback): void {
151
        $this->checkboxcallback = $callback;
152
    }
153
 
154
    /**
155
     * Return instance of toggle all checkbox, if previously defined by {@see set_checkbox_toggleall}
156
     *
157
     * @param bool $ismaster
158
     * @param stdClass|null $row
159
     * @return checkbox_toggleall|null
160
     */
161
    final public function get_checkbox_toggleall(bool $ismaster, ?stdClass $row = null): ?checkbox_toggleall {
162
        if (!is_callable($this->checkboxcallback)) {
163
            return null;
164
        }
165
 
166
        // Generic content for the master checkbox, execute callback for those belonging to each row.
167
        if ($ismaster) {
168
            $value = '';
169
            $label = get_string('selectall');
170
        } else {
171
            [$value, $label] = ($this->checkboxcallback)($row);
172
        }
173
 
174
        return new checkbox_toggleall('report-select-all', $ismaster, [
175
            'id' => html_writer::random_id(),
176
            'name' => 'report-select-row[]',
177
            'value' => $value,
178
            'label' => $label,
179
            'labelclasses' => 'accesshide',
180
        ]);
181
    }
182
 
183
    /**
184
     * Override whether to use the default system report filters form, for instance this can be disabled if the UI requires
185
     * it's own custom filter management form for a specific report
186
     *
187
     * @param bool $filterformdefault
188
     */
189
    final public function set_filter_form_default(bool $filterformdefault = true): void {
190
        $this->filterformdefault = $filterformdefault;
191
    }
192
 
193
    /**
194
     * Whether to use the default filters form
195
     *
196
     * @return bool
197
     */
198
    final public function get_filter_form_default(): bool {
199
        return $this->filterformdefault;
200
    }
201
 
202
    /**
203
     * Adds an action to the report
204
     *
205
     * @param action $action
206
     */
207
    final public function add_action(action $action): void {
208
        $this->actions[] = $action;
209
    }
210
 
211
    /**
212
     * Adds action divider to the report
213
     *
214
     */
215
    final public function add_action_divider(): void {
216
        $divider = new action_menu_filler();
217
        // We need to set as not primary action because we just need add an action divider, not a new action item.
218
        $divider->primary = false;
219
        $this->actions[] = $divider;
220
    }
221
 
222
    /**
223
     * Whether report has any actions
224
     *
225
     * @return bool
226
     */
227
    final public function has_actions(): bool {
228
        return !empty($this->actions);
229
    }
230
 
231
    /**
232
     * Return report actions
233
     *
234
     * @return action|action_menu_filler[]
235
     */
236
    final public function get_actions(): array {
237
        return $this->actions;
238
    }
239
 
240
    /**
241
     * Set all report parameters
242
     *
243
     * @param array $parameters
244
     */
245
    final public function set_parameters(array $parameters): void {
246
        $this->parameters = $parameters;
247
    }
248
 
249
    /**
250
     * Return all report parameters
251
     *
252
     * @return array
253
     */
254
    final public function get_parameters(): array {
255
        return $this->parameters;
256
    }
257
 
258
    /**
259
     * Return specific report parameter
260
     *
261
     * @param string $param
262
     * @param mixed $default
263
     * @param string $type
264
     * @return mixed
265
     */
266
    final public function get_parameter(string $param, $default, string $type) {
267
        if (!array_key_exists($param, $this->parameters)) {
268
            return $default;
269
        }
270
 
271
        return clean_param($this->parameters[$param], $type);
272
    }
273
 
274
    /**
275
     * Output the report
276
     *
277
     * @uses \core_reportbuilder\output\renderer::render_system_report()
278
     *
279
     * @return string
280
     */
281
    final public function output(): string {
282
        global $PAGE;
283
 
284
        /** @var \core_reportbuilder\output\renderer $renderer */
285
        $renderer = $PAGE->get_renderer('core_reportbuilder');
286
        $report = new \core_reportbuilder\output\system_report($this->get_report_persistent(), $this, $this->parameters);
287
 
288
        return $renderer->render($report);
289
    }
290
 
291
    /**
292
     * CSS classes to add to the row. Can be overridden by system reports do define class to be added to output according to
293
     * content of each row
294
     *
295
     * @param stdClass $row
296
     * @return string
297
     */
298
    public function get_row_class(stdClass $row): string {
299
        return '';
300
    }
301
 
302
    /**
303
     * Called before rendering each row. Can be overridden to pre-fetch/create objects and store them in the class, which can
304
     * later be used in column and action callbacks
305
     *
306
     * @param stdClass $row
307
     */
308
    public function row_callback(stdClass $row): void {
309
        return;
310
    }
311
 
312
    /**
313
     * Validates access to download this report.
314
     *
315
     * @return bool
316
     */
317
    final public function can_be_downloaded(): bool {
318
        return $this->can_view() && $this->is_downloadable();
319
    }
320
 
321
    /**
322
     * Return list of column names that will be excluded when table is downloaded. Extending classes should override this method
323
     * as appropriate
324
     *
325
     * @return string[] Array of column unique identifiers
326
     */
327
    public function get_exclude_columns_for_download(): array {
328
        return [];
329
    }
330
 
331
    /**
332
     * Set initial sort column and sort direction for the report
333
     *
334
     * @param string $uniqueidentifier
335
     * @param int $sortdirection One of SORT_ASC or SORT_DESC
336
     * @throws coding_exception
337
     */
338
    public function set_initial_sort_column(string $uniqueidentifier, int $sortdirection): void {
339
        if (!$sortcolumn = $this->get_column($uniqueidentifier)) {
340
            throw new coding_exception('Unknown column identifier', $uniqueidentifier);
341
        }
342
 
343
        $this->initialsortcolumn = $sortcolumn;
344
        $this->initialsortdirection = $sortdirection;
345
    }
346
 
347
    /**
348
     * Get initial sort column
349
     *
350
     * @return column|null
351
     */
352
    public function get_initial_sort_column(): ?column {
353
        return $this->initialsortcolumn;
354
    }
355
 
356
    /**
357
     * Get initial sort column direction
358
     *
359
     * @return int
360
     */
361
    public function get_initial_sort_direction(): int {
362
        return $this->initialsortdirection;
363
    }
364
}