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 402] [Versions 39 and 403]

   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   * Log store manager.
  19   *
  20   * @package    tool_log
  21   * @copyright  2013 Petr Skoda {@link http://skodak.org}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace tool_log\log;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  class manager implements \core\log\manager {
  30      /** @var \core\log\reader[] $readers list of initialised log readers */
  31      protected $readers;
  32  
  33      /** @var \tool_log\log\writer[] $writers list of initialised log writers */
  34      protected $writers;
  35  
  36      /** @var \tool_log\log\store[] $stores list of all enabled stores */
  37      protected $stores;
  38  
  39      /**
  40       * Delayed initialisation of singleton.
  41       */
  42      protected function init() {
  43          if (isset($this->stores)) {
  44              // Do not bother checking readers and writers here
  45              // because everything is init here.
  46              return;
  47          }
  48          $this->stores = array();
  49          $this->readers = array();
  50          $this->writers = array();
  51  
  52          // Register shutdown handler - this may be useful for buffering, file handle closing, etc.
  53          \core_shutdown_manager::register_function(array($this, 'dispose'));
  54  
  55          $plugins = get_config('tool_log', 'enabled_stores');
  56          if (empty($plugins)) {
  57              return;
  58          }
  59  
  60          $plugins = explode(',', $plugins);
  61          foreach ($plugins as $plugin) {
  62              $classname = "\\$plugin\\log\\store";
  63              if (class_exists($classname)) {
  64                  $store = new $classname($this);
  65                  $this->stores[$plugin] = $store;
  66                  if ($store instanceof \tool_log\log\writer) {
  67                      $this->writers[$plugin] = $store;
  68                  }
  69                  if ($store instanceof \core\log\reader) {
  70                      $this->readers[$plugin] = $store;
  71                  }
  72              }
  73          }
  74      }
  75  
  76      /**
  77       * Called from the observer only.
  78       *
  79       * @param \core\event\base $event
  80       */
  81      public function process(\core\event\base $event) {
  82          $this->init();
  83          foreach ($this->writers as $plugin => $writer) {
  84              try {
  85                  $writer->write($event, $this);
  86              } catch (\Exception $e) {
  87                  debugging('Exception detected when logging event ' . $event->eventname . ' in ' . $plugin . ': ' .
  88                      $e->getMessage(), DEBUG_NORMAL, $e->getTrace());
  89              }
  90          }
  91      }
  92  
  93      /**
  94       * Returns list of available log readers.
  95       *
  96       * This way the reports find out available sources of data.
  97       *
  98       * @param string $interface Returned stores must implement this interface.
  99       *
 100       * @return \core\log\reader[] list of available log data readers
 101       */
 102      public function get_readers($interface = null) {
 103          $this->init();
 104          $return = array();
 105          foreach ($this->readers as $plugin => $reader) {
 106              if (empty($interface) || ($reader instanceof $interface)) {
 107                  $return[$plugin] = $reader;
 108              }
 109          }
 110  
 111          return $return;
 112      }
 113  
 114      /**
 115       * Get a list of reports that support the given store instance.
 116       *
 117       * @param string $logstore Name of the store.
 118       *
 119       * @return array List of supported reports
 120       */
 121      public function get_supported_reports($logstore) {
 122  
 123          $allstores = self::get_store_plugins();
 124          if (empty($allstores[$logstore])) {
 125              // Store doesn't exist.
 126              return array();
 127          }
 128  
 129          $reports = get_plugin_list_with_function('report', 'supports_logstore', 'lib.php');
 130          $enabled = $this->stores;
 131  
 132          if (empty($enabled[$logstore])) {
 133              // Store is not enabled, init an instance.
 134              $classname = '\\' . $logstore . '\log\store';
 135              $instance = new $classname($this);
 136          } else {
 137              $instance = $enabled[$logstore];
 138          }
 139  
 140          $return = array();
 141          foreach ($reports as $report => $fulldir) {
 142              if (component_callback($report, 'supports_logstore', array($instance), false)) {
 143                  $return[$report] = get_string('pluginname', $report);
 144              }
 145          }
 146  
 147          return $return;
 148      }
 149  
 150      /**
 151       * For a given report, returns a list of log stores that are supported.
 152       *
 153       * @param string $component component.
 154       *
 155       * @return false|array list of logstores that support the given report. It returns false if the given $component doesn't
 156       *      require logstores.
 157       */
 158      public function get_supported_logstores($component) {
 159  
 160          $allstores = self::get_store_plugins();
 161          $enabled = $this->stores;
 162  
 163          $function = component_callback_exists($component, 'supports_logstore');
 164          if (!$function) {
 165              // The report doesn't define the callback, most probably it doesn't need log stores.
 166              return false;
 167          }
 168  
 169          $return = array();
 170          foreach ($allstores as $store => $logclass) {
 171              $instance = empty($enabled[$store]) ? new $logclass($this) : $enabled[$store];
 172              if ($function($instance)) {
 173                  $return[$store] = get_string('pluginname', $store);
 174              }
 175          }
 176          return $return;
 177      }
 178  
 179      /**
 180       * Intended for store management, do not use from reports.
 181       *
 182       * @return store[] Returns list of available store plugins.
 183       */
 184      public static function get_store_plugins() {
 185          return \core_component::get_plugin_list_with_class('logstore', 'log\store');
 186      }
 187  
 188      /**
 189       * Usually called automatically from shutdown manager,
 190       * this allows us to implement buffering of write operations.
 191       */
 192      public function dispose() {
 193          if ($this->stores) {
 194              foreach ($this->stores as $store) {
 195                  $store->dispose();
 196              }
 197          }
 198          $this->stores = null;
 199          $this->readers = null;
 200          $this->writers = null;
 201      }
 202  
 203      /**
 204       * Legacy add_to_log() redirection.
 205       *
 206       * To be used only from deprecated add_to_log() function and event trigger() method.
 207       *
 208       * NOTE: this is hardcoded to legacy log store plugin, hopefully we can get rid of it soon.
 209       *
 210       * @param int $courseid The course id
 211       * @param string $module The module name  e.g. forum, journal, resource, course, user etc
 212       * @param string $action 'view', 'update', 'add' or 'delete', possibly followed by another word to clarify
 213       * @param string $url The file and parameters used to see the results of the action
 214       * @param string $info Additional description information
 215       * @param int $cm The course_module->id if there is one
 216       * @param int|\stdClass $user If log regards $user other than $USER
 217       * @param string $ip Override the IP, should only be used for restore.
 218       * @param int $time Override the log time, should only be used for restore.
 219       */
 220      public function legacy_add_to_log($courseid, $module, $action, $url = '', $info = '',
 221                                        $cm = 0, $user = 0, $ip = null, $time = null) {
 222          $this->init();
 223          if (isset($this->stores['logstore_legacy'])) {
 224              $this->stores['logstore_legacy']->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user, $ip, $time);
 225          }
 226      }
 227  }