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\report;
20
 
21
use coding_exception;
22
use context;
23
use lang_string;
24
use core_reportbuilder\local\entities\base as entity_base;
25
use core_reportbuilder\local\filters\base as filter_base;
1441 ariadna 26
use core_reportbuilder\local\helpers\{database, user_filter_manager};
1 efrain 27
use core_reportbuilder\local\models\report;
1441 ariadna 28
use core_reportbuilder\output\report_action;
1 efrain 29
 
30
/**
31
 * Base class for all reports
32
 *
33
 * @package     core_reportbuilder
34
 * @copyright   2020 Paul Holden <paulh@moodle.com>
35
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 */
37
abstract class base {
38
 
39
    /** @var int Custom report type value */
40
    public const TYPE_CUSTOM_REPORT = 0;
41
 
42
    /** @var int System report type value */
43
    public const TYPE_SYSTEM_REPORT = 1;
44
 
45
    /** @var int Default paging limit */
46
    public const DEFAULT_PAGESIZE = 30;
47
 
48
    /** @var report $report Report persistent */
49
    private $report;
50
 
51
    /** @var string $maintable */
52
    private $maintable = '';
53
 
54
    /** @var string $maintablealias */
55
    private $maintablealias = '';
56
 
57
    /** @var array $sqljoins */
58
    private $sqljoins = [];
59
 
60
    /** @var array $sqlwheres */
61
    private $sqlwheres = [];
62
 
63
    /** @var array $sqlparams */
64
    private $sqlparams = [];
65
 
66
    /** @var entity_base[] $entities */
67
    private $entities = [];
68
 
69
    /** @var lang_string[] */
70
    private $entitytitles = [];
71
 
72
    /** @var column[] $columns */
73
    private $columns = [];
74
 
75
    /** @var filter[] $conditions */
76
    private $conditions = [];
77
 
78
    /** @var filter[] $filters */
79
    private $filters = [];
80
 
81
    /** @var bool $downloadable Set if the report can be downloaded */
82
    private $downloadable = false;
83
 
84
    /** @var string $downloadfilename Name of the downloaded file */
85
    private $downloadfilename = '';
86
 
87
    /** @var int Default paging size */
88
    private $defaultperpage = self::DEFAULT_PAGESIZE;
89
 
1441 ariadna 90
    /** @var report_action $reportaction */
91
    private report_action|null $reportaction = null;
92
 
93
    /** @var string $reportinfocontainer */
94
    private string $reportinfocontainer = '';
95
 
1 efrain 96
    /** @var array $attributes */
97
    private $attributes = [];
98
 
99
    /** @var lang_string $noresultsnotice */
100
    private $noresultsnotice;
101
 
102
    /**
103
     * Base report constructor
104
     *
105
     * @param report $report
106
     */
107
    public function __construct(report $report) {
108
        $this->report = $report;
109
        $this->noresultsnotice = new lang_string('nothingtodisplay');
110
 
111
        // Initialise and validate the report.
112
        $this->initialise();
113
        $this->validate();
114
    }
115
 
116
    /**
117
     * Returns persistent class used when initialising this report
118
     *
119
     * @return report
120
     */
121
    final public function get_report_persistent(): report {
122
        return $this->report;
123
    }
124
 
125
    /**
126
     * Return user friendly name of the report
127
     *
128
     * @return string
129
     */
130
    abstract public static function get_name(): string;
131
 
132
    /**
133
     * Initialise report. Specify which columns, filters, etc should be present
134
     *
135
     * To set the base query use:
136
     * - {@see set_main_table}
137
     * - {@see add_base_condition_simple} or {@see add_base_condition_sql}
138
     * - {@see add_join}
139
     *
140
     * To add content to the report use:
141
     * - {@see add_entity}
142
     * - {@see add_column}
143
     * - {@see add_filter}
144
     * - etc
145
     */
146
    abstract protected function initialise(): void;
147
 
148
    /**
149
     * Get the report availability. Sub-classes should override this method to declare themselves unavailable, for example if
150
     * they require classes that aren't present due to missing plugin
151
     *
152
     * @return bool
153
     */
154
    public static function is_available(): bool {
155
        return true;
156
    }
157
 
158
    /**
159
     * Perform some basic validation about expected class properties
160
     *
161
     * @throws coding_exception
162
     */
163
    protected function validate(): void {
164
        if (empty($this->maintable)) {
165
            throw new coding_exception('Report must define main table by calling $this->set_main_table()');
166
        }
167
 
168
        if (empty($this->columns)) {
169
            throw new coding_exception('Report must define at least one column by calling $this->add_column()');
170
        }
171
    }
172
 
173
    /**
174
     * Set the main table and alias for the SQL query
175
     *
176
     * @param string $tablename
177
     * @param string $tablealias
178
     */
179
    final public function set_main_table(string $tablename, string $tablealias = ''): void {
180
        $this->maintable = $tablename;
181
        $this->maintablealias = $tablealias;
182
    }
183
 
184
    /**
185
     * Get the main table name
186
     *
187
     * @return string
188
     */
189
    final public function get_main_table(): string {
190
        return $this->maintable;
191
    }
192
 
193
    /**
194
     * Get the alias for the main table
195
     *
196
     * @return string
197
     */
198
    final public function get_main_table_alias(): string {
199
        return $this->maintablealias;
200
    }
201
 
202
    /**
203
     * Adds report JOIN clause that is always added
204
     *
205
     * @param string $join
206
     * @param array $params
207
     * @param bool $validateparams Some queries might add non-standard params and validation could fail
208
     */
209
    protected function add_join(string $join, array $params = [], bool $validateparams = true): void {
210
        if ($validateparams) {
211
            database::validate_params($params);
212
        }
213
 
214
        $this->sqljoins[trim($join)] = trim($join);
215
        $this->sqlparams += $params;
216
    }
217
 
218
    /**
219
     * Return report JOIN clauses
220
     *
221
     * @return array
222
     */
223
    public function get_joins(): array {
224
        return array_values($this->sqljoins);
225
    }
226
 
227
    /**
228
     * Define simple "field = value" clause to apply to the report query
229
     *
230
     * @param string $fieldname
231
     * @param mixed $fieldvalue
232
     */
233
    final public function add_base_condition_simple(string $fieldname, $fieldvalue): void {
234
        if ($fieldvalue === null) {
235
            $this->add_base_condition_sql("{$fieldname} IS NULL");
236
        } else {
237
            $fieldvalueparam = database::generate_param_name();
238
            $this->add_base_condition_sql("{$fieldname} = :{$fieldvalueparam}", [
239
                $fieldvalueparam => $fieldvalue,
240
            ]);
241
        }
242
    }
243
 
244
    /**
245
     * Define more complex/non-empty clause to apply to the report query
246
     *
247
     * @param string $where
248
     * @param array $params Note that the param names should be generated by {@see database::generate_param_name}
249
     */
250
    final public function add_base_condition_sql(string $where, array $params = []): void {
251
 
252
        // Validate parameters always, so that potential errors are caught early.
253
        database::validate_params($params);
254
 
255
        if ($where !== '') {
256
            $this->sqlwheres[] = trim($where);
257
            $this->sqlparams = $params + $this->sqlparams;
258
        }
259
    }
260
 
261
    /**
262
     * Return base select/params for the report query
263
     *
264
     * @return array [string $select, array $params]
265
     */
266
    final public function get_base_condition(): array {
267
        return [
268
            implode(' AND ', $this->sqlwheres),
269
            $this->sqlparams,
270
        ];
271
    }
272
 
273
    /**
274
     * Adds given entity, along with it's columns and filters, to the report
275
     *
276
     * @param entity_base $entity
277
     */
278
    final protected function add_entity(entity_base $entity): void {
279
        $entityname = $entity->get_entity_name();
280
        $this->annotate_entity($entityname, $entity->get_entity_title());
281
        $this->entities[$entityname] = $entity->initialise();
282
    }
283
 
284
    /**
285
     * Returns the entity added to the report from the given entity name
286
     *
287
     * @param string $name
288
     * @return entity_base
289
     * @throws coding_exception
290
     */
291
    final protected function get_entity(string $name): entity_base {
292
        if (!array_key_exists($name, $this->entities)) {
293
            throw new coding_exception('Invalid entity name', $name);
294
        }
295
 
296
        return $this->entities[$name];
297
    }
298
 
299
    /**
300
     * Returns the list of all the entities added to the report
301
     *
302
     * @return entity_base[]
303
     */
304
    final protected function get_entities(): array {
305
        return $this->entities;
306
    }
307
 
308
    /**
309
     * Define a new entity for the report
310
     *
311
     * @param string $name
312
     * @param lang_string $title
313
     * @throws coding_exception
314
     */
315
    final protected function annotate_entity(string $name, lang_string $title): void {
316
        if ($name === '' || $name !== clean_param($name, PARAM_ALPHANUMEXT)) {
317
            throw new coding_exception('Entity name must be comprised of alphanumeric character, underscore or dash');
318
        }
319
 
320
        if (array_key_exists($name, $this->entitytitles)) {
321
            throw new coding_exception('Duplicate entity name', $name);
322
        }
323
 
324
        $this->entitytitles[$name] = $title;
325
    }
326
 
327
    /**
328
     * Returns title of given report entity
329
     *
330
     * @param string $name
331
     * @return lang_string
332
     * @throws coding_exception
333
     */
334
    final public function get_entity_title(string $name): lang_string {
335
        if (!array_key_exists($name, $this->entitytitles)) {
336
            throw new coding_exception('Invalid entity name', $name);
337
        }
338
 
339
        return $this->entitytitles[$name];
340
    }
341
 
342
    /**
343
     * Adds a column to the report
344
     *
345
     * @param column $column
346
     * @return column
347
     * @throws coding_exception
348
     */
349
    final protected function add_column(column $column): column {
350
        if (!array_key_exists($column->get_entity_name(), $this->entitytitles)) {
351
            throw new coding_exception('Invalid entity name', $column->get_entity_name());
352
        }
353
 
354
        $name = $column->get_name();
355
        if (empty($name) || $name !== clean_param($name, PARAM_ALPHANUMEXT)) {
356
            throw new coding_exception('Column name must be comprised of alphanumeric character, underscore or dash');
357
        }
358
 
359
        $uniqueidentifier = $column->get_unique_identifier();
360
        if (array_key_exists($uniqueidentifier, $this->columns)) {
361
            throw new coding_exception('Duplicate column identifier', $uniqueidentifier);
362
        }
363
 
364
        $this->columns[$uniqueidentifier] = $column;
365
 
366
        return $column;
367
    }
368
 
369
    /**
370
     * Add given column to the report from an entity
371
     *
372
     * The entity must have already been added to the report before calling this method
373
     *
374
     * @param string $uniqueidentifier
375
     * @return column
376
     */
377
    final protected function add_column_from_entity(string $uniqueidentifier): column {
378
        [$entityname, $columnname] = explode(':', $uniqueidentifier, 2);
379
 
380
        return $this->add_column($this->get_entity($entityname)->get_column($columnname));
381
    }
382
 
383
    /**
1441 ariadna 384
     * Add columns from the given entity name to be available to use in a custom report
385
     *
386
     * Wildcard matching is supported with '*' in both $include and $exclude, e.g. ['customfield*']
387
     *
388
     * @param string $entityname
389
     * @param string[] $include Include only these columns, if omitted then include all
390
     * @param string[] $exclude Exclude these columns, if omitted then exclude none
391
     * @throws coding_exception If both $include and $exclude are non-empty
392
     */
393
    final protected function add_columns_from_entity(string $entityname, array $include = [], array $exclude = []): void {
394
        if (!empty($include) && !empty($exclude)) {
395
            throw new coding_exception('Cannot specify columns to include and exclude simultaneously');
396
        }
397
 
398
        $entity = $this->get_entity($entityname);
399
 
400
        // Retrieve filtered columns from entity, respecting given $include/$exclude parameters.
401
        $columns = array_filter($entity->get_columns(), function(column $column) use ($include, $exclude): bool {
402
            if (!empty($include)) {
403
                return $this->report_element_search($column->get_name(), $include);
404
            }
405
 
406
            if (!empty($exclude)) {
407
                return !$this->report_element_search($column->get_name(), $exclude);
408
            }
409
 
410
            return true;
411
        });
412
 
413
        foreach ($columns as $column) {
414
            $this->add_column($column);
415
        }
416
    }
417
 
418
    /**
1 efrain 419
     * Add given columns to the report from one or more entities
420
     *
421
     * Each entity must have already been added to the report before calling this method
422
     *
423
     * @param string[] $columns Unique identifier of each entity column
424
     */
425
    final protected function add_columns_from_entities(array $columns): void {
426
        foreach ($columns as $column) {
427
            $this->add_column_from_entity($column);
428
        }
429
    }
430
 
431
    /**
432
     * Return report column by unique identifier
433
     *
434
     * @param string $uniqueidentifier
435
     * @return column|null
436
     */
437
    final public function get_column(string $uniqueidentifier): ?column {
438
        return $this->columns[$uniqueidentifier] ?? null;
439
    }
440
 
441
    /**
442
     * Return all available report columns
443
     *
444
     * @return column[]
445
     */
446
    final public function get_columns(): array {
447
        return array_filter($this->columns, static function(column $column): bool {
448
            return $column->get_is_available();
449
        });
450
    }
451
 
452
    /**
453
     * Return all active report columns (by default, all available columns)
454
     *
455
     * @return column[]
456
     */
457
    public function get_active_columns(): array {
458
        $columns = $this->get_columns();
459
        foreach ($columns as $column) {
460
            if ($column->get_is_deprecated()) {
461
                debugging("The column '{$column->get_unique_identifier()}' is deprecated, please do not use it any more." .
462
                    " {$column->get_is_deprecated_message()}", DEBUG_DEVELOPER);
463
            }
464
        }
465
 
466
        return $columns;
467
    }
468
 
469
    /**
470
     * Return all active report columns, keyed by their alias (only active columns in a report would have a valid alias/index)
471
     *
472
     * @return column[]
473
     */
474
    final public function get_active_columns_by_alias(): array {
475
        $columns = [];
476
 
477
        foreach ($this->get_active_columns() as $column) {
478
            $columns[$column->get_column_alias()] = $column;
479
        }
480
 
481
        return $columns;
482
    }
483
 
484
    /**
485
     * Adds a condition to the report
486
     *
487
     * @param filter $condition
488
     * @return filter
489
     * @throws coding_exception
490
     */
491
    final protected function add_condition(filter $condition): filter {
492
        if (!array_key_exists($condition->get_entity_name(), $this->entitytitles)) {
493
            throw new coding_exception('Invalid entity name', $condition->get_entity_name());
494
        }
495
 
496
        $name = $condition->get_name();
497
        if (empty($name) || $name !== clean_param($name, PARAM_ALPHANUMEXT)) {
498
            throw new coding_exception('Condition name must be comprised of alphanumeric character, underscore or dash');
499
        }
500
 
501
        $uniqueidentifier = $condition->get_unique_identifier();
502
        if (array_key_exists($uniqueidentifier, $this->conditions)) {
503
            throw new coding_exception('Duplicate condition identifier', $uniqueidentifier);
504
        }
505
 
506
        $this->conditions[$uniqueidentifier] = $condition;
507
 
508
        return $condition;
509
    }
510
 
511
    /**
512
     * Add given condition to the report from an entity
513
     *
514
     * The entity must have already been added to the report before calling this method
515
     *
516
     * @param string $uniqueidentifier
517
     * @return filter
518
     */
519
    final protected function add_condition_from_entity(string $uniqueidentifier): filter {
520
        [$entityname, $conditionname] = explode(':', $uniqueidentifier, 2);
521
 
522
        return $this->add_condition($this->get_entity($entityname)->get_condition($conditionname));
523
    }
524
 
525
    /**
526
     * Add given conditions to the report from one or more entities
527
     *
528
     * Each entity must have already been added to the report before calling this method
529
     *
530
     * @param string[] $conditions Unique identifier of each entity condition
531
     */
532
    final protected function add_conditions_from_entities(array $conditions): void {
533
        foreach ($conditions as $condition) {
534
            $this->add_condition_from_entity($condition);
535
        }
536
    }
537
 
538
    /**
539
     * Return report condition by unique identifier
540
     *
541
     * @param string $uniqueidentifier
542
     * @return filter|null
543
     */
544
    final public function get_condition(string $uniqueidentifier): ?filter {
545
        return $this->conditions[$uniqueidentifier] ?? null;
546
    }
547
 
548
    /**
549
     * Return all available report conditions
550
     *
551
     * @return filter[]
552
     */
553
    final public function get_conditions(): array {
554
        return array_filter($this->conditions, static function(filter $condition): bool {
555
            return $condition->get_is_available();
556
        });
557
    }
558
 
559
    /**
560
     * Return all active report conditions (by default, all available conditions)
561
     *
1441 ariadna 562
     * @param bool $checkavailable
1 efrain 563
     * @return filter[]
564
     */
1441 ariadna 565
    public function get_active_conditions(bool $checkavailable = true): array {
1 efrain 566
        $conditions = $this->get_conditions();
567
        foreach ($conditions as $condition) {
568
            if ($condition->get_is_deprecated()) {
569
                debugging("The condition '{$condition->get_unique_identifier()}' is deprecated, please do not use it any more." .
570
                    " {$condition->get_is_deprecated_message()}", DEBUG_DEVELOPER);
571
            }
572
        }
573
 
574
        return $conditions;
575
    }
576
 
577
    /**
578
     * Return all active report condition instances
579
     *
580
     * @return filter_base[]
581
     */
582
    final public function get_condition_instances(): array {
583
        return array_map(static function(filter $condition): filter_base {
584
            /** @var filter_base $conditionclass */
585
            $conditionclass = $condition->get_filter_class();
586
 
587
            return $conditionclass::create($condition);
588
        }, $this->get_active_conditions());
589
    }
590
 
591
    /**
592
     * Set the condition values of the report
593
     *
594
     * @param array $values
595
     * @return bool
596
     */
597
    final public function set_condition_values(array $values): bool {
598
        $this->report->set('conditiondata', json_encode($values))
599
            ->save();
600
 
601
        return true;
602
    }
603
 
604
    /**
605
     * Get the condition values of the report
606
     *
607
     * @return array
608
     */
609
    final public function get_condition_values(): array {
610
        $conditions = (string) $this->report->get('conditiondata');
611
 
612
        return (array) json_decode($conditions);
613
    }
614
 
615
    /**
616
     * Set the settings values of the report
617
     *
618
     * @param array $values
619
     * @return bool
620
     */
621
    final public function set_settings_values(array $values): bool {
622
        $currentsettings = $this->get_settings_values();
623
        $settings = array_merge($currentsettings, $values);
624
        $this->report->set('settingsdata', json_encode($settings))
625
            ->save();
626
        return true;
627
    }
628
 
629
    /**
630
     * Get the settings values of the report
631
     *
632
     * @return array
633
     */
634
    final public function get_settings_values(): array {
635
        $settings = (string) $this->report->get('settingsdata');
636
 
637
        return (array) json_decode($settings);
638
    }
639
 
640
    /**
641
     * Adds a filter to the report
642
     *
643
     * @param filter $filter
644
     * @return filter
645
     * @throws coding_exception
646
     */
647
    final protected function add_filter(filter $filter): filter {
648
        if (!array_key_exists($filter->get_entity_name(), $this->entitytitles)) {
649
            throw new coding_exception('Invalid entity name', $filter->get_entity_name());
650
        }
651
 
652
        $name = $filter->get_name();
653
        if (empty($name) || $name !== clean_param($name, PARAM_ALPHANUMEXT)) {
654
            throw new coding_exception('Filter name must be comprised of alphanumeric character, underscore or dash');
655
        }
656
 
657
        $uniqueidentifier = $filter->get_unique_identifier();
658
        if (array_key_exists($uniqueidentifier, $this->filters)) {
659
            throw new coding_exception('Duplicate filter identifier', $uniqueidentifier);
660
        }
661
 
662
        $this->filters[$uniqueidentifier] = $filter;
663
 
664
        return $filter;
665
    }
666
 
667
    /**
668
     * Add given filter to the report from an entity
669
     *
670
     * The entity must have already been added to the report before calling this method
671
     *
672
     * @param string $uniqueidentifier
673
     * @return filter
674
     */
675
    final protected function add_filter_from_entity(string $uniqueidentifier): filter {
676
        [$entityname, $filtername] = explode(':', $uniqueidentifier, 2);
677
 
678
        return $this->add_filter($this->get_entity($entityname)->get_filter($filtername));
679
    }
680
 
681
    /**
1441 ariadna 682
     * Add filters from the given entity name to be available to use in a custom report
683
     *
684
     * Wildcard matching is supported with '*' in both $include and $exclude, e.g. ['customfield*']
685
     *
686
     * @param string $entityname
687
     * @param string[] $include Include only these filters, if omitted then include all
688
     * @param string[] $exclude Exclude these filters, if omitted then exclude none
689
     * @throws coding_exception If both $include and $exclude are non-empty
690
     */
691
    final protected function add_filters_from_entity(string $entityname, array $include = [], array $exclude = []): void {
692
        if (!empty($include) && !empty($exclude)) {
693
            throw new coding_exception('Cannot specify filters to include and exclude simultaneously');
694
        }
695
 
696
        $entity = $this->get_entity($entityname);
697
 
698
        // Retrieve filtered filters from entity, respecting given $include/$exclude parameters.
699
        $filters = array_filter($entity->get_filters(), function(filter $filter) use ($include, $exclude): bool {
700
            if (!empty($include)) {
701
                return $this->report_element_search($filter->get_name(), $include);
702
            }
703
 
704
            if (!empty($exclude)) {
705
                return !$this->report_element_search($filter->get_name(), $exclude);
706
            }
707
 
708
            return true;
709
        });
710
 
711
        foreach ($filters as $filter) {
712
            $this->add_filter($filter);
713
        }
714
    }
715
 
716
    /**
1 efrain 717
     * Add given filters to the report from one or more entities
718
     *
719
     * Each entity must have already been added to the report before calling this method
720
     *
721
     * @param string[] $filters Unique identifier of each entity filter
722
     */
723
    final protected function add_filters_from_entities(array $filters): void {
724
        foreach ($filters as $filter) {
725
            $this->add_filter_from_entity($filter);
726
        }
727
    }
728
 
729
    /**
730
     * Return report filter by unique identifier
731
     *
732
     * @param string $uniqueidentifier
733
     * @return filter|null
734
     */
735
    final public function get_filter(string $uniqueidentifier): ?filter {
736
        return $this->filters[$uniqueidentifier] ?? null;
737
    }
738
 
739
    /**
740
     * Return all available report filters
741
     *
742
     * @return filter[]
743
     */
744
    final public function get_filters(): array {
745
        return array_filter($this->filters, static function(filter $filter): bool {
746
            return $filter->get_is_available();
747
        });
748
    }
749
 
750
    /**
751
     * Return all active report filters (by default, all available filters)
752
     *
753
     * @return filter[]
754
     */
755
    public function get_active_filters(): array {
756
        $filters = $this->get_filters();
757
        foreach ($filters as $filter) {
758
            if ($filter->get_is_deprecated()) {
759
                debugging("The filter '{$filter->get_unique_identifier()}' is deprecated, please do not use it any more." .
760
                    " {$filter->get_is_deprecated_message()}", DEBUG_DEVELOPER);
761
            }
762
        }
763
 
764
        return $filters;
765
    }
766
 
767
    /**
768
     * Return all active report filter instances
769
     *
770
     * @return filter_base[]
771
     */
772
    final public function get_filter_instances(): array {
773
        return array_map(static function(filter $filter): filter_base {
774
            /** @var filter_base $filterclass */
775
            $filterclass = $filter->get_filter_class();
776
 
777
            return $filterclass::create($filter);
778
        }, $this->get_active_filters());
779
    }
780
 
781
    /**
782
     * Set the filter values of the report
783
     *
784
     * @param array $values
785
     * @return bool
786
     */
787
    final public function set_filter_values(array $values): bool {
788
        return user_filter_manager::set($this->report->get('id'), $values);
789
    }
790
 
791
    /**
792
     * Get the filter values of the report
793
     *
794
     * @return array
795
     */
796
    final public function get_filter_values(): array {
797
        return user_filter_manager::get($this->report->get('id'));
798
    }
799
 
800
    /**
801
     * Return the number of filter instances that are being applied based on the report's filter values (i.e. user has
802
     * configured them from their initial "Any value" state)
803
     *
804
     * @return int
805
     */
806
    final public function get_applied_filter_count(): int {
807
        $values = $this->get_filter_values();
808
        $applied = array_filter($this->get_filter_instances(), static function(filter_base $filter) use ($values): bool {
809
            return $filter->applies_to_values($values);
810
        });
811
 
812
        return count($applied);
813
    }
814
 
815
    /**
816
     * Set if the report can be downloaded.
817
     *
818
     * @param bool $downloadable
819
     * @param string|null $downloadfilename If downloadable, then the name of the file (defaults to the name of the current report)
820
     */
821
    final public function set_downloadable(bool $downloadable, ?string $downloadfilename = null): void {
822
        $this->downloadable = $downloadable;
823
        $this->downloadfilename = $downloadfilename ?? static::get_name();
824
    }
825
 
826
    /**
827
     * Get if the report can be downloaded.
828
     *
829
     * @return bool
830
     */
831
    final public function is_downloadable(): bool {
832
        return $this->downloadable;
833
    }
834
 
835
    /**
836
     * Return the downloadable report filename
837
     *
838
     * @return string
839
     */
840
    final public function get_downloadfilename(): string {
841
        return $this->downloadfilename;
842
    }
843
 
844
    /**
845
     * Returns the report context
846
     *
847
     * @return context
848
     */
849
    public function get_context(): context {
850
        return $this->report->get_context();
851
    }
852
 
853
    /**
854
     * Set the default 'per page' size
855
     *
856
     * @param int $defaultperpage
857
     */
858
    public function set_default_per_page(int $defaultperpage): void {
859
        $this->defaultperpage = $defaultperpage;
860
    }
861
 
862
    /**
863
     * Set the default lang string for the notice used when no results are found.
864
     *
1441 ariadna 865
     * Note this should be called from within the report class instance itself (ideally it would be protected)
866
     *
1 efrain 867
     * @param lang_string|null $notice string, or null to tell the report to omit the notice entirely.
868
     */
869
    public function set_default_no_results_notice(?lang_string $notice): void {
870
        $this->noresultsnotice = $notice;
871
    }
872
 
873
    /**
874
     * Get the default lang string for the notice used when no results are found.
875
     *
876
     * @return lang_string|null the lang_string instance or null if the report prefers not to use one.
877
     */
878
    public function get_default_no_results_notice(): ?lang_string {
879
        return $this->noresultsnotice;
880
    }
881
 
882
    /**
883
     * Default 'per page' size
884
     *
885
     * @return int
886
     */
887
    public function get_default_per_page(): int {
888
        return $this->defaultperpage;
889
    }
890
 
891
    /**
1441 ariadna 892
     * Sets the report action to be rendered above the table
893
     *
894
     * @param report_action $reportaction
895
     */
896
    final public function set_report_action(report_action $reportaction): void {
897
        $this->reportaction = $reportaction;
898
    }
899
 
900
    /**
901
     * Gets the report action to be rendered abover the table
902
     *
903
     * @return report_action|null
904
     */
905
    final public function get_report_action(): ?report_action {
906
        return $this->reportaction;
907
    }
908
 
909
    /**
910
     * Sets the report info container content to be rendered between action buttons and table
911
     *
912
     * @param string $reportinfocontainer
913
     */
914
    final public function set_report_info_container(string $reportinfocontainer): void {
915
        $this->reportinfocontainer = $reportinfocontainer;
916
    }
917
 
918
    /**
919
     * Gets the report info container content to be rendered between action buttons and table
920
     *
921
     * @return string
922
     */
923
    final public function get_report_info_container(): string {
924
        return $this->reportinfocontainer;
925
    }
926
 
927
    /**
1 efrain 928
     * Add report attributes (data-, class, etc.) that will be included in HTML when report is displayed
929
     *
930
     * @param array $attributes
931
     * @return self
932
     */
933
    public function add_attributes(array $attributes): self {
934
        $this->attributes = $attributes + $this->attributes;
935
        return $this;
936
    }
937
 
938
    /**
939
     * Returns the report HTML attributes
940
     *
941
     * @return array
942
     */
943
    public function get_attributes(): array {
944
        return $this->attributes;
945
    }
1441 ariadna 946
 
947
    /**
948
     * Search for given element within list of search items, supporting '*' wildcards
949
     *
950
     * @param string $element
951
     * @param string[] $search
952
     * @return bool
953
     */
954
    final protected function report_element_search(string $element, array $search): bool {
955
        foreach ($search as $item) {
956
            // Simple matching.
957
            if ($element === $item) {
958
                return true;
959
            }
960
 
961
            // Wildcard matching.
962
            if (strpos($item, '*') !== false) {
963
                $pattern = '/^' . str_replace('\*', '.*', preg_quote($item)) . '$/';
964
                return (bool) preg_match($pattern, $element);
965
            }
966
        }
967
 
968
        return false;
969
    }
1 efrain 970
}