Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 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 39 and 310] [Versions 39 and 311]

   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              '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)) {
  86              $orwhere = [];
  87              $filter = str_replace('\\', '\\\\', $filter);
  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) . ")";
  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.id, tl.type, tl.component, tl.classname, tl.userid, tl.timestart, tl.timeend,
 135                      tl.dbreads, tl.dbwrites, tl.result,
 136                      tl.dbreads + tl.dbwrites AS db,
 137                      tl.timeend - tl.timestart AS duration,
 138                      {$userfields}
 139                  FROM {task_log} tl
 140             LEFT JOIN {user} u ON u.id = tl.userid
 141                  {$where}
 142                  {$sort}";
 143  
 144          $this->pagesize($pagesize, $DB->count_records_sql("SELECT COUNT('x') FROM {task_log} tl {$where}", $this->sql->params));
 145          if (!$this->is_downloading()) {
 146              $this->rawdata = $DB->get_records_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size());
 147          } else {
 148              $this->rawdata = $DB->get_records_sql($sql, $this->sql->params);
 149          }
 150      }
 151  
 152      /**
 153       * Format the name cell.
 154       *
 155       * @param   \stdClass $row
 156       * @return  string
 157       */
 158      public function col_classname($row) : string {
 159          $output = '';
 160          if (class_exists($row->classname)) {
 161              $task = new $row->classname;
 162              if ($task instanceof \core\task\scheduled_task) {
 163                  $output = $task->get_name();
 164              }
 165          }
 166  
 167          $output .= \html_writer::tag('div', "\\{$row->classname}", [
 168                  'class' => 'task-class',
 169              ]);
 170          return $output;
 171      }
 172  
 173      /**
 174       * Format the type cell.
 175       *
 176       * @param   \stdClass $row
 177       * @return  string
 178       */
 179      public function col_type($row) : string {
 180          if (\core\task\database_logger::TYPE_SCHEDULED == $row->type) {
 181              return get_string('task_type:scheduled', 'admin');
 182          } else {
 183              return get_string('task_type:adhoc', 'admin');
 184          }
 185      }
 186  
 187      /**
 188       * Format the timestart cell.
 189       *
 190       * @param   \stdClass $row
 191       * @return  string
 192       */
 193      public function col_result($row) : string {
 194          if ($row->result) {
 195              return get_string('task_result:failed', 'admin');
 196          } else {
 197              return get_string('success');
 198          }
 199      }
 200  
 201      /**
 202       * Format the timestart cell.
 203       *
 204       * @param   \stdClass $row
 205       * @return  string
 206       */
 207      public function col_timestart($row) : string {
 208          return userdate($row->timestart, get_string('strftimedatetimeshort', 'langconfig'));
 209      }
 210  
 211      /**
 212       * Format the duration cell.
 213       *
 214       * @param   \stdClass $row
 215       * @return  string
 216       */
 217      public function col_duration($row) : string {
 218          $duration = round($row->timeend - $row->timestart, 2);
 219  
 220          if (empty($duration)) {
 221              // The format_time function returns 'now' when the difference is exactly 0.
 222              // Note: format_time performs concatenation in exactly this fashion so we should do this for consistency.
 223              return '0 ' . get_string('secs', 'moodle');
 224          }
 225  
 226          return format_time($duration);
 227      }
 228  
 229      /**
 230       * Format the DB details cell.
 231       *
 232       * @param   \stdClass $row
 233       * @return  string
 234       */
 235      public function col_db($row) : string {
 236          $output = '';
 237  
 238          $output .= \html_writer::div(get_string('task_stats:dbreads', 'admin', $row->dbreads));
 239          $output .= \html_writer::div(get_string('task_stats:dbwrites', 'admin', $row->dbwrites));
 240  
 241          return $output;
 242      }
 243  
 244      /**
 245       * Format the actions cell.
 246       *
 247       * @param   \stdClass $row
 248       * @return  string
 249       */
 250      public function col_actions($row) : string {
 251          global $OUTPUT;
 252  
 253          $actions = [];
 254  
 255          $url = new \moodle_url('/admin/tasklogs.php', ['logid' => $row->id]);
 256  
 257          // Quick view.
 258          $actions[] = $OUTPUT->action_icon(
 259              $url,
 260              new \pix_icon('e/search', get_string('view')),
 261              new \popup_action('click', $url)
 262          );
 263  
 264          // Download.
 265          $actions[] = $OUTPUT->action_icon(
 266              new \moodle_url($url, ['download' => true]),
 267              new \pix_icon('t/download', get_string('download'))
 268          );
 269  
 270          return implode('&nbsp;', $actions);
 271      }
 272  
 273      /**
 274       * Format the user cell.
 275       *
 276       * @param   \stdClass $row
 277       * @return  string
 278       */
 279      public function col_userid($row) : string {
 280          if (empty($row->userid)) {
 281              return '';
 282          }
 283  
 284          $user = (object) [];
 285          username_load_fields_from_object($user, $row, 'user');
 286  
 287          return fullname($user);
 288      }
 289  }