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
namespace core_admin\reportbuilder\local\entities;
18
 
19
use core_reportbuilder\local\filters\date;
20
use core_reportbuilder\local\filters\duration;
21
use core_reportbuilder\local\filters\number;
22
use core_reportbuilder\local\filters\select;
23
use core_reportbuilder\local\filters\text;
24
use core_reportbuilder\local\filters\autocomplete;
25
use core_reportbuilder\local\helpers\format;
26
use lang_string;
27
use core_reportbuilder\local\entities\base;
28
use core_reportbuilder\local\report\column;
29
use core_reportbuilder\local\report\filter;
30
use stdClass;
31
use core_collator;
32
 
33
/**
34
 * Task log entity class implementation
35
 *
36
 * @package    core_admin
37
 * @copyright  2021 David Matamoros <davidmc@moodle.com>
38
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39
 */
40
class task_log extends base {
41
 
42
    /** @var int Result success */
43
    protected const SUCCESS = 0;
44
 
45
    /** @var int Result failed */
46
    protected const FAILED = 1;
47
 
48
    /**
49
     * Database tables that this entity uses
50
     *
51
     * @return string[]
52
     */
53
    protected function get_default_tables(): array {
54
        return [
55
            'task_log',
56
        ];
57
    }
58
 
59
    /**
60
     * The default title for this entity in the list of columns/conditions/filters in the report builder
61
     *
62
     * @return lang_string
63
     */
64
    protected function get_default_entity_title(): lang_string {
65
        return new lang_string('entitytasklog', 'admin');
66
    }
67
 
68
    /**
69
     * Initialise the entity
70
     *
71
     * @return base
72
     */
73
    public function initialise(): base {
74
        $columns = $this->get_all_columns();
75
        foreach ($columns as $column) {
76
            $this->add_column($column);
77
        }
78
 
79
        // All the filters defined by the entity can also be used as conditions.
80
        $filters = $this->get_all_filters();
81
        foreach ($filters as $filter) {
82
            $this
83
                ->add_filter($filter)
84
                ->add_condition($filter);
85
        }
86
 
87
        return $this;
88
    }
89
 
90
    /**
91
     * Returns list of all available columns
92
     *
93
     * @return column[]
94
     */
95
    protected function get_all_columns(): array {
96
        global $DB;
97
 
98
        $tablealias = $this->get_table_alias('task_log');
99
 
100
        // Name column.
101
        $columns[] = (new column(
102
            'name',
103
            new lang_string('name'),
104
            $this->get_entity_name()
105
        ))
106
            ->add_joins($this->get_joins())
107
            ->set_type(column::TYPE_TEXT)
108
            ->add_field("$tablealias.classname")
109
            ->set_is_sortable(true)
110
            ->add_callback(static function(string $classname): string {
111
                $output = '';
112
                if (class_exists($classname)) {
113
                    $task = new $classname;
114
                    if ($task instanceof \core\task\task_base) {
115
                        $output = $task->get_name();
116
                    }
117
                }
118
                $output .= \html_writer::tag('div', "\\{$classname}", [
119
                    'class' => 'small text-muted',
120
                ]);
121
                return $output;
122
            });
123
 
124
        // Component column.
125
        $columns[] = (new column(
126
            'component',
127
            new lang_string('plugin'),
128
            $this->get_entity_name()
129
        ))
130
            ->add_joins($this->get_joins())
131
            ->set_type(column::TYPE_TEXT)
132
            ->add_field("{$tablealias}.component")
133
            ->set_is_sortable(true);
134
 
135
        // Type column.
136
        $columns[] = (new column(
137
            'type',
138
            new lang_string('tasktype', 'admin'),
139
            $this->get_entity_name()
140
        ))
141
            ->add_joins($this->get_joins())
142
            ->set_type(column::TYPE_TEXT)
143
            ->add_field("{$tablealias}.type")
144
            ->set_is_sortable(true)
145
            ->add_callback(static function($value): string {
146
                if (\core\task\database_logger::TYPE_SCHEDULED === (int) $value) {
147
                    return get_string('task_type:scheduled', 'admin');
148
                }
149
                return get_string('task_type:adhoc', 'admin');
150
            });
151
 
152
        // Start time column.
153
        $columns[] = (new column(
154
            'starttime',
155
            new lang_string('task_starttime', 'admin'),
156
            $this->get_entity_name()
157
        ))
158
            ->add_joins($this->get_joins())
159
            ->set_type(column::TYPE_TIMESTAMP)
160
            ->add_field("{$tablealias}.timestart")
161
            ->set_is_sortable(true)
162
            ->add_callback([format::class, 'userdate'], get_string('strftimedatetimeshortaccurate', 'core_langconfig'));
163
 
164
        // End time column.
165
        $columns[] = (new column(
166
            'endtime',
167
            new lang_string('task_endtime', 'admin'),
168
            $this->get_entity_name()
169
        ))
170
            ->add_joins($this->get_joins())
171
            ->set_type(column::TYPE_TIMESTAMP)
172
            ->add_field("{$tablealias}.timeend")
173
            ->set_is_sortable(true)
174
            ->add_callback([format::class, 'userdate'], get_string('strftimedatetimeshortaccurate', 'core_langconfig'));
175
 
176
        // Duration column.
177
        $columns[] = (new column(
178
            'duration',
179
            new lang_string('task_duration', 'admin'),
180
            $this->get_entity_name()
181
        ))
182
            ->add_joins($this->get_joins())
183
            ->set_type(column::TYPE_FLOAT)
184
            ->add_field("{$tablealias}.timeend - {$tablealias}.timestart", 'duration')
185
            ->set_is_sortable(true)
186
            ->add_callback(static function(float $value): string {
187
                $duration = round($value, 2);
188
                if (empty($duration)) {
189
                    // The format_time function returns 'now' when the difference is exactly 0.
190
                    // Note: format_time performs concatenation in exactly this fashion so we should do this for consistency.
191
                    return '0 ' . get_string('secs', 'moodle');
192
                }
193
                return format_time($duration);
194
            });
195
 
196
        // Hostname column.
197
        $columns[] = (new column(
198
            'hostname',
199
            new lang_string('hostname', 'admin'),
200
            $this->get_entity_name()
201
        ))
202
            ->add_joins($this->get_joins())
203
            ->set_type(column::TYPE_TEXT)
204
            ->add_field("$tablealias.hostname")
205
            ->set_is_sortable(true);
206
 
207
        // PID column.
208
        $columns[] = (new column(
209
            'pid',
210
            new lang_string('pid', 'admin'),
211
            $this->get_entity_name()
212
        ))
213
            ->add_joins($this->get_joins())
214
            ->set_type(column::TYPE_INTEGER)
215
            ->add_field("{$tablealias}.pid")
216
            ->set_is_sortable(true)
217
            // Although this is an integer column, it doesn't make sense to perform numeric aggregation on it.
218
            ->set_disabled_aggregation(['avg', 'count', 'countdistinct', 'max', 'min', 'sum']);
219
 
220
        // Database column.
221
        $columns[] = (new column(
222
            'database',
223
            new lang_string('task_dbstats', 'admin'),
224
            $this->get_entity_name()
225
        ))
226
            ->add_joins($this->get_joins())
227
            ->set_type(column::TYPE_INTEGER)
228
            ->add_fields("{$tablealias}.dbreads, {$tablealias}.dbwrites")
229
            ->set_is_sortable(true, ["{$tablealias}.dbreads", "{$tablealias}.dbwrites"])
230
            ->add_callback(static function(int $value, stdClass $row): string {
231
                $output = '';
232
                $output .= \html_writer::div(get_string('task_stats:dbreads', 'admin', $row->dbreads));
233
                $output .= \html_writer::div(get_string('task_stats:dbwrites', 'admin', $row->dbwrites));
234
                return $output;
235
            })
236
            // Although this is an integer column, it doesn't make sense to perform numeric aggregation on it.
237
            ->set_disabled_aggregation(['avg', 'count', 'countdistinct', 'max', 'min', 'sum']);
238
 
239
        // Database reads column.
240
        $columns[] = (new column(
241
            'dbreads',
242
            new lang_string('task_dbreads', 'admin'),
243
            $this->get_entity_name()
244
        ))
245
            ->add_joins($this->get_joins())
246
            ->set_type(column::TYPE_INTEGER)
247
            ->add_fields("{$tablealias}.dbreads")
248
            ->set_is_sortable(true);
249
 
250
        // Database writes column.
251
        $columns[] = (new column(
252
            'dbwrites',
253
            new lang_string('task_dbwrites', 'admin'),
254
            $this->get_entity_name()
255
        ))
256
            ->add_joins($this->get_joins())
257
            ->set_type(column::TYPE_INTEGER)
258
            ->add_fields("{$tablealias}.dbwrites")
259
            ->set_is_sortable(true);
260
 
261
        // Result column.
262
        $columns[] = (new column(
263
            'result',
264
            new lang_string('task_result', 'admin'),
265
            $this->get_entity_name()
266
        ))
267
            ->add_joins($this->get_joins())
268
            ->set_type(column::TYPE_BOOLEAN)
269
            // For accurate aggregation, we need to return boolean success = true by xor'ing the field value.
270
            ->add_field($DB->sql_bitxor("{$tablealias}.result", 1), 'success')
271
            ->set_is_sortable(true)
272
            ->add_callback(static function(bool $success): string {
273
                if (!$success) {
274
                    return get_string('task_result:failed', 'admin');
275
                }
276
                return get_string('success');
277
            });
278
 
279
        return $columns;
280
    }
281
 
282
    /**
283
     * Return list of all available filters
284
     *
285
     * @return filter[]
286
     */
287
    protected function get_all_filters(): array {
288
        global $DB;
289
 
290
        $tablealias = $this->get_table_alias('task_log');
291
 
292
        // Name filter (Filter by classname).
293
        $filters[] = (new filter(
294
            autocomplete::class,
295
            'name',
296
            new lang_string('classname', 'tool_task'),
297
            $this->get_entity_name(),
298
            "{$tablealias}.classname"
299
        ))
300
            ->add_joins($this->get_joins())
301
            ->set_options_callback(static function(): array {
302
                global $DB;
303
                $classnames = $DB->get_fieldset_sql('SELECT DISTINCT classname FROM {task_log} ORDER BY classname ASC');
304
 
305
                $options = [];
306
                foreach ($classnames as $classname) {
307
                    if (class_exists($classname)) {
308
                        $task = new $classname;
309
                        $options[$classname] = $task->get_name();
310
                    }
311
                }
312
 
313
                core_collator::asort($options);
314
                return $options;
315
            });
316
 
317
        // Component filter.
318
        $filters[] = (new filter(
319
            text::class,
320
            'component',
321
            new lang_string('plugin'),
322
            $this->get_entity_name(),
323
            "{$tablealias}.component"
324
        ))
325
            ->add_joins($this->get_joins());
326
 
327
        // Type filter.
328
        $filters[] = (new filter(
329
            select::class,
330
            'type',
331
            new lang_string('tasktype', 'admin'),
332
            $this->get_entity_name(),
333
            "{$tablealias}.type"
334
        ))
335
            ->add_joins($this->get_joins())
336
            ->set_options([
337
                \core\task\database_logger::TYPE_ADHOC => new lang_string('task_type:adhoc', 'admin'),
338
                \core\task\database_logger::TYPE_SCHEDULED => new lang_string('task_type:scheduled', 'admin'),
339
            ]);
340
 
341
        // Output filter (Filter by task output).
342
        $filters[] = (new filter(
343
            text::class,
344
            'output',
345
            new lang_string('task_logoutput', 'admin'),
346
            $this->get_entity_name(),
347
            $DB->sql_cast_to_char("{$tablealias}.output")
348
        ))
349
            ->add_joins($this->get_joins());
350
 
351
        // Start time filter.
352
        $filters[] = (new filter(
353
            date::class,
354
            'timestart',
355
            new lang_string('task_starttime', 'admin'),
356
            $this->get_entity_name(),
357
            "{$tablealias}.timestart"
358
        ))
359
            ->add_joins($this->get_joins())
360
            ->set_limited_operators([
361
                date::DATE_ANY,
362
                date::DATE_RANGE,
363
                date::DATE_PREVIOUS,
364
                date::DATE_CURRENT,
365
            ]);
366
 
367
        // End time.
368
        $filters[] = (new filter(
369
            date::class,
370
            'timeend',
371
            new lang_string('task_endtime', 'admin'),
372
            $this->get_entity_name(),
373
            "{$tablealias}.timeend"
374
        ))
375
            ->add_joins($this->get_joins())
376
            ->set_limited_operators([
377
                date::DATE_ANY,
378
                date::DATE_RANGE,
379
                date::DATE_PREVIOUS,
380
                date::DATE_CURRENT,
381
            ]);
382
 
383
        // Duration filter.
384
        $filters[] = (new filter(
385
            duration::class,
386
            'duration',
387
            new lang_string('task_duration', 'admin'),
388
            $this->get_entity_name(),
389
            "{$tablealias}.timeend - {$tablealias}.timestart"
390
        ))
391
            ->add_joins($this->get_joins());
392
 
393
        // Database reads.
394
        $filters[] = (new filter(
395
            number::class,
396
            'dbreads',
397
            new lang_string('task_dbreads', 'admin'),
398
            $this->get_entity_name(),
399
            "{$tablealias}.dbreads"
400
        ))
401
            ->add_joins($this->get_joins());
402
 
403
        // Database writes.
404
        $filters[] = (new filter(
405
            number::class,
406
            'dbwrites',
407
            new lang_string('task_dbwrites', 'admin'),
408
            $this->get_entity_name(),
409
            "{$tablealias}.dbwrites"
410
        ))
411
            ->add_joins($this->get_joins());
412
 
413
        // Result filter.
414
        $filters[] = (new filter(
415
            select::class,
416
            'result',
417
            new lang_string('task_result', 'admin'),
418
            $this->get_entity_name(),
419
            "{$tablealias}.result"
420
        ))
421
            ->add_joins($this->get_joins())
422
            ->set_options([
423
                self::SUCCESS => get_string('success'),
424
                self::FAILED => get_string('task_result:failed', 'admin'),
425
            ]);
426
 
427
        return $filters;
428
    }
429
}