Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 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   * This file contains classes that are used by the Cache API only when it is disabled.
  19   *
  20   * These classes are derivatives of other significant classes used by the Cache API customised specifically
  21   * to only do what is absolutely necessary when initialising and using the Cache API when its been disabled.
  22   *
  23   * @package    core
  24   * @category   cache
  25   * @copyright  2012 Sam Hemelryk
  26   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27   */
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  /**
  32   * Required as it is needed for cache_config_disabled which extends cache_config_writer.
  33   */
  34  require_once($CFG->dirroot.'/cache/locallib.php');
  35  
  36  /**
  37   * The cache loader class used when the Cache has been disabled.
  38   *
  39   * @copyright  2012 Sam Hemelryk
  40   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   */
  42  class cache_disabled extends cache implements cache_loader_with_locking {
  43  
  44      /**
  45       * Constructs the cache.
  46       *
  47       * @param cache_definition $definition
  48       * @param cache_store $store
  49       * @param null $loader Unused.
  50       */
  51      public function __construct(cache_definition $definition, cache_store $store, $loader = null) {
  52          if ($loader instanceof cache_data_source) {
  53              // Set the data source to allow data sources to work when caching is entirely disabled.
  54              $this->set_data_source($loader);
  55          }
  56  
  57          // No other features are handled.
  58      }
  59  
  60      /**
  61       * Gets a key from the cache.
  62       *
  63       * @param int|string $key
  64       * @param int $requiredversion Minimum required version of the data or cache::VERSION_NONE
  65       * @param int $strictness Unused.
  66       * @param mixed &$actualversion If specified, will be set to the actual version number retrieved
  67       * @return bool
  68       */
  69      protected function get_implementation($key, int $requiredversion, int $strictness, &$actualversion = null) {
  70          $datasource = $this->get_datasource();
  71          if ($datasource !== false) {
  72              if ($requiredversion === cache::VERSION_NONE) {
  73                  return $datasource->load_for_cache($key);
  74              } else {
  75                  if (!$datasource instanceof cache_data_source_versionable) {
  76                      throw new \coding_exception('Data source is not versionable');
  77                  }
  78                  $result = $datasource->load_for_cache_versioned($key, $requiredversion, $actualversion);
  79                  if ($result && $actualversion < $requiredversion) {
  80                      throw new \coding_exception('Data source returned outdated version');
  81                  }
  82                  return $result;
  83              }
  84          }
  85          return false;
  86      }
  87  
  88      /**
  89       * Gets many keys at once from the cache.
  90       *
  91       * @param array $keys
  92       * @param int $strictness Unused.
  93       * @return array
  94       */
  95      public function get_many(array $keys, $strictness = IGNORE_MISSING) {
  96          if ($this->get_datasource() !== false) {
  97              return $this->get_datasource()->load_many_for_cache($keys);
  98          }
  99  
 100          return array_combine($keys, array_fill(0, count($keys), false));
 101      }
 102  
 103      /**
 104       * Sets a key value pair in the cache.
 105       *
 106       * @param int|string $key Unused.
 107       * @param int $version Unused.
 108       * @param mixed $data Unused.
 109       * @param bool $setparents Unused.
 110       * @return bool
 111       */
 112      protected function set_implementation($key, int $version, $data, bool $setparents = true): bool {
 113          return false;
 114      }
 115  
 116      /**
 117       * Sets many key value pairs in the cache at once.
 118       *
 119       * @param array $keyvaluearray Unused.
 120       * @return int
 121       */
 122      public function set_many(array $keyvaluearray) {
 123          return 0;
 124      }
 125  
 126      /**
 127       * Deletes an item from the cache.
 128       *
 129       * @param int|string $key Unused.
 130       * @param bool $recurse Unused.
 131       * @return bool
 132       */
 133      public function delete($key, $recurse = true) {
 134          return false;
 135      }
 136  
 137      /**
 138       * Deletes many items at once from the cache.
 139       *
 140       * @param array $keys Unused.
 141       * @param bool $recurse Unused.
 142       * @return int
 143       */
 144      public function delete_many(array $keys, $recurse = true) {
 145          return 0;
 146      }
 147  
 148      /**
 149       * Checks if the cache has the requested key.
 150       *
 151       * @param int|string $key Unused.
 152       * @param bool $tryloadifpossible Unused.
 153       * @return bool
 154       */
 155      public function has($key, $tryloadifpossible = false) {
 156          $result = $this->get($key);
 157  
 158          return $result !== false;
 159      }
 160  
 161      /**
 162       * Checks if the cache has all of the requested keys.
 163       * @param array $keys Unused.
 164       * @return bool
 165       */
 166      public function has_all(array $keys) {
 167          if (!$this->get_datasource()) {
 168              return false;
 169          }
 170  
 171          foreach ($keys as $key) {
 172              if (!$this->has($key)) {
 173                  return false;
 174              }
 175          }
 176          return true;
 177      }
 178  
 179      /**
 180       * Checks if the cache has any of the requested keys.
 181       *
 182       * @param array $keys Unused.
 183       * @return bool
 184       */
 185      public function has_any(array $keys) {
 186          foreach ($keys as $key) {
 187              if ($this->has($key)) {
 188                  return true;
 189              }
 190          }
 191  
 192          return false;
 193      }
 194  
 195      /**
 196       * Purges all items from the cache.
 197       *
 198       * @return bool
 199       */
 200      public function purge() {
 201          return true;
 202      }
 203  
 204      /**
 205       * Pretend that we got a lock to avoid errors.
 206       *
 207       * @param int|string $key
 208       * @return bool
 209       */
 210      public function acquire_lock($key) : bool {
 211          return true;
 212      }
 213  
 214      /**
 215       * Pretend that we released a lock to avoid errors.
 216       *
 217       * @param int|string $key
 218       * @return bool
 219       */
 220      public function release_lock($key) : bool {
 221          return true;
 222      }
 223  
 224      /**
 225       * Pretend that we have a lock to avoid errors.
 226       *
 227       * @param int|string $key
 228       * @return bool
 229       */
 230      public function check_lock_state($key) : bool {
 231          return true;
 232      }
 233  }
 234  
 235  /**
 236   * The cache factory class used when the Cache has been disabled.
 237   *
 238   * @copyright  2012 Sam Hemelryk
 239   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 240   */
 241  class cache_factory_disabled extends cache_factory {
 242      /** @var array Array of temporary caches in use. */
 243      protected static $tempcaches = [];
 244  
 245      /**
 246       * Returns an instance of the cache_factor method.
 247       *
 248       * @param bool $forcereload Unused.
 249       * @return cache_factory
 250       * @throws coding_exception
 251       */
 252      public static function instance($forcereload = false) {
 253          throw new coding_exception('You must not call to this cache factory within your code.');
 254      }
 255  
 256      /**
 257       * Creates a definition instance or returns the existing one if it has already been created.
 258       *
 259       * @param string $component
 260       * @param string $area
 261       * @param string $unused Used to be datasourceaggregate but that was removed and this is now unused.
 262       * @return cache_definition
 263       */
 264      public function create_definition($component, $area, $unused = null) {
 265          $definition = parent::create_definition($component, $area);
 266          if ($definition->has_data_source()) {
 267              return $definition;
 268          }
 269  
 270          return cache_definition::load_adhoc(cache_store::MODE_REQUEST, $component, $area);
 271      }
 272  
 273      /**
 274       * Common public method to create a cache instance given a definition.
 275       *
 276       * @param cache_definition $definition
 277       * @return cache_application|cache_session|cache_store
 278       * @throws coding_exception
 279       */
 280      public function create_cache(cache_definition $definition) {
 281          $loader = null;
 282          if ($definition->has_data_source()) {
 283              $loader = $definition->get_data_source();
 284          }
 285          return new cache_disabled($definition, $this->create_dummy_store($definition), $loader);
 286      }
 287  
 288      /**
 289       * Creates a cache object given the parameters for a definition.
 290       *
 291       * @param string $component
 292       * @param string $area
 293       * @param array $identifiers
 294       * @param string $unused Used to be datasourceaggregate but that was removed and this is now unused.
 295       * @return cache_application|cache_session|cache_request
 296       */
 297      public function create_cache_from_definition($component, $area, array $identifiers = array(), $unused = null) {
 298          // Temporary in-memory caches are sometimes allowed when caching is disabled.
 299          if (\core_cache\allow_temporary_caches::is_allowed() && !$identifiers) {
 300              $key = $component . '/' . $area;
 301              if (array_key_exists($key, self::$tempcaches)) {
 302                  $cache = self::$tempcaches[$key];
 303              } else {
 304                  $definition = $this->create_definition($component, $area);
 305                  // The cachestore_static class returns true to all three 'SUPPORTS_' checks so it
 306                  // can be used with all definitions.
 307                  $store = new cachestore_static('TEMP:' . $component . '/' . $area);
 308                  $store->initialise($definition);
 309                  // We need to use a cache loader wrapper rather than directly returning the store,
 310                  // or it wouldn't have support for versioning. The cache_application class is used
 311                  // (rather than cache_request which might make more sense logically) because it
 312                  // includes support for locking, which might be necessary for some caches.
 313                  $cache = new cache_application($definition, $store);
 314                  self::$tempcaches[$key] = $cache;
 315              }
 316              return $cache;
 317          }
 318  
 319          // Regular cache definitions are cached inside create_definition().  This is not the case for disabledlib.php
 320          // definitions as they use load_adhoc().  They are built as a new object on each call.
 321          // We do not need to clone the definition because we know it's new.
 322          $definition = $this->create_definition($component, $area);
 323          $definition->set_identifiers($identifiers);
 324          $cache = $this->create_cache($definition);
 325          return $cache;
 326      }
 327  
 328      /**
 329       * Removes all temporary caches.
 330       *
 331       * Don't call this directly - used by {@see \core_cache\allow_temporary_caches}.
 332       */
 333      public static function clear_temporary_caches(): void {
 334          self::$tempcaches = [];
 335      }
 336  
 337      /**
 338       * Creates an ad-hoc cache from the given param.
 339       *
 340       * @param int $mode
 341       * @param string $component
 342       * @param string $area
 343       * @param array $identifiers
 344       * @param array $options An array of options, available options are:
 345       *   - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
 346       *   - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
 347       *   - staticacceleration : If set to true the cache will hold onto all data passing through it.
 348       *   - staticaccelerationsize : Sets the max size of the static acceleration array.
 349       * @return cache_application|cache_session|cache_request
 350       */
 351      public function create_cache_from_params($mode, $component, $area, array $identifiers = array(), array $options = array()) {
 352          // Regular cache definitions are cached inside create_definition().  This is not the case for disabledlib.php
 353          // definitions as they use load_adhoc().  They are built as a new object on each call.
 354          // We do not need to clone the definition because we know it's new.
 355          $definition = cache_definition::load_adhoc($mode, $component, $area, $options);
 356          $definition->set_identifiers($identifiers);
 357          $cache = $this->create_cache($definition);
 358          return $cache;
 359      }
 360  
 361      /**
 362       * Creates a store instance given its name and configuration.
 363       *
 364       * @param string $name Unused.
 365       * @param array $details Unused.
 366       * @param cache_definition $definition
 367       * @return boolean|cache_store
 368       */
 369      public function create_store_from_config($name, array $details, cache_definition $definition) {
 370          return $this->create_dummy_store($definition);
 371      }
 372  
 373      /**
 374       * Creates a cache config instance with the ability to write if required.
 375       *
 376       * @param bool $writer Unused.
 377       * @return cache_config_disabled|cache_config_writer
 378       */
 379      public function create_config_instance($writer = false) {
 380          // We are always going to use the cache_config_disabled class for all regular request.
 381          // However if the code has requested the writer then likely something is changing and
 382          // we're going to need to interact with the config.php file.
 383          // In this case we will still use the cache_config_writer.
 384          $class = 'cache_config_disabled';
 385          if ($writer) {
 386              // If the writer was requested then something is changing.
 387              $class = 'cache_config_writer';
 388          }
 389          if (!array_key_exists($class, $this->configs)) {
 390              self::set_state(self::STATE_INITIALISING);
 391              if ($class === 'cache_config_disabled') {
 392                  $configuration = $class::create_default_configuration();
 393                  $this->configs[$class] = new $class;
 394              } else {
 395                  $configuration = false;
 396                  // If we need a writer, we should get the classname from the generic factory.
 397                  // This is so alternative classes can be used if a different writer is required.
 398                  $this->configs[$class] = parent::get_disabled_writer();
 399              }
 400              $this->configs[$class]->load($configuration);
 401          }
 402          self::set_state(self::STATE_READY);
 403  
 404          // Return the instance.
 405          return $this->configs[$class];
 406      }
 407  
 408      /**
 409       * Returns true if the cache API has been disabled.
 410       *
 411       * @return bool
 412       */
 413      public function is_disabled() {
 414          return true;
 415      }
 416  }
 417  
 418  /**
 419   * The cache config class used when the Cache has been disabled.
 420   *
 421   * @copyright  2012 Sam Hemelryk
 422   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 423   */
 424  class cache_config_disabled extends cache_config_writer {
 425  
 426      /**
 427       * Returns an instance of the configuration writer.
 428       *
 429       * @return cache_config_disabled
 430       */
 431      public static function instance() {
 432          $factory = cache_factory::instance();
 433          return $factory->create_config_instance(true);
 434      }
 435  
 436      /**
 437       * Saves the current configuration.
 438       */
 439      protected function config_save() {
 440          // Nothing to do here.
 441      }
 442  
 443      /**
 444       * Generates a configuration array suitable to be written to the config file.
 445       *
 446       * @return array
 447       */
 448      protected function generate_configuration_array() {
 449          $configuration = array();
 450          $configuration['stores'] = $this->configstores;
 451          $configuration['modemappings'] = $this->configmodemappings;
 452          $configuration['definitions'] = $this->configdefinitions;
 453          $configuration['definitionmappings'] = $this->configdefinitionmappings;
 454          $configuration['locks'] = $this->configlocks;
 455          return $configuration;
 456      }
 457  
 458      /**
 459       * Adds a plugin instance.
 460       *
 461       * @param string $name Unused.
 462       * @param string $plugin Unused.
 463       * @param array $configuration Unused.
 464       * @return bool
 465       * @throws cache_exception
 466       */
 467      public function add_store_instance($name, $plugin, array $configuration = array()) {
 468          return false;
 469      }
 470  
 471      /**
 472       * Sets the mode mappings.
 473       *
 474       * @param array $modemappings Unused.
 475       * @return bool
 476       * @throws cache_exception
 477       */
 478      public function set_mode_mappings(array $modemappings) {
 479          return false;
 480      }
 481  
 482      /**
 483       * Edits a give plugin instance.
 484       *
 485       * @param string $name Unused.
 486       * @param string $plugin Unused.
 487       * @param array $configuration Unused.
 488       * @return bool
 489       * @throws cache_exception
 490       */
 491      public function edit_store_instance($name, $plugin, $configuration) {
 492          return false;
 493      }
 494  
 495      /**
 496       * Deletes a store instance.
 497       *
 498       * @param string $name Unused.
 499       * @return bool
 500       * @throws cache_exception
 501       */
 502      public function delete_store_instance($name) {
 503          return false;
 504      }
 505  
 506      /**
 507       * Creates the default configuration and saves it.
 508       *
 509       * @param bool $forcesave Ignored because we are disabled!
 510       * @return array
 511       */
 512      public static function create_default_configuration($forcesave = false) {
 513          global $CFG;
 514  
 515          // HACK ALERT.
 516          // We probably need to come up with a better way to create the default stores, or at least ensure 100% that the
 517          // default store plugins are protected from deletion.
 518          require_once($CFG->dirroot.'/cache/stores/file/lib.php');
 519          require_once($CFG->dirroot.'/cache/stores/session/lib.php');
 520          require_once($CFG->dirroot.'/cache/stores/static/lib.php');
 521  
 522          $writer = new self;
 523          $writer->configstores = array(
 524              'default_application' => array(
 525                  'name' => 'default_application',
 526                  'plugin' => 'file',
 527                  'configuration' => array(),
 528                  'features' => cachestore_file::get_supported_features(),
 529                  'modes' => cache_store::MODE_APPLICATION,
 530                  'default' => true,
 531              ),
 532              'default_session' => array(
 533                  'name' => 'default_session',
 534                  'plugin' => 'session',
 535                  'configuration' => array(),
 536                  'features' => cachestore_session::get_supported_features(),
 537                  'modes' => cache_store::MODE_SESSION,
 538                  'default' => true,
 539              ),
 540              'default_request' => array(
 541                  'name' => 'default_request',
 542                  'plugin' => 'static',
 543                  'configuration' => array(),
 544                  'features' => cachestore_static::get_supported_features(),
 545                  'modes' => cache_store::MODE_REQUEST,
 546                  'default' => true,
 547              )
 548          );
 549          $writer->configdefinitions = array();
 550          $writer->configmodemappings = array(
 551              array(
 552                  'mode' => cache_store::MODE_APPLICATION,
 553                  'store' => 'default_application',
 554                  'sort' => -1
 555              ),
 556              array(
 557                  'mode' => cache_store::MODE_SESSION,
 558                  'store' => 'default_session',
 559                  'sort' => -1
 560              ),
 561              array(
 562                  'mode' => cache_store::MODE_REQUEST,
 563                  'store' => 'default_request',
 564                  'sort' => -1
 565              )
 566          );
 567          $writer->configlocks = array(
 568              'default_file_lock' => array(
 569                  'name' => 'cachelock_file_default',
 570                  'type' => 'cachelock_file',
 571                  'dir' => 'filelocks',
 572                  'default' => true
 573              )
 574          );
 575  
 576          return $writer->generate_configuration_array();
 577      }
 578  
 579      /**
 580       * Updates the definition in the configuration from those found in the cache files.
 581       *
 582       * @param bool $coreonly Unused.
 583       */
 584      public static function update_definitions($coreonly = false) {
 585          // Nothing to do here.
 586      }
 587  
 588      /**
 589       * Locates all of the definition files.
 590       *
 591       * @param bool $coreonly Unused.
 592       * @return array
 593       */
 594      protected static function locate_definitions($coreonly = false) {
 595          return array();
 596      }
 597  
 598      /**
 599       * Sets the mappings for a given definition.
 600       *
 601       * @param string $definition Unused.
 602       * @param array $mappings Unused.
 603       * @throws coding_exception
 604       */
 605      public function set_definition_mappings($definition, $mappings) {
 606          // Nothing to do here.
 607      }
 608  }