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 coding_exception;
1441 ariadna 22
use core_reportbuilder\local\helpers\{database, join_trait};
1 efrain 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
 
1441 ariadna 36
    use join_trait;
37
 
1 efrain 38
    /** @var string $entityname Internal reference to name of entity */
39
    private $entityname = null;
40
 
41
    /** @var lang_string $entitytitle Used as a title for the entity in reports */
42
    private $entitytitle = null;
43
 
44
    /** @var array $tablealiases Database tables that this entity uses and their aliases */
45
    private $tablealiases = [];
46
 
47
    /** @var array $tablejoinaliases Database tables that have already been joined to the report and their aliases */
48
    private $tablejoinaliases = [];
49
 
50
    /** @var column[] $columns List of columns for the entity */
51
    private $columns = [];
52
 
53
    /** @var filter[] $filters List of filters for the entity */
54
    private $filters = [];
55
 
56
    /** @var filter[] $conditions List of conditions for the entity */
57
    private $conditions = [];
58
 
59
    /**
1441 ariadna 60
     * Database tables that the entity expects to be present in the main SQL or in JOINs added to it
1 efrain 61
     *
62
     * @return string[]
63
     */
1441 ariadna 64
    abstract protected function get_default_tables(): array;
1 efrain 65
 
1441 ariadna 66
    /**
67
     * @deprecated since Moodle 4.4 - aliases are now autogenerated, please implement {@see get_default_tables} instead
68
     */
69
    #[\core\attribute\deprecated('::get_default_tables', since: '4.4', mdl: 'MDL-79397', final: true)]
70
    protected function get_default_table_aliases(): array {
71
        \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
72
        return [];
1 efrain 73
    }
74
 
75
    /**
1441 ariadna 76
     * Database tables that the entity once used but now no longer does. To prevent errors in third-party code, rather than
77
     * simply removing the table from {@see get_default_tables} you can override this method, which will emit developer debug
1 efrain 78
     *
1441 ariadna 79
     * Returns a simple list of table names, ['t1', 't2'] if they have no replacement; or ['t3' => 't1'] if an equivalent
80
     * replacement table name exists, where 't3' replaces 't1'
1 efrain 81
     *
1441 ariadna 82
     * @return string[]
1 efrain 83
     */
1441 ariadna 84
    protected function get_deprecated_tables(): array {
1 efrain 85
        return [];
86
    }
87
 
88
    /**
89
     * The default title for this entity
90
     *
91
     * @return lang_string
92
     */
93
    abstract protected function get_default_entity_title(): lang_string;
94
 
95
    /**
96
     * Initialise the entity, called automatically when it is added to a report
97
     *
98
     * This is where entity defines all its columns and filters by calling:
99
     * - {@see add_column}
100
     * - {@see add_filter}
101
     * - etc
102
     *
103
     * @return self
104
     */
105
    abstract public function initialise(): self;
106
 
107
    /**
108
     * The default machine-readable name for this entity that will be used in the internal names of the columns/filters
109
     *
110
     * @return string
111
     */
112
    private function get_default_entity_name(): string {
113
        $namespace = explode('\\', get_called_class());
114
 
115
        return end($namespace);
116
    }
117
 
118
    /**
119
     * Set entity name
120
     *
121
     * @param string $entityname
122
     * @return self
123
     */
124
    final public function set_entity_name(string $entityname): self {
125
        $this->entityname = $entityname;
126
        return $this;
127
    }
128
 
129
    /**
130
     * Return entity name
131
     *
132
     * @return string
133
     */
134
    final public function get_entity_name(): string {
135
        return $this->entityname ?? $this->get_default_entity_name();
136
    }
137
 
138
    /**
139
     * Set entity title
140
     *
141
     * @param lang_string $title
142
     * @return self
143
     */
144
    final public function set_entity_title(lang_string $title): self {
145
        $this->entitytitle = $title;
146
        return $this;
147
    }
148
 
149
    /**
150
     * Get entity title
151
     *
152
     * @return lang_string
153
     */
