Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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

   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   * Restore support for tool_log logstore subplugins.
  19   *
  20   * @package    tool_log
  21   * @category   backup
  22   * @copyright  2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Parent class of all the logstore subplugin implementations.
  30   *
  31   * Note: While this intermediate class is not strictly required and all the
  32   * subplugin implementations can extend directly {@link restore_subplugin},
  33   * it is always recommended to have it, both for better testing and also
  34   * for sharing code between all subplugins.
  35   */
  36  abstract class restore_tool_log_logstore_subplugin extends restore_subplugin {
  37  
  38      /**
  39       * Process log entries.
  40       *
  41       * This method proceeds to read, complete, remap and, finally,
  42       * discard or save every log entry.
  43       *
  44       * @param array $data log entry.
  45       * @param bool $jsonformat If true, uses JSON format for the 'other' field
  46       * @return object|null $dataobject A data object with values for one or more fields in the record,
  47       *  or null if we are not going to process the log.
  48       */
  49      protected function process_log($data, bool $jsonformat = false) {
  50          $data = (object) $data;
  51  
  52          // Complete the information that does not come from backup.
  53          $contextid = $data->contextid;
  54          if (!$data->contextid = $this->get_mappingid('context', $contextid)) {
  55              $message = "Context id \"$contextid\" could not be mapped. Skipping log record.";
  56              $this->log($message, backup::LOG_DEBUG);
  57              return;
  58          }
  59          $context = context::instance_by_id($data->contextid, MUST_EXIST);
  60          $data->contextlevel = $context->contextlevel;
  61          $data->contextinstanceid = $context->instanceid;
  62          $data->courseid = $this->task->get_courseid();
  63  
  64          // Remap users.
  65          $userid = $data->userid;
  66          if (!$data->userid = $this->get_mappingid('user', $userid)) {
  67              $message = "User id \"$userid\" could not be mapped. Skipping log record.";
  68              $this->log($message, backup::LOG_DEBUG);
  69              return;
  70          }
  71          if (!empty($data->relateduserid)) { // This is optional.
  72              $relateduserid = $data->relateduserid;
  73              if (!$data->relateduserid = $this->get_mappingid('user', $relateduserid)) {
  74                  $message = "Related user id \"$relateduserid\" could not be mapped. Skipping log record.";
  75                  $this->log($message, backup::LOG_DEBUG);
  76                  return;
  77              }
  78          }
  79          if (!empty($data->realuserid)) { // This is optional.
  80              $realuserid = $data->realuserid;
  81              if (!$data->realuserid = $this->get_mappingid('user', $realuserid)) {
  82                  $message = "Real user id \"$realuserid\" could not be mapped. Skipping log record.";
  83                  $this->log($message, backup::LOG_DEBUG);
  84                  return;
  85              }
  86          }
  87  
  88          // There is no need to roll dates. Logs are supposed to be immutable. See MDL-44961.
  89  
  90          // Revert other to its original php way.
  91          $data->other = \tool_log\local\privacy\helper::decode_other(base64_decode($data->other));
  92  
  93          // Arrived here, we have both 'objectid' and 'other' to be converted. This is the tricky part.
  94          // Both are pointing to other records id, but the sources are not identified in the
  95          // same way restore mappings work. So we need to delegate them to some resolver that
  96          // will give us the correct restore mapping to be used.
  97          if (!empty($data->objectid)) {
  98              // Check if there is an available class for this event we can use to map this value.
  99              $eventclass = $data->eventname;
 100              if (class_exists($eventclass)) {
 101                  $mapping = $eventclass::get_objectid_mapping();
 102                  if ($mapping) {
 103                      // Check if it can not be mapped.
 104                      if ((is_int($mapping) && $mapping === \core\event\base::NOT_MAPPED) ||
 105                          ($mapping['restore'] === \core\event\base::NOT_MAPPED)) {
 106                          $data->objectid = \core\event\base::NOT_MAPPED;
 107                      } else {
 108                          $data->objectid = $this->get_mappingid($mapping['restore'], $data->objectid,
 109                              \core\event\base::NOT_FOUND);
 110                      }
 111                  }
 112              } else {
 113                  $message = "Event class not found: \"$eventclass\". Skipping log record.";
 114                  $this->log($message, backup::LOG_DEBUG);
 115                  return; // No such class, can not restore.
 116              }
 117          }
 118          if (!empty($data->other)) {
 119              // Check if there is an available class for this event we can use to map this value.
 120              $eventclass = $data->eventname;
 121              if (class_exists($eventclass)) {
 122                  $othermapping = $eventclass::get_other_mapping();
 123                  if ($othermapping) {
 124                      // Go through the data we have.
 125                      foreach ($data->other as $key => $value) {
 126                          // Check if there is a corresponding key we can use to map to.
 127                          if (isset($othermapping[$key]) && !empty($value)) {
 128                              // Ok, let's map this.
 129                              $mapping = $othermapping[$key];
 130                              // Check if it can not be mapped.
 131                              if ((is_int($mapping) && $mapping === \core\event\base::NOT_MAPPED) ||
 132                                  ($mapping['restore'] === \core\event\base::NOT_MAPPED)) {
 133                                  $data->other[$key] = \core\event\base::NOT_MAPPED;
 134                              } else {
 135                                  $data->other[$key] = $this->get_mappingid($mapping['restore'], $value,
 136                                      \core\event\base::NOT_FOUND);
 137                              }
 138                          }
 139                      }
 140                  }
 141              } else {
 142                  $message = "Event class not found: \"$eventclass\". Skipping log record.";
 143                  $this->log($message, backup::LOG_DEBUG);
 144                  return; // No such class, can not restore.
 145              }
 146          }
 147  
 148          // Serialize 'other' field so we can store it in the DB.
 149          if ($jsonformat) {
 150              $data->other = json_encode($data->other);
 151          } else {
 152              $data->other = serialize($data->other);
 153          }
 154  
 155          return $data;
 156      }
 157  }