MDL-49399 task: Add admin log viewer
[moodle.git] / admin / classes / task_log_table.php
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/>.
17 /**
18  * Task log table.
19  *
20  * @package    core_admin
21  * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace core_admin;
27 defined('MOODLE_INTERNAL') || die();
29 require_once($CFG->libdir . '/tablelib.php');
31 /**
32  * Table to display list of task logs.
33  *
34  * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
35  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36  */
37 class task_log_table extends \table_sql {
39     /**
40      * Constructor for the task_log table.
41      *
42      * @param   string      $filter
43      * @param   int         $resultfilter
44      */
45     public function __construct(string $filter = '', int $resultfilter = null) {
46         global $DB;
48         if (-1 === $resultfilter) {
49             $resultfilter = null;
50         }
52         parent::__construct('tasklogs');
54         $columnheaders = [
55             'classname'  => get_string('name'),
56             'type'       => get_string('tasktype', 'admin'),
57             'userid'     => get_string('user', 'admin'),
58             'timestart'  => get_string('task_starttime', 'admin'),
59             'duration'   => get_string('task_duration', 'admin'),
60             'db'         => get_string('task_dbstats', 'admin'),
61             'result'     => get_string('task_result', 'admin'),
62             'actions'    => '',
63         ];
64         $this->define_columns(array_keys($columnheaders));
65         $this->define_headers(array_values($columnheaders));
67         // The name column is a header.
68         $this->define_header_column('classname');
70         // This table is not collapsible.
71         $this->collapsible(false);
73         // The actions class should not wrap. Use the BS text utility class.
74         $this->column_class('actions', 'text-nowrap');
76         // Allow pagination.
77         $this->pageable(true);
79         // Allow sorting. Default to sort by timestarted DESC.
80         $this->sortable(true, 'timestart', SORT_DESC);
82         // Add filtering.
83         $where = [];
84         $params = [];
85         if (!empty($filter)) {
86             $where[] = $DB->sql_like('classname', ':filter', false, false);
87             $filter = str_replace('\\', '\\\\', $filter);
88             $params['filter'] = '%' . $DB->sql_like_escape($filter) . '%';
89         }
91         if (null !== $resultfilter) {
92             $where[] = 'tl.result = :result';
93             $params['result'] = $resultfilter;
94         }
96         $where = implode(' AND ', $where);
98         $this->set_sql('', '', $where, $params);
99     }
101     /**
102      * Query the db. Store results in the table object for use by build_table.
103      *
104      * @param int $pagesize size of page for paginated displayed table.
105      * @param bool $useinitialsbar do you want to use the initials bar. Bar
106      * will only be used if there is a fullname column defined for the table.
107      */
108     public function query_db($pagesize, $useinitialsbar = true) {
109         global $DB;
111         // Fetch the attempts.
112         $sort = $this->get_sql_sort();
113         if ($sort) {
114             $sort = "ORDER BY $sort";
115         }
117         $extrafields = get_extra_user_fields(\context_system::instance());
118         $userfields = \user_picture::fields('u', $extrafields, 'userid2', 'user');
120         $where = '';
121         if (!empty($this->sql->where)) {
122             $where = "WHERE {$this->sql->where}";
123         }
125         $sql = "SELECT
126                     tl.*,
127                     tl.dbreads + tl.dbwrites AS db,
128                     tl.timeend - tl.timestart AS duration,
129                     {$userfields}
130                 FROM {task_log} tl
131            LEFT JOIN {user} u ON u.id = tl.userid
132                 {$where}
133                 {$sort}";
135         $this->pagesize($pagesize, $DB->count_records_sql("SELECT COUNT('x') FROM {task_log} tl {$where}", $this->sql->params));
136         if (!$this->is_downloading()) {
137             $this->rawdata = $DB->get_records_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
138         } else {
139             $this->rawdata = $DB->get_records_sql($sql, $this->sql->params);
140         }
141     }
143     /**
144      * Format the name cell.
145      *
146      * @param   \stdClass $row
147      * @return  string
148      */
149     public function col_classname($row) : string {
150         $output = '';
151         if (class_exists($row->classname)) {
152             $task = new $row->classname;
153             if ($task instanceof \core\task\scheduled_task) {
154                 $output = $task->get_name();
155             }
156         }
158         $output .= \html_writer::tag('div', "\\{$row->classname}", [
159                 'class' => 'task-class',
160             ]);
161         return $output;
162     }
164     /**
165      * Format the type cell.
166      *
167      * @param   \stdClass $row
168      * @return  string
169      */
170     public function col_type($row) : string {
171         if (\core\task\database_logger::TYPE_SCHEDULED == $row->type) {
172             return get_string('task_type:scheduled', 'admin');
173         } else {
174             return get_string('task_type:adhoc', 'admin');
175         }
176     }
178     /**
179      * Format the timestart cell.
180      *
181      * @param   \stdClass $row
182      * @return  string
183      */
184     public function col_result($row) : string {
185         if ($row->result) {
186             return get_string('task_result:failed', 'admin');
187         } else {
188             return get_string('success');
189         }
190     }
192     /**
193      * Format the timestart cell.
194      *
195      * @param   \stdClass $row
196      * @return  string
197      */
198     public function col_timestart($row) : string {
199         return userdate($row->timestart, get_string('strftimedatetimeshort', 'langconfig'));
200     }
202     /**
203      * Format the duration cell.
204      *
205      * @param   \stdClass $row
206      * @return  string
207      */
208     public function col_duration($row) : string {
209         $duration = round($row->timeend - $row->timestart, 2);
211         if (empty($duration)) {
212             // The format_time function returns 'now' when the difference is exactly 0.
213             // Note: format_time performs concatenation in exactly this fashion so we should do this for consistency.
214             return '0 ' . get_string('secs', 'moodle');
215         }
217         return format_time($duration);
218     }
220     /**
221      * Format the DB details cell.
222      *
223      * @param   \stdClass $row
224      * @return  string
225      */
226     public function col_db($row) : string {
227         $output = '';
229         $output .= \html_writer::div(get_string('task_stats:dbreads', 'admin', $row->dbreads));
230         $output .= \html_writer::div(get_string('task_stats:dbwrites', 'admin', $row->dbwrites));
232         return $output;
233     }
235     /**
236      * Format the actions cell.
237      *
238      * @param   \stdClass $row
239      * @return  string
240      */
241     public function col_actions($row) : string {
242         global $OUTPUT;
244         $actions = [];
246         $url = new \moodle_url('/admin/tasklogs.php', ['logid' => $row->id]);
248         // Quick view.
249         $actions[] = $OUTPUT->action_icon(
250             $url,
251             new \pix_icon('e/search', get_string('view')),
252             new \popup_action('click', $url)
253         );
255         // Download.
256         $actions[] = $OUTPUT->action_icon(
257             new \moodle_url($url, ['download' => true]),
258             new \pix_icon('t/download', get_string('download'))
259         );
261         return implode('&nbsp;', $actions);
262     }
264     /**
265      * Format the user cell.
266      *
267      * @param   \stdClass $row
268      * @return  string
269      */
270     public function col_userid($row) : string {
271         if (empty($row->userid)) {
272             return '';
273         }
275         $user = (object) [];
276         username_load_fields_from_object($user, $row, 'user');
278         return fullname($user);
279     }