154
    final public function get_entity_title(): lang_string {
155
        return $this->entitytitle ?? $this->get_default_entity_title();
156
    }
157
 
158
    /**
1441 ariadna 159
     * Validate the given table is expected by the entity
160
     *
161
     * Emits developer debugging for deprecated tables, will return replacement for deprecated table if specified
162
     * by the entity
163
     *
164
     * @param string $tablename
165
     * @return string
166
     * @throws coding_exception For invalid table name
167
     */
168
    private function validate_table_name(string $tablename): string {
169
        $deprecatedtables = $this->get_deprecated_tables();
170
        if (!in_array($tablename, array_merge($this->get_default_tables(), $deprecatedtables))) {
171
            throw new coding_exception('Invalid table name', $tablename);
172
        }
173
 
174
        // Emit debugging if table is marked as deprecated by the entity.
175
        if (($tablenamereplacement = array_search($tablename, $deprecatedtables)) !== false) {
176
            debugging("The table '{$tablename}' is deprecated, please do not use it any more.", DEBUG_DEVELOPER);
177
 
178
            // An associative array contains the replacement table name as the key, so return that.
179
            if (!array_is_list($deprecatedtables)) {
180
                return $tablenamereplacement;
181
            }
182
        }
183
 
184
        return $tablename;
185
    }
186
 
187
    /**
1 efrain 188
     * Override the default alias for given database table used in entity queries, for instance when the same table is used
189
     * by multiple entities and you want them each to refer to it by the same alias
190
     *
191
     * @param string $tablename One of the tables set by {@see get_default_tables}
192
     * @param string $alias
193
     * @return self
194
     */
195
    final public function set_table_alias(string $tablename, string $alias): self {
1441 ariadna 196
        $tablename = $this->validate_table_name($tablename);
197
        $this->tablealiases[$tablename] = $alias;
1 efrain 198
 
199
        return $this;
200
    }
201
 
202
    /**
203
     * Override multiple default database table aliases used in entity queries as per {@see set_table_alias}
204
     *
205
     * @param array $aliases Array of tablename => alias values
206
     * @return self
207
     */
208
    final public function set_table_aliases(array $aliases): self {
209
        foreach ($aliases as $tablename => $alias) {
210
            $this->set_table_alias($tablename, $alias);
211
        }
212
        return $this;
213
    }
214
 
215
    /**
216
     * Returns an alias used in the queries for a given table
217
     *
218
     * @param string $tablename One of the tables set by {@see get_default_tables}
219
     * @return string
220
     */
221
    final public function get_table_alias(string $tablename): string {
1441 ariadna 222
        $tablename = $this->validate_table_name($tablename);
1 efrain 223
 
224
        // We don't have the alias yet, generate a new one.
225
        if (!array_key_exists($tablename, $this->tablealiases)) {
226
            $this->set_table_alias($tablename, database::generate_alias());
227
        }
228
 
229
        return $this->tablealiases[$tablename];
230
    }
231
 
232
    /**
233
     * Returns aliases used in the queries for all tables
234
     *
235
     * @return string[]
236
     */
237
    final public function get_table_aliases(): array {
238
        $tablenames = $this->get_default_tables();
239
 
240
        return array_combine($tablenames, array_map([$this, 'get_table_alias'], $tablenames));
241
    }
242
 
243
    /**
244
     * Set the alias for given database table that has already been added to the report. Enables entities to avoid additional
245
     * joins on the same table by allowing re-use of existing table aliases in their own queries, {@see has_table_join_alias}
246
     *
247
     * @param string $tablename
248
     * @param string $alias
249
     * @return self
250
     */
251
    final public function set_table_join_alias(string $tablename, string $alias): self {
252
        $this->tablejoinaliases[$tablename] = $alias;
253
 
254
        // Internally set the same table alias for the entity.
255
        return $this->set_table_alias($tablename, $alias);
256
    }
257
 
