[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/report/log/classes/ -> table_log.php (source)

   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   * Table log for displaying logs.
  19   *
  20   * @package    report_log
  21   * @copyright  2014 Rajesh Taneja <rajesh.taneja@gmail.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die;
  26  
  27  /**
  28   * Table log class for displaying logs.
  29   *
  30   * @package    report_log
  31   * @copyright  2014 Rajesh Taneja <rajesh.taneja@gmail.com>
  32   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class report_log_table_log extends table_sql {
  35  
  36      /** @var array list of user fullnames shown in report */
  37      private $userfullnames = array();
  38  
  39      /** @var array list of context name shown in report */
  40      private $contextname = array();
  41  
  42      /** @var stdClass filters parameters */
  43      private $filterparams;
  44  
  45      /**
  46       * Sets up the table_log parameters.
  47       *
  48       * @param string $uniqueid unique id of form.
  49       * @param stdClass $filterparams (optional) filter params.
  50       *     - int courseid: id of course
  51       *     - int userid: user id
  52       *     - int|string modid: Module id or "site_errors" to view site errors
  53       *     - int groupid: Group id
  54       *     - \core\log\sql_reader logreader: reader from which data will be fetched.
  55       *     - int edulevel: educational level.
  56       *     - string action: view action
  57       *     - int date: Date from which logs to be viewed.
  58       */
  59      public function __construct($uniqueid, $filterparams = null) {
  60          parent::__construct($uniqueid);
  61  
  62          $this->set_attribute('class', 'reportlog generaltable generalbox');
  63          $this->filterparams = $filterparams;
  64          // Add course column if logs are displayed for site.
  65          $cols = array();
  66          $headers = array();
  67          if (empty($filterparams->courseid)) {
  68              $cols = array('course');
  69              $headers = array(get_string('course'));
  70          }
  71  
  72          $this->define_columns(array_merge($cols, array('time', 'fullnameuser', 'relatedfullnameuser', 'context', 'component',
  73                  'eventname', 'description', 'origin', 'ip')));
  74          $this->define_headers(array_merge($headers, array(
  75                  get_string('time'),
  76                  get_string('fullnameuser'),
  77                  get_string('eventrelatedfullnameuser', 'report_log'),
  78                  get_string('eventcontext', 'report_log'),
  79                  get_string('eventcomponent', 'report_log'),
  80                  get_string('eventname'),
  81                  get_string('description'),
  82                  get_string('eventorigin', 'report_log'),
  83                  get_string('ip_address')
  84                  )
  85              ));
  86          $this->collapsible(false);
  87          $this->sortable(false);
  88          $this->pageable(true);
  89      }
  90  
  91      /**
  92       * Generate the course column.
  93       *
  94       * @deprecated since Moodle 2.9 MDL-48595 - please do not use this function any more.
  95       */
  96      public function col_course($event) {
  97          throw new coding_exception('col_course() can not be used any more, there is no such column.');
  98      }
  99  
 100      /**
 101       * Gets the user full name.
 102       *
 103       * This function is useful because, in the unlikely case that the user is
 104       * not already loaded in $this->userfullnames it will fetch it from db.
 105       *
 106       * @since Moodle 2.9
 107       * @param int $userid
 108       * @return string|false
 109       */
 110      protected function get_user_fullname($userid) {
 111          global $DB;
 112  
 113          if (empty($userid)) {
 114              return false;
 115          }
 116  
 117          if (!empty($this->userfullnames[$userid])) {
 118              return $this->userfullnames[$userid];
 119          }
 120  
 121          // We already looked for the user and it does not exist.
 122          if ($this->userfullnames[$userid] === false) {
 123              return false;
 124          }
 125  
 126          // If we reach that point new users logs have been generated since the last users db query.
 127          list($usql, $uparams) = $DB->get_in_or_equal($userid);
 128          $sql = "SELECT id," . get_all_user_name_fields(true) . " FROM {user} WHERE id " . $usql;
 129          if (!$user = $DB->get_records_sql($sql, $uparams)) {
 130              return false;
 131          }
 132  
 133          $this->userfullnames[$userid] = fullname($user);
 134          return $this->userfullnames[$userid];
 135      }
 136  
 137      /**
 138       * Generate the time column.
 139       *
 140       * @param stdClass $event event data.
 141       * @return string HTML for the time column
 142       */
 143      public function col_time($event) {
 144  
 145          if (empty($this->download)) {
 146              $dateformat = get_string('strftimerecent', 'core_langconfig');
 147          } else {
 148              $dateformat = get_string('strftimedatetimeshort', 'core_langconfig');
 149          }
 150          return userdate($event->timecreated, $dateformat);
 151      }
 152  
 153      /**
 154       * Generate the username column.
 155       *
 156       * @param stdClass $event event data.
 157       * @return string HTML for the username column
 158       */
 159      public function col_fullnameuser($event) {
 160          // Get extra event data for origin and realuserid.
 161          $logextra = $event->get_logextra();
 162  
 163          // Add username who did the action.
 164          if (!empty($logextra['realuserid'])) {
 165              $a = new stdClass();
 166              if (!$a->realusername = $this->get_user_fullname($logextra['realuserid'])) {
 167                  $a->realusername = '-';
 168              }
 169              if (!$a->asusername = $this->get_user_fullname($event->userid)) {
 170                  $a->asusername = '-';
 171              }
 172              if (empty($this->download)) {
 173                  $params = array('id' => $logextra['realuserid']);
 174                  if ($event->courseid) {
 175                      $params['course'] = $event->courseid;
 176                  }
 177                  $a->realusername = html_writer::link(new moodle_url('/user/view.php', $params), $a->realusername);
 178                  $params['id'] = $event->userid;
 179                  $a->asusername = html_writer::link(new moodle_url('/user/view.php', $params), $a->asusername);
 180              }
 181              $username = get_string('eventloggedas', 'report_log', $a);
 182  
 183          } else if (!empty($event->userid) && $username = $this->get_user_fullname($event->userid)) {
 184              if (empty($this->download)) {
 185                  $params = array('id' => $event->userid);
 186                  if ($event->courseid) {
 187                      $params['course'] = $event->courseid;
 188                  }
 189                  $username = html_writer::link(new moodle_url('/user/view.php', $params), $username);
 190              }
 191          } else {
 192              $username = '-';
 193          }
 194          return $username;
 195      }
 196  
 197      /**
 198       * Generate the related username column.
 199       *
 200       * @param stdClass $event event data.
 201       * @return string HTML for the related username column
 202       */
 203      public function col_relatedfullnameuser($event) {
 204          // Add affected user.
 205          if (!empty($event->relateduserid) && $username = $this->get_user_fullname($event->relateduserid)) {
 206              if (empty($this->download)) {
 207                  $params = array('id' => $event->relateduserid);
 208                  if ($event->courseid) {
 209                      $params['course'] = $event->courseid;
 210                  }
 211                  $username = html_writer::link(new moodle_url('/user/view.php', $params), $username);
 212              }
 213          } else {
 214              $username = '-';
 215          }
 216          return $username;
 217      }
 218  
 219      /**
 220       * Generate the context column.
 221       *
 222       * @param stdClass $event event data.
 223       * @return string HTML for the context column
 224       */
 225      public function col_context($event) {
 226          // Add context name.
 227          if ($event->contextid) {
 228              // If context name was fetched before then return, else get one.
 229              if (isset($this->contextname[$event->contextid])) {
 230                  return $this->contextname[$event->contextid];
 231              } else {
 232                  $context = context::instance_by_id($event->contextid, IGNORE_MISSING);
 233                  if ($context) {
 234                      $contextname = $context->get_context_name(true);
 235                      if (empty($this->download) && $url = $context->get_url()) {
 236                          $contextname = html_writer::link($url, $contextname);
 237                      }
 238                  } else {
 239                      $contextname = get_string('other');
 240                  }
 241              }
 242          } else {
 243              $contextname = get_string('other');
 244          }
 245  
 246          $this->contextname[$event->contextid] = $contextname;
 247          return $contextname;
 248      }
 249  
 250      /**
 251       * Generate the component column.
 252       *
 253       * @param stdClass $event event data.
 254       * @return string HTML for the component column
 255       */
 256      public function col_component($event) {
 257          // Component.
 258          $componentname = $event->component;
 259          if (($event->component === 'core') || ($event->component === 'legacy')) {
 260              return  get_string('coresystem');
 261          } else if (get_string_manager()->string_exists('pluginname', $event->component)) {
 262              return get_string('pluginname', $event->component);
 263          } else {
 264              return $componentname;
 265          }
 266      }
 267  
 268      /**
 269       * Generate the event name column.
 270       *
 271       * @param stdClass $event event data.
 272       * @return string HTML for the event name column
 273       */
 274      public function col_eventname($event) {
 275          // Event name.
 276          if ($this->filterparams->logreader instanceof logstore_legacy\log\store) {
 277              // Hack for support of logstore_legacy.
 278              $eventname = $event->eventname;
 279          } else {
 280              $eventname = $event->get_name();
 281          }
 282          // Only encode as an action link if we're not downloading.
 283          if (($url = $event->get_url()) && empty($this->download)) {
 284              $eventname = $this->action_link($url, $eventname, 'action');
 285          }
 286          return $eventname;
 287      }
 288  
 289      /**
 290       * Generate the description column.
 291       *
 292       * @param stdClass $event event data.
 293       * @return string HTML for the description column
 294       */
 295      public function col_description($event) {
 296          // Description.
 297          return $event->get_description();
 298      }
 299  
 300      /**
 301       * Generate the origin column.
 302       *
 303       * @param stdClass $event event data.
 304       * @return string HTML for the origin column
 305       */
 306      public function col_origin($event) {
 307          // Get extra event data for origin and realuserid.
 308          $logextra = $event->get_logextra();
 309  
 310          // Add event origin, normally IP/cron.
 311          return $logextra['origin'];
 312      }
 313  
 314      /**
 315       * Generate the ip column.
 316       *
 317       * @param stdClass $event event data.
 318       * @return string HTML for the ip column
 319       */
 320      public function col_ip($event) {
 321          // Get extra event data for origin and realuserid.
 322          $logextra = $event->get_logextra();
 323          $ip = $logextra['ip'];
 324  
 325          if (empty($this->download)) {
 326              $url = new moodle_url("/iplookup/index.php?ip={$ip}&user={$event->userid}");
 327              $ip = $this->action_link($url, $ip, 'ip');
 328          }
 329          return $ip;
 330      }
 331  
 332      /**
 333       * Method to create a link with popup action.
 334       *
 335       * @param moodle_url $url The url to open.
 336       * @param string $text Anchor text for the link.
 337       * @param string $name Name of the popup window.
 338       *
 339       * @return string html to use.
 340       */
 341      protected function action_link(moodle_url $url, $text, $name = 'popup') {
 342          global $OUTPUT;
 343          $link = new action_link($url, $text, new popup_action('click', $url, $name, array('height' => 440, 'width' => 700)));
 344          return $OUTPUT->render($link);
 345      }
 346  
 347      /**
 348       * Helper function to get legacy crud action.
 349       *
 350       * @param string $crud crud action
 351       * @return string legacy action.
 352       */
 353      public function get_legacy_crud_action($crud) {
 354          $legacyactionmap = array('c' => 'add', 'r' => 'view', 'u' => 'update', 'd' => 'delete');
 355          if (array_key_exists($crud, $legacyactionmap)) {
 356              return $legacyactionmap[$crud];
 357          } else {
 358              // From old legacy log.
 359              return '-view';
 360          }
 361      }
 362  
 363      /**
 364       * Helper function which is used by build logs to get action sql and param.
 365       *
 366       * @return array sql and param for action.
 367       */
 368      public function get_action_sql() {
 369          global $DB;
 370  
 371          // In new logs we have a field to pick, and in legacy try get this from action.
 372          if ($this->filterparams->logreader instanceof logstore_legacy\log\store) {
 373              $action = $this->get_legacy_crud_action($this->filterparams->action);
 374              $firstletter = substr($action, 0, 1);
 375              if ($firstletter == '-') {
 376                  $sql = $DB->sql_like('action', ':action', false, true, true);
 377                  $params['action'] = '%'.substr($action, 1).'%';
 378              } else {
 379                  $sql = $DB->sql_like('action', ':action', false);
 380                  $params['action'] = '%'.$action.'%';
 381              }
 382          } else if (!empty($this->filterparams->action)) {
 383              $sql = "crud = :crud";
 384              $params['crud'] = $this->filterparams->action;
 385          } else {
 386              // Add condition for all possible values of crud (to use db index).
 387              list($sql, $params) = $DB->get_in_or_equal(array('c', 'r', 'u', 'd'),
 388                      SQL_PARAMS_NAMED, 'crud');
 389              $sql = "crud ".$sql;
 390          }
 391          return array($sql, $params);
 392      }
 393  
 394      /**
 395       * Helper function which is used by build logs to get course module sql and param.
 396       *
 397       * @return array sql and param for action.
 398       */
 399      public function get_cm_sql() {
 400          $joins = array();
 401          $params = array();
 402  
 403          if ($this->filterparams->logreader instanceof logstore_legacy\log\store) {
 404              // The legacy store doesn't support context level.
 405              $joins[] = "cmid = :cmid";
 406              $params['cmid'] = $this->filterparams->modid;
 407          } else {
 408              $joins[] = "contextinstanceid = :contextinstanceid";
 409              $joins[] = "contextlevel = :contextmodule";
 410              $params['contextinstanceid'] = $this->filterparams->modid;
 411              $params['contextmodule'] = CONTEXT_MODULE;
 412          }
 413  
 414          $sql = implode(' AND ', $joins);
 415          return array($sql, $params);
 416      }
 417  
 418      /**
 419       * Query the reader. Store results in the object for use by build_table.
 420       *
 421       * @param int $pagesize size of page for paginated displayed table.
 422       * @param bool $useinitialsbar do you want to use the initials bar.
 423       */
 424      public function query_db($pagesize, $useinitialsbar = true) {
 425          global $DB;
 426  
 427          $joins = array();
 428          $params = array();
 429  
 430          // If we filter by userid and module id we also need to filter by crud and edulevel to ensure DB index is engaged.
 431          $useextendeddbindex = !($this->filterparams->logreader instanceof logstore_legacy\log\store)
 432                  && !empty($this->filterparams->userid) && !empty($this->filterparams->modid);
 433  
 434          $groupid = 0;
 435          if (!empty($this->filterparams->courseid) && $this->filterparams->courseid != SITEID) {
 436              if (!empty($this->filterparams->groupid)) {
 437                  $groupid = $this->filterparams->groupid;
 438              }
 439  
 440              $joins[] = "courseid = :courseid";
 441              $params['courseid'] = $this->filterparams->courseid;
 442          }
 443  
 444          if (!empty($this->filterparams->siteerrors)) {
 445              $joins[] = "( action='error' OR action='infected' OR action='failed' )";
 446          }
 447  
 448          if (!empty($this->filterparams->modid)) {
 449              list($actionsql, $actionparams) = $this->get_cm_sql();
 450              $joins[] = $actionsql;
 451              $params = array_merge($params, $actionparams);
 452          }
 453  
 454          if (!empty($this->filterparams->action) || $useextendeddbindex) {
 455              list($actionsql, $actionparams) = $this->get_action_sql();
 456              $joins[] = $actionsql;
 457              $params = array_merge($params, $actionparams);
 458          }
 459  
 460          // Getting all members of a group.
 461          if ($groupid and empty($this->filterparams->userid)) {
 462              if ($gusers = groups_get_members($groupid)) {
 463                  $gusers = array_keys($gusers);
 464                  $joins[] = 'userid IN (' . implode(',', $gusers) . ')';
 465              } else {
 466                  $joins[] = 'userid = 0'; // No users in groups, so we want something that will always be false.
 467              }
 468          } else if (!empty($this->filterparams->userid)) {
 469              $joins[] = "userid = :userid";
 470              $params['userid'] = $this->filterparams->userid;
 471          }
 472  
 473          if (!empty($this->filterparams->date)) {
 474              $joins[] = "timecreated > :date AND timecreated < :enddate";
 475              $params['date'] = $this->filterparams->date;
 476              $params['enddate'] = $this->filterparams->date + DAYSECS; // Show logs only for the selected date.
 477          }
 478  
 479          if (isset($this->filterparams->edulevel) && ($this->filterparams->edulevel >= 0)) {
 480              $joins[] = "edulevel = :edulevel";
 481              $params['edulevel'] = $this->filterparams->edulevel;
 482          } else if ($useextendeddbindex) {
 483              list($edulevelsql, $edulevelparams) = $DB->get_in_or_equal(array(\core\event\base::LEVEL_OTHER,
 484                  \core\event\base::LEVEL_PARTICIPATING, \core\event\base::LEVEL_TEACHING), SQL_PARAMS_NAMED, 'edulevel');
 485              $joins[] = "edulevel ".$edulevelsql;
 486              $params = array_merge($params, $edulevelparams);
 487          }
 488          // Origin.
 489          if (isset($this->filterparams->origin) && ($this->filterparams->origin != '')) {
 490              $joins[] = "origin = :origin";
 491              $params['origin'] = $this->filterparams->origin;
 492          }
 493  
 494          if (!($this->filterparams->logreader instanceof logstore_legacy\log\store)) {
 495              // Filter out anonymous actions, this is N/A for legacy log because it never stores them.
 496              $joins[] = "anonymous = 0";
 497          }
 498  
 499          $selector = implode(' AND ', $joins);
 500  
 501          if (!$this->is_downloading()) {
 502              $total = $this->filterparams->logreader->get_events_select_count($selector, $params);
 503              $this->pagesize($pagesize, $total);
 504          } else {
 505              $this->pageable(false);
 506          }
 507  
 508          // Get the users and course data.
 509          $this->rawdata = $this->filterparams->logreader->get_events_select_iterator($selector, $params,
 510              $this->filterparams->orderby, $this->get_page_start(), $this->get_page_size());
 511  
 512          // Update list of users which will be displayed on log page.
 513          $this->update_users_used();
 514  
 515          // Get the events. Same query than before; even if it is not likely, logs from new users
 516          // may be added since last query so we will need to work around later to prevent problems.
 517          // In almost most of the cases this will be better than having two opened recordsets.
 518          $this->rawdata = $this->filterparams->logreader->get_events_select_iterator($selector, $params,
 519              $this->filterparams->orderby, $this->get_page_start(), $this->get_page_size());
 520  
 521          // Set initial bars.
 522          if ($useinitialsbar && !$this->is_downloading()) {
 523              $this->initialbars($total > $pagesize);
 524          }
 525  
 526      }
 527  
 528      /**
 529       * Helper function to create list of course shortname and user fullname shown in log report.
 530       *
 531       * This will update $this->userfullnames and $this->courseshortnames array with userfullname and courseshortname (with link),
 532       * which will be used to render logs in table.
 533       *
 534       * @deprecated since Moodle 2.9 MDL-48595 - please do not use this function any more.
 535       */
 536      public function update_users_and_courses_used() {
 537          throw new coding_exception('update_users_and_courses_used() can not be used any more, please use update_users_used() instead.');
 538      }
 539  
 540      /**
 541       * Helper function to create list of user fullnames shown in log report.
 542       *
 543       * This will update $this->userfullnames array with userfullname,
 544       * which will be used to render logs in table.
 545       *
 546       * @since   Moodle 2.9
 547       * @return  void
 548       */
 549      protected function update_users_used() {
 550          global $DB;
 551  
 552          $this->userfullnames = array();
 553          $userids = array();
 554  
 555          // For each event cache full username.
 556          // Get list of userids which will be shown in log report.
 557          foreach ($this->rawdata as $event) {
 558              $logextra = $event->get_logextra();
 559              if (!empty($event->userid) && empty($userids[$event->userid])) {
 560                  $userids[$event->userid] = $event->userid;
 561              }
 562              if (!empty($logextra['realuserid']) && empty($userids[$logextra['realuserid']])) {
 563                  $userids[$logextra['realuserid']] = $logextra['realuserid'];
 564              }
 565              if (!empty($event->relateduserid) && empty($userids[$event->relateduserid])) {
 566                  $userids[$event->relateduserid] = $event->relateduserid;
 567              }
 568          }
 569          $this->rawdata->close();
 570  
 571          // Get user fullname and put that in return list.
 572          if (!empty($userids)) {
 573              list($usql, $uparams) = $DB->get_in_or_equal($userids);
 574              $users = $DB->get_records_sql("SELECT id," . get_all_user_name_fields(true) . " FROM {user} WHERE id " . $usql,
 575                      $uparams);
 576              foreach ($users as $userid => $user) {
 577                  $this->userfullnames[$userid] = fullname($user);
 578                  unset($userids[$userid]);
 579              }
 580  
 581              // We fill the array with false values for the users that don't exist anymore
 582              // in the database so we don't need to query the db again later.
 583              foreach ($userids as $userid) {
 584                  $this->userfullnames[$userid] = false;
 585              }
 586          }
 587      }
 588  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1