MDL-49399 tool_task: Link to log viewer
[moodle.git] / admin / classes / task_log_table.php
CommitLineData
8c69e86c
AN
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/**
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 */
24
25namespace core_admin;
26
27defined('MOODLE_INTERNAL') || die();
28
29require_once($CFG->libdir . '/tablelib.php');
30
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 */
37class task_log_table extends \table_sql {
38
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;
47
48 if (-1 === $resultfilter) {
49 $resultfilter = null;
50 }
51
52 parent::__construct('tasklogs');
53
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));
66
67 // The name column is a header.
68 $this->define_header_column('classname');
69
70 // This table is not collapsible.
71 $this->collapsible(false);
72
73 // The actions class should not wrap. Use the BS text utility class.
74 $this->column_class('actions', 'text-nowrap');
75
76 // Allow pagination.
77 $this->pageable(true);
78
79 // Allow sorting. Default to sort by timestarted DESC.
80 $this->sortable(true, 'timestart', SORT_DESC);
81
82 // Add filtering.
83 $where = [];
84 $params = [];
85 if (!empty($filter)) {
251ee97c 86 $orwhere = [];
8c69e86c 87 $filter = str_replace('\\', '\\\\', $filter);
251ee97c
AN
88
89 // Check the class name.
90 $orwhere[] = $DB->sql_like('classname', ':classfilter', false, false);
91 $params['classfilter'] = '%' . $DB->sql_like_escape($filter) . '%';
92
93 $orwhere[] = $DB->sql_like('output', ':outputfilter', false, false);
94 $params['outputfilter'] = '%' . $DB->sql_like_escape($filter) . '%';
95
96 $where[] = "(" . implode(' OR ', $orwhere) . ")";
8c69e86c
AN
97 }
98
99 if (null !== $resultfilter) {
100 $where[] = 'tl.result = :result';
101 $params['result'] = $resultfilter;
102 }
103
104 $where = implode(' AND ', $where);
105
106 $this->set_sql('', '', $where, $params);
107 }
108
109 /**
110 * Query the db. Store results in the table object for use by build_table.
111 *
112 * @param int $pagesize size of page for paginated displayed table.
113 * @param bool $useinitialsbar do you want to use the initials bar. Bar
114 * will only be used if there is a fullname column defined for the table.
115 */
116 public function query_db($pagesize, $useinitialsbar = true) {
117 global $DB;
118
119 // Fetch the attempts.
120 $sort = $this->get_sql_sort();
121 if ($sort) {
122 $sort = "ORDER BY $sort";
123 }
124
125 $extrafields = get_extra_user_fields(\context_system::instance());
126 $userfields = \user_picture::fields('u', $extrafields, 'userid2', 'user');
127
128 $where = '';
129 if (!empty($this->sql->where)) {
130 $where = "WHERE {$this->sql->where}";
131 }
132
133 $sql = "SELECT
134 tl.*,
135 tl.dbreads + tl.dbwrites AS db,
136 tl.timeend - tl.timestart AS duration,
137 {$userfields}
138 FROM {task_log} tl
139 LEFT JOIN {user} u ON u.id = tl.userid
140 {$where}
141 {$sort}";
142
143 $this->pagesize($pagesize, $DB->count_records_sql("SELECT COUNT('x') FROM {task_log} tl {$where}", $this->sql->params));
144 if (!$this->is_downloading()) {
145 $this->rawdata = $DB->get_records_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
146 } else {
147 $this->rawdata = $DB->get_records_sql($sql, $this->sql->params);
148 }
149 }
150
151 /**
152 * Format the name cell.
153 *
154 * @param \stdClass $row
155 * @return string
156 */
157 public function col_classname($row) : string {
158 $output = '';
159 if (class_exists($row->classname)) {
160 $task = new $row->classname;
161 if ($task instanceof \core\task\scheduled_task) {
162 $output = $task->get_name();
163 }
164 }
165
166 $output .= \html_writer::tag('div', "\\{$row->classname}", [
167 'class' => 'task-class',
168 ]);
169 return $output;
170 }
171
172 /**
173 * Format the type cell.
174 *
175 * @param \stdClass $row
176 * @return string
177 */
178 public function col_type($row) : string {
179 if (\core\task\database_logger::TYPE_SCHEDULED == $row->type) {
180 return get_string('task_type:scheduled', 'admin');
181 } else {
182 return get_string('task_type:adhoc', 'admin');
183 }
184 }
185
186 /**
187 * Format the timestart cell.
188 *
189 * @param \stdClass $row
190 * @return string
191 */
192 public function col_result($row) : string {
193 if ($row->result) {
194 return get_string('task_result:failed', 'admin');
195 } else {
196 return get_string('success');
197 }
198 }
199
200 /**
201 * Format the timestart cell.
202 *
203 * @param \stdClass $row
204 * @return string
205 */
206 public function col_timestart($row) : string {
207 return userdate($row->timestart, get_string('strftimedatetimeshort', 'langconfig'));
208 }
209
210 /**
211 * Format the duration cell.
212 *
213 * @param \stdClass $row
214 * @return string
215 */
216 public function col_duration($row) : string {
217 $duration = round($row->timeend - $row->timestart, 2);
218
219 if (empty($duration)) {
220 // The format_time function returns 'now' when the difference is exactly 0.
221 // Note: format_time performs concatenation in exactly this fashion so we should do this for consistency.
222 return '0 ' . get_string('secs', 'moodle');
223 }
224
225 return format_time($duration);
226 }
227
228 /**
229 * Format the DB details cell.
230 *
231 * @param \stdClass $row
232 * @return string
233 */
234 public function col_db($row) : string {
235 $output = '';
236
237 $output .= \html_writer::div(get_string('task_stats:dbreads', 'admin', $row->dbreads));
238 $output .= \html_writer::div(get_string('task_stats:dbwrites', 'admin', $row->dbwrites));
239
240 return $output;
241 }
242
243 /**
244 * Format the actions cell.
245 *
246 * @param \stdClass $row
247 * @return string
248 */
249 public function col_actions($row) : string {
250 global $OUTPUT;
251
252 $actions = [];
253
254 $url = new \moodle_url('/admin/tasklogs.php', ['logid' => $row->id]);
255
256 // Quick view.
257 $actions[] = $OUTPUT->action_icon(
258 $url,
259 new \pix_icon('e/search', get_string('view')),
260 new \popup_action('click', $url)
261 );
262
263 // Download.
264 $actions[] = $OUTPUT->action_icon(
265 new \moodle_url($url, ['download' => true]),
266 new \pix_icon('t/download', get_string('download'))
267 );
268
269 return implode('&nbsp;', $actions);
270 }
271
272 /**
273 * Format the user cell.
274 *
275 * @param \stdClass $row
276 * @return string
277 */
278 public function col_userid($row) : string {
279 if (empty($row->userid)) {
280 return '';
281 }
282
283 $user = (object) [];
284 username_load_fields_from_object($user, $row, 'user');
285
286 return fullname($user);
287 }
288}