Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 39 and 310]

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