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.
   1  <?php
   2  
   3  // This file is part of Moodle - http://moodle.org/
   4  //
   5  // Moodle is free software: you can redistribute it and/or modify
   6  // it under the terms of the GNU General Public License as published by
   7  // the Free Software Foundation, either version 3 of the License, or
   8  // (at your option) any later version.
   9  //
  10  // Moodle is distributed in the hope that it will be useful,
  11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  // GNU General Public License for more details.
  14  //
  15  // You should have received a copy of the GNU General Public License
  16  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  17  
  18  /**
  19   * @package    moodlecore
  20   * @subpackage backup-logger
  21   * @copyright  2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  /**
  26   * Base abstract class for all the loggers to be used in backup/restore
  27   *
  28   * Any message passed will be processed by all the loggers in the defined chain
  29   * (note some implementations may be not strictly "loggers" but classes performing
  30   * other sort of tasks (avoiding browser/php timeouts, painters...). One simple 1-way
  31   * basic chain of commands/responsibility pattern.
  32   *
  33   * TODO: Finish phpdocs
  34   */
  35  abstract class base_logger implements checksumable {
  36  
  37      protected $level;     // minimum level of logging this logger must handle (valid level from @backup class)
  38      protected $showdate;  // flag to decide if the logger must output the date (true) or no (false)
  39      protected $showlevel; // flag to decide if the logger must output the level (true) or no (false)
  40      protected $next; // next logger in the chain
  41  
  42      public function __construct($level, $showdate = false, $showlevel = false) {
  43          // TODO: check level is correct
  44          $this->level = $level;
  45          $this->showdate = $showdate;
  46          $this->showlevel = $showlevel;
  47          $this->next = null;
  48      }
  49  
  50      public final function set_next($next) {
  51          // TODO: Check is a base logger
  52  
  53          // TODO: Check next hasn't been set already
  54  
  55          // TODO: Avoid circular dependencies
  56          if ($this->is_circular_reference($next)) {
  57              $a = new stdclass();
  58              $a->alreadyinchain = get_class($this);
  59              $a->main = get_class($next);
  60              throw new base_logger_exception('logger_circular_reference', $a);
  61          }
  62  
  63          $this->next = $next;
  64      }
  65  
  66      public function get_next() {
  67          return $this->next;
  68      }
  69  
  70      public function get_level() {
  71          return $this->level;
  72      }
  73  
  74      /**
  75       * Destroy (nullify) the chain of loggers references, also closing resources when needed.
  76       *
  77       * @since Moodle 3.1
  78       */
  79      public final function destroy() {
  80          // Recursively destroy the chain.
  81          if ($this->next !== null) {
  82              $this->next->destroy();
  83              $this->next = null;
  84          }
  85          // And close every logger.
  86          $this->close();
  87      }
  88  
  89      /**
  90       * Close any resource the logger may have open.
  91       *
  92       * @since Moodle 3.1
  93       */
  94      public function close() {
  95          // Nothing to do by default. Only loggers using resources (files, own connections...) need to override this.
  96      }
  97  
  98  // checksumable interface methods
  99  
 100      public function calculate_checksum() {
 101          // Checksum is a simple md5 hash of classname, level and
 102          // on each specialised logger, its own atrributes
 103          // Not following the chain at all.
 104          return md5(get_class($this) . '-' . $this->level);
 105      }
 106  
 107      public function is_checksum_correct($checksum) {
 108          return $this->calculate_checksum() === $checksum;
 109      }
 110  
 111  // Protected API starts here
 112  
 113      abstract protected function action($message, $level, $options = null); // To implement
 114  
 115      public final function process($message, $level, $options = null) {
 116          $result = true;
 117          if ($this->level != backup::LOG_NONE && $this->level >= $level
 118              && !(defined('BEHAT_TEST') && BEHAT_TEST)) { // Perform action conditionally.
 119              $result = $this->action($message, $level, $options);
 120          }
 121          if ($result === false) { // Something was wrong, stop the chain
 122              return $result;
 123          }
 124          if ($this->next !== null) { // The chain continues being processed
 125              $result = $this->next->process($message, $level, $options);
 126          }
 127          return $result;
 128      }
 129  
 130      protected function is_circular_reference($obj) {
 131          // Get object all nexts recursively and check if $this is already there
 132          $nexts = $obj->get_nexts();
 133          if (array_key_exists($this->calculate_checksum(), $nexts) || $obj == $this) {
 134              return true;
 135          }
 136          return false;
 137      }
 138  
 139      protected function get_nexts() {
 140          $nexts = array();
 141          if ($this->next !== null) {
 142              $nexts[$this->next->calculate_checksum()] = $this->next->calculate_checksum();
 143              $nexts = array_merge($nexts, $this->next->get_nexts());
 144          }
 145          return $nexts;
 146      }
 147  
 148      protected function get_datestr() {
 149          return userdate(time(), '%c');
 150      }
 151  
 152      protected function get_levelstr($level) {
 153          $result = 'undefined';
 154          switch ($level) {
 155              case backup::LOG_ERROR:
 156                  $result = 'error';
 157                  break;
 158              case backup::LOG_WARNING:
 159                  $result = 'warn';
 160                  break;
 161              case backup::LOG_INFO:
 162                  $result = 'info';
 163                  break;
 164              case backup::LOG_DEBUG:
 165                  $result = 'debug';
 166                  break;
 167          }
 168          return $result;
 169      }
 170  
 171      protected function get_prefix($level, $options) {
 172          $prefix = '';
 173          if ($this->showdate) {
 174              $prefix .= '[' . $this->get_datestr() . '] ';
 175          }
 176          if ($this->showlevel) {
 177              $prefix .= '[' . $this->get_levelstr($level) . '] ';
 178          }
 179          return $prefix;
 180      }
 181  }
 182  
 183  /*
 184   * Exception class used by all the @base_logger stuff
 185   */
 186  class base_logger_exception extends backup_exception {
 187  
 188      public function __construct($errorcode, $a=NULL, $debuginfo=null) {
 189          parent::__construct($errorcode, $a, $debuginfo);
 190      }
 191  }