258
    /**
259
     * Determine whether defined table join alias was specified. Call {@see get_table_alias} to retrieve said value
260
     *
261
     * @param string $tablename
262
     * @return bool
263
     */
264
    final public function has_table_join_alias(string $tablename): bool {
265
        return array_key_exists($tablename, $this->tablejoinaliases);
266
    }
267
 
268
    /**
269
     * Helper method for returning joins necessary for retrieving tags related to the current entity
270
     *
271
     * Both 'tag' and 'tag_instance' aliases must be returned by the entity {@see get_default_tables} method
272
     *
273
     * @param string $component
274
     * @param string $itemtype
275
     * @param string $itemidfield
276
     * @return string[]
277
     */
278
    final protected function get_tag_joins_for_entity(string $component, string $itemtype, string $itemidfield): array {
279
        $taginstancealias = $this->get_table_alias('tag_instance');
280
        $tagalias = $this->get_table_alias('tag');
281
 
282
        return [
283
            "LEFT JOIN {tag_instance} {$taginstancealias}
284
                    ON {$taginstancealias}.component = '{$component}'
285
                   AND {$taginstancealias}.itemtype = '{$itemtype}'
286
                   AND {$taginstancealias}.itemid = {$itemidfield}",
287
            "LEFT JOIN {tag} {$tagalias}
288
                    ON {$tagalias}.id = {$taginstancealias}.tagid",
289
        ];
290
    }
291
 
292
    /**
293
     * Add a column to the entity
294
     *
295
     * @param column $column
296
     * @return self
297
     */
298
    final protected function add_column(column $column): self {
299
        $this->columns[$column->get_name()] = $column;
300
        return $this;
301
    }
302
 
303
    /**
304
     * Returns entity columns
305
     *
306
     * @return column[]
307
     */
308
    final public function get_columns(): array {
309
        return $this->columns;
310
    }
311
 
312
    /**
313
     * Returns an entity column
314
     *
315
     * @param string $name
316
     * @return column
317
     * @throws coding_exception For invalid column name
318
     */
319
    final public function get_column(string $name): column {
320
        if (!array_key_exists($name, $this->columns)) {
321
            throw new coding_exception('Invalid column name', $name);
322
        }
323
 
324
        return $this->columns[$name];
325
    }
326
 
327
    /**
328
     * Add a filter to the entity
329
     *
330
     * @param filter $filter
331
     * @return self
332
     */
333
    final protected function add_filter(filter $filter): self {
334
        $this->filters[$filter->get_name()] = $filter;
335
        return $this;
336
    }
337
 
338
    /**
339
     * Returns entity filters
340
     *
341
     * @return filter[]
342
     */
343
    final public function get_filters(): array {
344
        return $this->filters;
345
    }
346
 
347
    /**
348
     * Returns an entity filter
349
     *
350
     * @param string $name
351
     * @return filter
352
     * @throws coding_exception For invalid filter name
353
     */
354
    final public function get_filter(string $name): filter {
355
        if (!array_key_exists($name, $this->filters)) {
356
            throw new coding_exception('Invalid filter name', $name);
357
        }
358
 
359
        return $this->filters[$name];
360
    }
361
 
362
    /**
363
     * Add a condition to the entity
364
     *
365
     * @param filter $condition
366
     * @return $this
367
     */
368
    final protected function add_condition(filter $condition): self {
369
        $this->conditions[$condition->get_name()] = $condition;
370
        return $this;
371
    }
372
 
373
    /**
374
     * Returns entity conditions
375
     *
376
     * @return filter[]
377
     */
378
    final public function get_conditions(): array {
379
        return $this->conditions;
380
    }
381
 
382
    /**
383
     * Returns an entity condition
384
     *
385
     * @param string $name
386
     * @return filter
387
     * @throws coding_exception For invalid condition name
388
     */
389
    final public function get_condition(string $name): filter {
390
        if (!array_key_exists($name, $this->conditions)) {
391
            throw new coding_exception('Invalid condition name', $name);
392
        }
393
 
394
        return $this->conditions[$name];
395
    }
396
}