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  namespace Psr\Log\Test;
   4  
   5  use Psr\Log\AbstractLogger;
   6  
   7  /**
   8   * Used for testing purposes.
   9   *
  10   * It records all records and gives you access to them for verification.
  11   *
  12   * @method bool hasEmergency($record)
  13   * @method bool hasAlert($record)
  14   * @method bool hasCritical($record)
  15   * @method bool hasError($record)
  16   * @method bool hasWarning($record)
  17   * @method bool hasNotice($record)
  18   * @method bool hasInfo($record)
  19   * @method bool hasDebug($record)
  20   *
  21   * @method bool hasEmergencyRecords()
  22   * @method bool hasAlertRecords()
  23   * @method bool hasCriticalRecords()
  24   * @method bool hasErrorRecords()
  25   * @method bool hasWarningRecords()
  26   * @method bool hasNoticeRecords()
  27   * @method bool hasInfoRecords()
  28   * @method bool hasDebugRecords()
  29   *
  30   * @method bool hasEmergencyThatContains($message)
  31   * @method bool hasAlertThatContains($message)
  32   * @method bool hasCriticalThatContains($message)
  33   * @method bool hasErrorThatContains($message)
  34   * @method bool hasWarningThatContains($message)
  35   * @method bool hasNoticeThatContains($message)
  36   * @method bool hasInfoThatContains($message)
  37   * @method bool hasDebugThatContains($message)
  38   *
  39   * @method bool hasEmergencyThatMatches($message)
  40   * @method bool hasAlertThatMatches($message)
  41   * @method bool hasCriticalThatMatches($message)
  42   * @method bool hasErrorThatMatches($message)
  43   * @method bool hasWarningThatMatches($message)
  44   * @method bool hasNoticeThatMatches($message)
  45   * @method bool hasInfoThatMatches($message)
  46   * @method bool hasDebugThatMatches($message)
  47   *
  48   * @method bool hasEmergencyThatPasses($message)
  49   * @method bool hasAlertThatPasses($message)
  50   * @method bool hasCriticalThatPasses($message)
  51   * @method bool hasErrorThatPasses($message)
  52   * @method bool hasWarningThatPasses($message)
  53   * @method bool hasNoticeThatPasses($message)
  54   * @method bool hasInfoThatPasses($message)
  55   * @method bool hasDebugThatPasses($message)
  56   */
  57  class TestLogger extends AbstractLogger
  58  {
  59      /**
  60       * @var array
  61       */
  62      public $records = [];
  63  
  64      public $recordsByLevel = [];
  65  
  66      /**
  67       * @inheritdoc
  68       */
  69      public function log($level, $message, array $context = [])
  70      {
  71          $record = [
  72              'level' => $level,
  73              'message' => $message,
  74              'context' => $context,
  75          ];
  76  
  77          $this->recordsByLevel[$record['level']][] = $record;
  78          $this->records[] = $record;
  79      }
  80  
  81      public function hasRecords($level)
  82      {
  83          return isset($this->recordsByLevel[$level]);
  84      }
  85  
  86      public function hasRecord($record, $level)
  87      {
  88          if (is_string($record)) {
  89              $record = ['message' => $record];
  90          }
  91          return $this->hasRecordThatPasses(function ($rec) use ($record) {
  92              if ($rec['message'] !== $record['message']) {
  93                  return false;
  94              }
  95              if (isset($record['context']) && $rec['context'] !== $record['context']) {
  96                  return false;
  97              }
  98              return true;
  99          }, $level);
 100      }
 101  
 102      public function hasRecordThatContains($message, $level)
 103      {
 104          return $this->hasRecordThatPasses(function ($rec) use ($message) {
 105              return strpos($rec['message'], $message) !== false;
 106          }, $level);
 107      }
 108  
 109      public function hasRecordThatMatches($regex, $level)
 110      {
 111          return $this->hasRecordThatPasses(function ($rec) use ($regex) {
 112              return preg_match($regex, $rec['message']) > 0;
 113          }, $level);
 114      }
 115  
 116      public function hasRecordThatPasses(callable $predicate, $level)
 117      {
 118          if (!isset($this->recordsByLevel[$level])) {
 119              return false;
 120          }
 121          foreach ($this->recordsByLevel[$level] as $i => $rec) {
 122              if (call_user_func($predicate, $rec, $i)) {
 123                  return true;
 124              }
 125          }
 126          return false;
 127      }
 128  
 129      public function __call($method, $args)
 130      {
 131          if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) {
 132              $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3];
 133              $level = strtolower($matches[2]);
 134              if (method_exists($this, $genericMethod)) {
 135                  $args[] = $level;
 136                  return call_user_func_array([$this, $genericMethod], $args);
 137              }
 138          }
 139          throw new \BadMethodCallException('Call to undefined method ' . get_class($this) . '::' . $method . '()');
 140      }
 141  
 142      public function reset()
 143      {
 144          $this->records = [];
 145          $this->recordsByLevel = [];
 146      }
 147  }