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\local\entities;
20
 
21
use coding_exception;
22
use core_reportbuilder\local\helpers\database;
23
use core_reportbuilder\local\report\column;
24
use core_reportbuilder\local\report\filter;
25
use lang_string;
26
 
27
/**
28
 * Base class for all report entities
29
 *
30
 * @package     core_reportbuilder
31
 * @copyright   2019 Marina Glancy <marina@moodle.com>
32
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33
 */
34
abstract class base {
35
 
36
    /** @var string $entityname Internal reference to name of entity */
37
    private $entityname = null;
38
 
39
    /** @var lang_string $entitytitle Used as a title for the entity in reports */
40
    private $entitytitle = null;
41
 
42
    /** @var array $tablealiases Database tables that this entity uses and their aliases */
43
    private $tablealiases = [];
44
 
45
    /** @var array $tablejoinaliases Database tables that have already been joined to the report and their aliases */
46
    private $tablejoinaliases = [];
47
 
48
    /** @var string[] $joins List of SQL joins for the entity */
49
    private $joins = [];
50
 
51
    /** @var column[] $columns List of columns for the entity */
52
    private $columns = [];
53
 
54
    /** @var filter[] $filters List of filters for the entity */
55
    private $filters = [];
56
 
57
    /** @var filter[] $conditions List of conditions for the entity */
58
    private $conditions = [];
59
 
60
    /**
61
     * Database tables that this entity uses
62
     *
63
     * Must be overridden by the entity to list all database tables that it expects to be present in the main
64
     * SQL or in JOINs added to this entity
65
     *
66
     * @todo in Moodle 4.8 - make abstract when support for {@see get_default_table_aliases} is finally removed
67
     *
68
     * @return string[]
69
     */
70
    protected function get_default_tables(): array {
71
        static $debuggingshown;
72
 
73
        // The default implementation falls back to retrieving deprecated table aliases to determine our table names.
74
        $tablenamealiases = $this->get_default_table_aliases();
75
        if (!empty($tablenamealiases) && !$debuggingshown) {
76
            debugging('The function get_default_table_aliases() is deprecated, please define the entity' .
77
                ' tables with get_default_tables() in ' . static::class, DEBUG_DEVELOPER);
78
 
79
            // Don't be too spammy with the debugging, this method is called multiple times per entity load.
80
            $debuggingshown = true;
81
        }
82
 
83
        return array_keys($tablenamealiases);
84
    }
85
 
86
    /**
87
     * Database tables that this entity uses and their default aliases (note that these aliases are now ignored)
88
     *
89
     * @return string[] Array of $tablename => $alias
90
     *
91
     * @deprecated since Moodle 4.4 - aliases are now autogenerated, please implement {@see get_default_tables} instead
92
     */
93
    protected function get_default_table_aliases(): array {
94
        return [];
95
    }
96
 
97
    /**
98
     * The default title for this entity
99
     *
100
     * @return lang_string
101
     */
102
    abstract protected function get_default_entity_title(): lang_string;
103
 
104
    /**
105
     * Initialise the entity, called automatically when it is added to a report
106
     *
107
     * This is where entity defines all its columns and filters by calling:
108
     * - {@see add_column}
109
     * - {@see add_filter}
110
     * - etc
111
     *
112
     * @return self
113
     */
114
    abstract public function initialise(): self;
115
 
116
    /**
117
     * The default machine-readable name for this entity that will be used in the internal names of the columns/filters
118
     *
119
     * @return string
120
     */
121
    private function get_default_entity_name(): string {
122
        $namespace = explode('\\', get_called_class());
123
 
124
        return end($namespace);
125
    }
126
 
127
    /**
128
     * Set entity name
129
     *
130
     * @param string $entityname
131
     * @return self
132
     */
133
    final public function set_entity_name(string $entityname): self {
134
        $this->entityname = $entityname;
135
        return $this;
136
    }
137
 
138
    /**
139
     * Return entity name
140
     *
141
     * @return string
142
     */
143
    final public function get_entity_name(): string {
144
        return $this->entityname ?? $this->get_default_entity_name();
145
    }
146
 
147
    /**
148
     * Set entity title
149
     *
150
     * @param lang_string $title
151
     * @return self
152
     */
153
    final public function set_entity_title(lang_string $title): self {
154
        $this->entitytitle = $title;
155
        return $this;
156
    }
157
 
158
    /**
159
     * Get entity title
160
     *
161
     * @return lang_string
162
     */
163
    final public function get_entity_title(): lang_string {
164
        return $this->entitytitle ?? $this->get_default_entity_title();
165
    }
166
 
167
    /**
168
     * Override the default alias for given database table used in entity queries, for instance when the same table is used
169
     * by multiple entities and you want them each to refer to it by the same alias
170
     *
171
     * @param string $tablename One of the tables set by {@see get_default_tables}
172
     * @param string $alias
173
     * @return self
174
     * @throws coding_exception For invalid table name
175
     */
176
    final public function set_table_alias(string $tablename, string $alias): self {
177
        $tablenames = $this->get_default_tables();
178
        if (!in_array($tablename, $tablenames)) {
179
            throw new coding_exception('Invalid table name', $tablename);
180
        }
181
 
182
        $this->tablealiases[$tablename] = $alias;
183
        return $this;
184
    }
185
 
186
    /**
187
     * Override multiple default database table aliases used in entity queries as per {@see set_table_alias}
188
     *
189
     * @param array $aliases Array of tablename => alias values
190
     * @return self
191
     */
192
    final public function set_table_aliases(array $aliases): self {
193
        foreach ($aliases as $tablename => $alias) {
194
            $this->set_table_alias($tablename, $alias);
195
        }
196
        return $this;
197
    }
198
 
199
    /**
200
     * Returns an alias used in the queries for a given table
201
     *
202
     * @param string $tablename One of the tables set by {@see get_default_tables}
203
     * @return string
204
     * @throws coding_exception For invalid table name
205
     */
206
    final public function get_table_alias(string $tablename): string {
207
        $tablenames = $this->get_default_tables();
208
        if (!in_array($tablename, $tablenames)) {
209
            throw new coding_exception('Invalid table name', $tablename);
210
        }
211
 
212
        // We don't have the alias yet, generate a new one.
213
        if (!array_key_exists($tablename, $this->tablealiases)) {
214
            $this->set_table_alias($tablename, database::generate_alias());
215
        }
216
 
217
        return $this->tablealiases[$tablename];
218
    }
219
 
220
    /**
221
     * Returns aliases used in the queries for all tables
222
     *
223
     * @return string[]
224
     */
225
    final public function get_table_aliases(): array {
226
        $tablenames = $this->get_default_tables();
227
 
228
        return array_combine($tablenames, array_map([$this, 'get_table_alias'], $tablenames));
229
    }
230
 
231
    /**
232
     * Set the alias for given database table that has already been added to the report. Enables entities to avoid additional
233
     * joins on the same table by allowing re-use of existing table aliases in their own queries, {@see has_table_join_alias}
234
     *
235
     * @param string $tablename
236
     * @param string $alias
237
     * @return self
238
     */
239
    final public function set_table_join_alias(string $tablename, string $alias): self {
240
        $this->tablejoinaliases[$tablename] = $alias;
241
 
242
        // Internally set the same table alias for the entity.
243
        return $this->set_table_alias($tablename, $alias);
244
    }
245
 
246
    /**
247
     * Determine whether defined table join alias was specified. Call {@see get_table_alias} to retrieve said value
248
     *
249
     * @param string $tablename
250
     * @return bool
251
     */
252
    final public function has_table_join_alias(string $tablename): bool {
253
        return array_key_exists($tablename, $this->tablejoinaliases);
254
    }
255
 
256
    /**
257
     * Add join clause required for this entity to join to existing tables/entities
258
     *
259
     * @param string $join
260
     * @return self
261
     */
262
    final public function add_join(string $join): self {
263
        $this->joins[trim($join)] = trim($join);
264
        return $this;
265
    }
266
 
267
    /**
268
     * Add multiple join clauses required for this entity {@see add_join}
269
     *
270
     * @param string[] $joins
271
     * @return self
272
     */
273
    final public function add_joins(array $joins): self {
274
        foreach ($joins as $join) {
275
            $this->add_join($join);
276
        }
277
        return $this;
278
    }
279
 
280
    /**
281
     * Return entity joins
282
     *
283
     * @return string[]
284
     */
285
    final public function get_joins(): array {
286
        return array_values($this->joins);
287
    }
288
 
289
    /**
290
     * Helper method for returning joins necessary for retrieving tags related to the current entity
291
     *
292
     * Both 'tag' and 'tag_instance' aliases must be returned by the entity {@see get_default_tables} method
293
     *
294
     * @param string $component
295
     * @param string $itemtype
296
     * @param string $itemidfield
297
     * @return string[]
298
     */
299
    final protected function get_tag_joins_for_entity(string $component, string $itemtype, string $itemidfield): array {
300
        $taginstancealias = $this->get_table_alias('tag_instance');
301
        $tagalias = $this->get_table_alias('tag');
302
 
303
        return [
304
            "LEFT JOIN {tag_instance} {$taginstancealias}
305
                    ON {$taginstancealias}.component = '{$component}'
306
                   AND {$taginstancealias}.itemtype = '{$itemtype}'
307
                   AND {$taginstancealias}.itemid = {$itemidfield}",
308
            "LEFT JOIN {tag} {$tagalias}
309
                    ON {$tagalias}.id = {$taginstancealias}.tagid",
310
        ];
311
    }
312
 
313
    /**
314
     * Add a column to the entity
315
     *
316
     * @param column $column
317
     * @return self
318
     */
319
    final protected function add_column(column $column): self {
320
        $this->columns[$column->get_name()] = $column;
321
        return $this;
322
    }
323
 
324
    /**
325
     * Returns entity columns
326
     *
327
     * @return column[]
328
     */
329
    final public function get_columns(): array {
330
        return $this->columns;
331
    }
332
 
333
    /**
334
     * Returns an entity column
335
     *
336
     * @param string $name
337
     * @return column
338
     * @throws coding_exception For invalid column name
339
     */
340
    final public function get_column(string $name): column {
341
        if (!array_key_exists($name, $this->columns)) {
342
            throw new coding_exception('Invalid column name', $name);
343
        }
344
 
345
        return $this->columns[$name];
346
    }
347
 
348
    /**
349
     * Add a filter to the entity
350
     *
351
     * @param filter $filter
352
     * @return self
353
     */
354
    final protected function add_filter(filter $filter): self {
355
        $this->filters[$filter->get_name()] = $filter;
356
        return $this;
357
    }
358
 
359
    /**
360
     * Returns entity filters
361
     *
362
     * @return filter[]
363
     */
364
    final public function get_filters(): array {
365
        return $this->filters;
366
    }
367
 
368
    /**
369
     * Returns an entity filter
370
     *
371
     * @param string $name
372
     * @return filter
373
     * @throws coding_exception For invalid filter name
374
     */
375
    final public function get_filter(string $name): filter {
376
        if (!array_key_exists($name, $this->filters)) {
377
            throw new coding_exception('Invalid filter name', $name);
378
        }
379
 
380
        return $this->filters[$name];
381
    }
382
 
383
    /**
384
     * Add a condition to the entity
385
     *
386
     * @param filter $condition
387
     * @return $this
388
     */
389
    final protected function add_condition(filter $condition): self {
390
        $this->conditions[$condition->get_name()] = $condition;
391
        return $this;
392
    }
393
 
394
    /**
395
     * Returns entity conditions
396
     *
397
     * @return filter[]
398
     */
399
    final public function get_conditions(): array {
400
        return $this->conditions;
401
    }
402
 
403
    /**
404
     * Returns an entity condition
405
     *
406
     * @param string $name
407
     * @return filter
408
     * @throws coding_exception For invalid condition name
409
     */
410
    final public function get_condition(string $name): filter {
411
        if (!array_key_exists($name, $this->conditions)) {
412
            throw new coding_exception('Invalid condition name', $name);
413
        }
414
 
415
        return $this->conditions[$name];
416
    }
417
}