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] [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   * Cache definition class
  19   *
  20   * This file is part of Moodle's cache API, affectionately called MUC.
  21   * It contains the components that are requried in order to use caching.
  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   * The cache definition class.
  33   *
  34   * Cache definitions need to be defined in db/caches.php files.
  35   * They can be constructed with the following options.
  36   *
  37   * Required settings:
  38   *     + mode
  39   *          [int] Sets the mode for the definition. Must be one of cache_store::MODE_*
  40   *
  41   * Optional settings:
  42   *     + simplekeys
  43   *          [bool] Set to true if your cache will only use simple keys for its items.
  44   *          Simple keys consist of digits, underscores and the 26 chars of the english language. a-zA-Z0-9_
  45   *          If true the keys won't be hashed before being passed to the cache store for gets/sets/deletes. It will be
  46   *          better for performance and possible only becase we know the keys are safe.
  47   *     + simpledata
  48   *          [bool] If set to true we know that the data is scalar or array of scalar.
  49   *     + requireidentifiers
  50   *          [array] An array of identifiers that must be provided to the cache when it is created.
  51   *     + requiredataguarantee
  52   *          [bool] If set to true then only stores that can guarantee data will remain available once set will be used.
  53   *     + requiremultipleidentifiers
  54   *          [bool] If set to true then only stores that support multiple identifiers will be used.
  55   *     + requirelockingread
  56   *          [bool] If set to true then a lock will be gained before reading from the cache store. It is recommended not to use
  57   *          this setting unless 100% absolutely positively required. Remember 99.9% of caches will NOT need this setting.
  58   *          This setting will only be used for application caches presently.
  59   *     + requirelockingwrite
  60   *          [bool] If set to true then a lock will be gained before writing to the cache store. As above this is not recommended
  61   *          unless truly needed. Please think about the order of your code and deal with race conditions there first.
  62   *          This setting will only be used for application caches presently.
  63   *     + maxsize
  64   *          [int] If set this will be used as the maximum number of entries within the cache store for this definition.
  65   *          Its important to note that cache stores don't actually have to acknowledge this setting or maintain it as a hard limit.
  66   *     + overrideclass
  67   *          [string] A class to use as the loader for this cache. This is an advanced setting and will allow the developer of the
  68   *          definition to take 100% control of the caching solution.
  69   *          Any class used here must inherit the cache_loader interface and must extend default cache loader for the mode they are
  70   *          using.
  71   *     + overrideclassfile
  72   *          [string] Suplements the above setting indicated the file containing the class to be used. This file is included when
  73   *          required.
  74   *     + datasource
  75   *          [string] A class to use as the data loader for this definition.
  76   *          Any class used here must inherit the cache_data_loader interface.
  77   *     + datasourcefile
  78   *          [string] Supplements the above setting indicating the file containing the class to be used. This file is included when
  79   *          required.
  80   *     + staticacceleration
  81   *          The cache loader will keep an array of the items set and retrieved to the cache during the request.
  82   *          Consider using this setting when you know that there are going to be many calls to the cache for the same information.
  83   *          Requests for data in this array will be ultra fast, but it will cost memory.
  84   *     + staticaccelerationsize
  85   *          [int] This supplements the above setting by limiting the number of items in the static acceleration array.
  86   *          Tweaking this setting lower will allow you to minimise the memory implications above while hopefully still managing to
  87   *          offset calls to the cache store.
  88   *     + ttl
  89   *          [int] A time to live for the data (in seconds). It is strongly recommended that you don't make use of this and
  90   *          instead try to create an event driven invalidation system.
  91   *          Not all cache stores will support this natively and there are undesired performance impacts if the cache store does not.
  92   *     + mappingsonly
  93   *          [bool] If set to true only the mapped cache store(s) will be used and the default mode store will not. This is a super
  94   *          advanced setting and should not be used unless absolutely required. It allows you to avoid the default stores for one
  95   *          reason or another.
  96   *     + invalidationevents
  97   *          [array] An array of events that should cause this cache to invalidate some or all of the items within it.
  98   *     + sharingoptions
  99   *          [int] The sharing options that are appropriate for this definition. Should be the sum of the possible options.
 100   *     + defaultsharing
 101   *          [int] The default sharing option to use. It's highly recommended that you don't set this unless there is a very
 102   *          specific reason not to use the system default.
 103   *     + canuselocalstore
 104   *          [bool] The cache is able to safely run with multiple copies on different webservers without any need for administrator
 105   *                 intervention to ensure that data stays in sync across nodes.  This is usually managed by a revision
 106   *                 system as seen in modinfo cache or language cache.  Requiring purge on upgrade is not sufficient as
 107   *                 it requires administrator intervention on each node to make it work.
 108   *
 109   * For examples take a look at lib/db/caches.php
 110   *
 111   * @package    core
 112   * @category   cache
 113   * @copyright  2012 Sam Hemelryk
 114   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 115   */
 116  class cache_definition {
 117  
 118      /** The cache can be shared with everyone */
 119      const SHARING_ALL = 1;
 120      /** The cache can be shared with other sites using the same siteid. */
 121      const SHARING_SITEID = 2;
 122      /** The cache can be shared with other sites of the same version. */
 123      const SHARING_VERSION = 4;
 124      /** The cache can be shared with other sites using the same key */
 125      const SHARING_INPUT = 8;
 126  
 127      /**
 128       * The default sharing options available.
 129       * All + SiteID + Version + Input.
 130       */
 131      const SHARING_DEFAULTOPTIONS = 15;
 132      /**
 133       * The default sharing option that gets used if none have been selected.
 134       * SiteID. It is the most restrictive.
 135       */
 136      const SHARING_DEFAULT = 2;
 137  
 138      /**
 139       * The identifier for the definition
 140       * @var string
 141       */
 142      protected $id;
 143  
 144      /**
 145       * The mode for the defintion. One of cache_store::MODE_*
 146       * @var int
 147       */
 148      protected $mode;
 149  
 150      /**
 151       * The component this definition is associated with.
 152       * @var string
 153       */
 154      protected $component;
 155  
 156      /**
 157       * The area this definition is associated with.
 158       * @var string
 159       */
 160      protected $area;
 161  
 162      /**
 163       * If set to true we know the keys are simple. a-zA-Z0-9_
 164       * @var bool
 165       */
 166      protected $simplekeys = false;
 167  
 168      /**
 169       * Set to true if we know the data is scalar or array of scalar.
 170       * @var bool
 171       */
 172      protected $simpledata = false;
 173  
 174      /**
 175       * An array of identifiers that must be provided when the definition is used to create a cache.
 176       * @var array
 177       */
 178      protected $requireidentifiers = array();
 179  
 180      /**
 181       * If set to true then only stores that guarantee data may be used with this definition.
 182       * @var bool
 183       */
 184      protected $requiredataguarantee = false;
 185  
 186      /**
 187       * If set to true then only stores that support multple identifiers may be used with this definition.
 188       * @var bool
 189       */
 190      protected $requiremultipleidentifiers = false;
 191  
 192      /**
 193       * If set to true then we know that this definition requires the locking functionality.
 194       * This gets set during construction based upon the settings requirelockingread and requirelockingwrite.
 195       * @var bool
 196       */
 197      protected $requirelocking = false;
 198  
 199      /**
 200       * Set to true if this definition requires read locking.
 201       * @var bool
 202       */
 203      protected $requirelockingread = false;
 204  
 205      /**
 206       * Gets set to true if this definition requires write locking.
 207       * @var bool
 208       */
 209      protected $requirelockingwrite = false;
 210  
 211      /**
 212       * Gets set to true if this definition requires a lock to be acquired before a write is attempted.
 213       * @var bool
 214       */
 215      protected $requirelockingbeforewrite = false;
 216  
 217      /**
 218       * Gets set to true if this definition requires searchable stores.
 219       * @since Moodle 2.4.4
 220       * @var bool
 221       */
 222      protected $requiresearchable = false;
 223  
 224      /**
 225       * Sets the maximum number of items that can exist in the cache.
 226       * Please note this isn't a hard limit, and doesn't need to be enforced by the caches. They can choose to do so optionally.
 227       * @var int
 228       */
 229      protected $maxsize = null;
 230  
 231      /**
 232       * The class to use as the cache loader for this definition.
 233       * @var string
 234       */
 235      protected $overrideclass = null;
 236  
 237      /**
 238       * The file in which the override class exists. This will be included if required.
 239       * @var string Absolute path
 240       */
 241      protected $overrideclassfile = null;
 242  
 243      /**
 244       * The data source class to use with this definition.
 245       * @var string
 246       */
 247      protected $datasource = null;
 248  
 249      /**
 250       * The file in which the data source class exists. This will be included if required.
 251       * @var string
 252       */
 253      protected $datasourcefile = null;
 254  
 255      /**
 256       * Set to true if the cache should hold onto items passing through it to speed up subsequent requests.
 257       * @var bool
 258       */
 259      protected $staticacceleration = false;
 260  
 261      /**
 262       * The maximum number of items that static acceleration cache should hold onto.
 263       * @var int
 264       */
 265      protected $staticaccelerationsize = false;
 266  
 267      /**
 268       * The TTL for data in this cache. Please don't use this, instead use event driven invalidation.
 269       * @var int
 270       */
 271      protected $ttl = 0;
 272  
 273      /**
 274       * Set to true if this cache should only use mapped cache stores and not the default mode cache store.
 275       * @var bool
 276       */
 277      protected $mappingsonly = false;
 278  
 279      /**
 280       * An array of events that should cause this cache to invalidate.
 281       * @var array
 282       */
 283      protected $invalidationevents = array();
 284  
 285      /**
 286       * An array of identifiers provided to this cache when it was initialised.
 287       * @var array
 288       */
 289      protected $identifiers = null;
 290  
 291      /**
 292       * Key prefix for use with single key cache stores
 293       * @var string
 294       */
 295      protected $keyprefixsingle = null;
 296  
 297      /**
 298       * Key prefix to use with cache stores that support multi keys.
 299       * @var array
 300       */
 301      protected $keyprefixmulti = null;
 302  
 303      /**
 304       * A hash identifier of this definition.
 305       * @var string
 306       */
 307      protected $definitionhash = null;
 308  
 309      /**
 310       * The selected sharing mode for this definition.
 311       * @var int
 312       */
 313      protected $sharingoptions;
 314  
 315      /**
 316       * Whether this cache supports local storages.
 317       * @var bool
 318       */
 319      protected $canuselocalstore = false;
 320  
 321      /**
 322       * The selected sharing option.
 323       * @var int One of self::SHARING_*
 324       */
 325      protected $selectedsharingoption = self::SHARING_DEFAULT;
 326  
 327      /**
 328       * The user input key to use if the SHARING_INPUT option has been selected.
 329       * @var string Must be ALPHANUMEXT
 330       */
 331      protected $userinputsharingkey = '';
 332  
 333      /**
 334       * Creates a cache definition given a definition from the cache configuration or from a caches.php file.
 335       *
 336       * @param string $id
 337       * @param array $definition
 338       * @param string $unused Used to be datasourceaggregate but that was removed and this is now unused.
 339       * @return cache_definition
 340       * @throws coding_exception
 341       */
 342      public static function load($id, array $definition, $unused = null) {
 343          global $CFG;
 344  
 345          if (!array_key_exists('mode', $definition)) {
 346              throw new coding_exception('You must provide a mode when creating a cache definition');
 347          }
 348          if (!array_key_exists('component', $definition)) {
 349              throw new coding_exception('You must provide a component when creating a cache definition');
 350          }
 351          if (!array_key_exists('area', $definition)) {
 352              throw new coding_exception('You must provide an area when creating a cache definition');
 353          }
 354          $mode = (int)$definition['mode'];
 355          $component = (string)$definition['component'];
 356          $area = (string)$definition['area'];
 357  
 358          // Set the defaults.
 359          $simplekeys = false;
 360          $simpledata = false;
 361          $requireidentifiers = array();
 362          $requiredataguarantee = false;
 363          $requiremultipleidentifiers = false;
 364          $requirelockingread = false;
 365          $requirelockingwrite = false;
 366          $requirelockingbeforewrite = false;
 367          $requiresearchable = ($mode === cache_store::MODE_SESSION) ? true : false;
 368          $maxsize = null;
 369          $overrideclass = null;
 370          $overrideclassfile = null;
 371          $datasource = null;
 372          $datasourcefile = null;
 373          $staticacceleration = false;
 374          $staticaccelerationsize = false;
 375          $ttl = 0;
 376          $mappingsonly = false;
 377          $invalidationevents = array();
 378          $sharingoptions = self::SHARING_DEFAULT;
 379          $selectedsharingoption = self::SHARING_DEFAULT;
 380          $userinputsharingkey = '';
 381          $canuselocalstore = false;
 382  
 383          if (array_key_exists('simplekeys', $definition)) {
 384              $simplekeys = (bool)$definition['simplekeys'];
 385          }
 386          if (array_key_exists('simpledata', $definition)) {
 387              $simpledata = (bool)$definition['simpledata'];
 388          }
 389          if (array_key_exists('requireidentifiers', $definition)) {
 390              $requireidentifiers = (array)$definition['requireidentifiers'];
 391          }
 392          if (array_key_exists('requiredataguarantee', $definition)) {
 393              $requiredataguarantee = (bool)$definition['requiredataguarantee'];
 394          }
 395          if (array_key_exists('requiremultipleidentifiers', $definition)) {
 396              $requiremultipleidentifiers = (bool)$definition['requiremultipleidentifiers'];
 397          }
 398  
 399          if (array_key_exists('requirelockingread', $definition)) {
 400              $requirelockingread = (bool)$definition['requirelockingread'];
 401          }
 402          if (array_key_exists('requirelockingwrite', $definition)) {
 403              $requirelockingwrite = (bool)$definition['requirelockingwrite'];
 404          }
 405          if (array_key_exists('requirelockingbeforewrite', $definition)) {
 406              $requirelockingbeforewrite = (bool)$definition['requirelockingbeforewrite'];
 407          }
 408          if ($requirelockingbeforewrite && ($requirelockingwrite || $requirelockingread)) {
 409              throw new coding_exception('requirelockingbeforewrite cannot be set with requirelockingread or requirelockingwrite
 410                      in a cache definition, as this will result in conflicting locks.');
 411          }
 412          $requirelocking = $requirelockingwrite || $requirelockingbeforewrite || $requirelockingread;
 413  
 414          if (array_key_exists('requiresearchable', $definition)) {
 415              $requiresearchable = (bool)$definition['requiresearchable'];
 416          }
 417  
 418          if (array_key_exists('maxsize', $definition)) {
 419              $maxsize = (int)$definition['maxsize'];
 420          }
 421  
 422          if (array_key_exists('overrideclass', $definition)) {
 423              $overrideclass = $definition['overrideclass'];
 424          }
 425          if (array_key_exists('overrideclassfile', $definition)) {
 426              $overrideclassfile = $definition['overrideclassfile'];
 427          }
 428  
 429          if (array_key_exists('datasource', $definition)) {
 430              $datasource = $definition['datasource'];
 431          }
 432          if (array_key_exists('datasourcefile', $definition)) {
 433              $datasourcefile = $definition['datasourcefile'];
 434          }
 435  
 436          if (array_key_exists('persistent', $definition)) {
 437              // Ahhh this is the legacy persistent option.
 438              $staticacceleration = (bool)$definition['persistent'];
 439          }
 440          if (array_key_exists('staticacceleration', $definition)) {
 441              $staticacceleration = (bool)$definition['staticacceleration'];
 442          }
 443          if (array_key_exists('persistentmaxsize', $definition)) {
 444              // Ahhh this is the legacy persistentmaxsize option.
 445              $staticaccelerationsize = (int)$definition['persistentmaxsize'];
 446          }
 447          if (array_key_exists('staticaccelerationsize', $definition)) {
 448              $staticaccelerationsize = (int)$definition['staticaccelerationsize'];
 449          }
 450          if (array_key_exists('ttl', $definition)) {
 451              $ttl = (int)$definition['ttl'];
 452          }
 453          if (array_key_exists('mappingsonly', $definition)) {
 454              $mappingsonly = (bool)$definition['mappingsonly'];
 455          }
 456          if (array_key_exists('invalidationevents', $definition)) {
 457              $invalidationevents = (array)$definition['invalidationevents'];
 458          }
 459          if (array_key_exists('sharingoptions', $definition)) {
 460              $sharingoptions = (int)$definition['sharingoptions'];
 461          }
 462          if (array_key_exists('selectedsharingoption', $definition)) {
 463              $selectedsharingoption = (int)$definition['selectedsharingoption'];
 464          } else if (array_key_exists('defaultsharing', $definition)) {
 465              $selectedsharingoption = (int)$definition['defaultsharing'];
 466          } else if ($sharingoptions ^ $selectedsharingoption) {
 467              if ($sharingoptions & self::SHARING_SITEID) {
 468                  $selectedsharingoption = self::SHARING_SITEID;
 469              } else if ($sharingoptions & self::SHARING_VERSION) {
 470                  $selectedsharingoption = self::SHARING_VERSION;
 471              } else {
 472                  $selectedsharingoption = self::SHARING_ALL;
 473              }
 474          }
 475          if (array_key_exists('canuselocalstore', $definition)) {
 476              $canuselocalstore = (bool)$definition['canuselocalstore'];
 477          }
 478  
 479          if (array_key_exists('userinputsharingkey', $definition) && !empty($definition['userinputsharingkey'])) {
 480              $userinputsharingkey = (string)$definition['userinputsharingkey'];
 481          }
 482  
 483          if (!is_null($overrideclass)) {
 484              if (!is_null($overrideclassfile)) {
 485                  if (strpos($overrideclassfile, $CFG->dirroot) !== 0) {
 486                      $overrideclassfile = $CFG->dirroot.'/'.$overrideclassfile;
 487                  }
 488                  if (strpos($overrideclassfile, '../') !== false) {
 489                      throw new coding_exception('No path craziness allowed within override class file path.');
 490                  }
 491                  if (!file_exists($overrideclassfile)) {
 492                      throw new coding_exception('The override class file does not exist.');
 493                  }
 494                  require_once($overrideclassfile);
 495              }
 496              if (!class_exists($overrideclass)) {
 497                  throw new coding_exception('The override class does not exist.');
 498              }
 499  
 500              // Make sure that the provided class extends the default class for the mode.
 501              if (get_parent_class($overrideclass) !== cache_helper::get_class_for_mode($mode)) {
 502                  throw new coding_exception('The override class does not immediately extend the relevant cache class.');
 503              }
 504          }
 505  
 506          if (!is_null($datasource)) {
 507              if (!is_null($datasourcefile)) {
 508                  if (strpos($datasourcefile, $CFG->dirroot) !== 0) {
 509                      $datasourcefile = $CFG->dirroot.'/'.$datasourcefile;
 510                  }
 511                  if (strpos($datasourcefile, '../') !== false) {
 512                      throw new coding_exception('No path craziness allowed within data source file path.');
 513                  }
 514                  if (!file_exists($datasourcefile)) {
 515                      throw new coding_exception('The data source class file does not exist.');
 516                  }
 517                  require_once($datasourcefile);
 518              }
 519              if (!class_exists($datasource)) {
 520                  throw new coding_exception('The data source class does not exist.');
 521              }
 522              if (!array_key_exists('cache_data_source', class_implements($datasource))) {
 523                  throw new coding_exception('Cache data source classes must implement the cache_data_source interface');
 524              }
 525          }
 526  
 527          $cachedefinition = new cache_definition();
 528          $cachedefinition->id = $id;
 529          $cachedefinition->mode = $mode;
 530          $cachedefinition->component = $component;
 531          $cachedefinition->area = $area;
 532          $cachedefinition->simplekeys = $simplekeys;
 533          $cachedefinition->simpledata = $simpledata;
 534          $cachedefinition->requireidentifiers = $requireidentifiers;
 535          $cachedefinition->requiredataguarantee = $requiredataguarantee;
 536          $cachedefinition->requiremultipleidentifiers = $requiremultipleidentifiers;
 537          $cachedefinition->requirelocking = $requirelocking;
 538          $cachedefinition->requirelockingread = $requirelockingread;
 539          $cachedefinition->requirelockingwrite = $requirelockingwrite;
 540          $cachedefinition->requirelockingbeforewrite = $requirelockingbeforewrite;
 541          $cachedefinition->requiresearchable = $requiresearchable;
 542          $cachedefinition->maxsize = $maxsize;
 543          $cachedefinition->overrideclass = $overrideclass;
 544          $cachedefinition->overrideclassfile = $overrideclassfile;
 545          $cachedefinition->datasource = $datasource;
 546          $cachedefinition->datasourcefile = $datasourcefile;
 547          $cachedefinition->staticacceleration = $staticacceleration;
 548          $cachedefinition->staticaccelerationsize = $staticaccelerationsize;
 549          $cachedefinition->ttl = $ttl;
 550          $cachedefinition->mappingsonly = $mappingsonly;
 551          $cachedefinition->invalidationevents = $invalidationevents;
 552          $cachedefinition->sharingoptions = $sharingoptions;
 553          $cachedefinition->selectedsharingoption = $selectedsharingoption;
 554          $cachedefinition->userinputsharingkey = $userinputsharingkey;
 555          $cachedefinition->canuselocalstore = $canuselocalstore;
 556  
 557          return $cachedefinition;
 558      }
 559  
 560      /**
 561       * Creates an ah-hoc cache definition given the required params.
 562       *
 563       * Please note that when using an adhoc definition you cannot set any of the optional params.
 564       * This is because we cannot guarantee consistent access and we don't want to mislead people into thinking that.
 565       *
 566       * @param int $mode One of cache_store::MODE_*
 567       * @param string $component The component this definition relates to.
 568       * @param string $area The area this definition relates to.
 569       * @param array $options An array of options, available options are:
 570       *   - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
 571       *   - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
 572       *   - overrideclass : The class to use as the loader.
 573       *   - staticacceleration : If set to true the cache will hold onto data passing through it.
 574       *   - staticaccelerationsize : Set it to an int to limit the size of the staticacceleration cache.
 575       * @return cache_application|cache_session|cache_request
 576       */
 577      public static function load_adhoc($mode, $component, $area, array $options = array()) {
 578          $id = 'adhoc/'.$component.'_'.$area;
 579          $definition = array(
 580              'mode' => $mode,
 581              'component' => $component,
 582              'area' => $area,
 583          );
 584          if (!empty($options['simplekeys'])) {
 585              $definition['simplekeys'] = $options['simplekeys'];
 586          }
 587          if (!empty($options['simpledata'])) {
 588              $definition['simpledata'] = $options['simpledata'];
 589          }
 590          if (!empty($options['persistent'])) {
 591              // Ahhh this is the legacy persistent option.
 592              $definition['staticacceleration'] = (bool)$options['persistent'];
 593          }
 594          if (!empty($options['staticacceleration'])) {
 595              $definition['staticacceleration'] = (bool)$options['staticacceleration'];
 596          }
 597          if (!empty($options['staticaccelerationsize'])) {
 598              $definition['staticaccelerationsize'] = (int)$options['staticaccelerationsize'];
 599          }
 600          if (!empty($options['overrideclass'])) {
 601              $definition['overrideclass'] = $options['overrideclass'];
 602          }
 603          if (!empty($options['sharingoptions'])) {
 604              $definition['sharingoptions'] = $options['sharingoptions'];
 605          }
 606          return self::load($id, $definition, null);
 607      }
 608  
 609      /**
 610       * Returns the cache loader class that should be used for this definition.
 611       * @return string
 612       */
 613      public function get_cache_class() {
 614          if (!is_null($this->overrideclass)) {
 615              return $this->overrideclass;
 616          }
 617          return cache_helper::get_class_for_mode($this->mode);
 618      }
 619  
 620      /**
 621       * Returns the id of this definition.
 622       * @return string
 623       */
 624      public function get_id() {
 625          return $this->id;
 626      }
 627  
 628      /**
 629       * Returns the name for this definition
 630       * @return string
 631       */
 632      public function get_name() {
 633          $identifier = 'cachedef_'.clean_param($this->area, PARAM_STRINGID);
 634          $component = $this->component;
 635          if ($component === 'core') {
 636              $component = 'cache';
 637          }
 638          return new lang_string($identifier, $component);
 639      }
 640  
 641      /**
 642       * Returns the mode of this definition
 643       * @return int One more cache_store::MODE_
 644       */
 645      public function get_mode() {
 646          return $this->mode;
 647      }
 648  
 649      /**
 650       * Returns the area this definition is associated with.
 651       * @return string
 652       */
 653      public function get_area() {
 654          return $this->area;
 655      }
 656  
 657      /**
 658       * Returns the component this definition is associated with.
 659       * @return string
 660       */
 661      public function get_component() {
 662          return $this->component;
 663      }
 664  
 665      /**
 666       * Returns true if this definition is using simple keys.
 667       *
 668       * Simple keys contain only a-zA-Z0-9_
 669       *
 670       * @return bool
 671       */
 672      public function uses_simple_keys() {
 673          return $this->simplekeys;
 674      }
 675  
 676      /**
 677       * Returns the identifiers that are being used for this definition.
 678       * @return array
 679       */
 680      public function get_identifiers() {
 681          if (!isset($this->identifiers)) {
 682              return array();
 683          }
 684          return $this->identifiers;
 685      }
 686  
 687      /**
 688       * Returns the ttl in seconds for this definition if there is one, or null if not.
 689       * @return int|null
 690       */
 691      public function get_ttl() {
 692          return $this->ttl;
 693      }
 694  
 695      /**
 696       * Returns the maximum number of items allowed in this cache.
 697       * @return int
 698       */
 699      public function get_maxsize() {
 700          return $this->maxsize;
 701      }
 702  
 703      /**
 704       * Returns true if this definition should only be used with mappings.
 705       * @return bool
 706       */
 707      public function is_for_mappings_only() {
 708          return $this->mappingsonly;
 709      }
 710  
 711      /**
 712       * Returns true if the data is known to be scalar or array of scalar.
 713       * @return bool
 714       */
 715      public function uses_simple_data() {
 716          return $this->simpledata;
 717      }
 718  
 719      /**
 720       * Returns true if this definition requires a data guarantee from the cache stores being used.
 721       * @return bool
 722       */
 723      public function require_data_guarantee() {
 724          return $this->requiredataguarantee;
 725      }
 726  
 727      /**
 728       * Returns true if this definition requires that the cache stores support multiple identifiers
 729       * @return bool
 730       */
 731      public function require_multiple_identifiers() {
 732          return $this->requiremultipleidentifiers;
 733      }
 734  
 735      /**
 736       * Returns true if this definition requires locking functionality. Either read or write locking.
 737       * @return bool
 738       */
 739      public function require_locking() {
 740          return $this->requirelocking;
 741      }
 742  
 743      /**
 744       * Returns true if this definition requires read locking.
 745       * @return bool
 746       */
 747      public function require_locking_read() {
 748          return $this->requirelockingread;
 749      }
 750  
 751      /**
 752       * Returns true if this definition requires write locking.
 753       * @return bool
 754       */
 755      public function require_locking_write() {
 756          return $this->requirelockingwrite;
 757      }
 758  
 759      /**
 760       * Returns true if this definition requires a lock to be aquired before a write is attempted.
 761       * @return bool
 762       */
 763      public function require_locking_before_write() {
 764          return $this->requirelockingbeforewrite;
 765      }
 766  
 767      /**
 768       * Returns true if this definition allows local storage to be used for caching.
 769       * @since Moodle 3.1.0
 770       * @return bool
 771       */
 772      public function can_use_localstore() {
 773          return $this->canuselocalstore;
 774      }
 775  
 776      /**
 777       * Returns true if this definition requires a searchable cache.
 778       * @since Moodle 2.4.4
 779       * @return bool
 780       */
 781      public function require_searchable() {
 782          return $this->requiresearchable;
 783      }
 784  
 785      /**
 786       * Returns true if this definition has an associated data source.
 787       * @return bool
 788       */
 789      public function has_data_source() {
 790          return !is_null($this->datasource);
 791      }
 792  
 793      /**
 794       * Returns an instance of the data source class used for this definition.
 795       *
 796       * @return cache_data_source
 797       * @throws coding_exception
 798       */
 799      public function get_data_source() {
 800          if (!$this->has_data_source()) {
 801              throw new coding_exception('This cache does not use a data source.');
 802          }
 803          return forward_static_call(array($this->datasource, 'get_instance_for_cache'), $this);
 804      }
 805  
 806      /**
 807       * Sets the identifiers for this definition, or updates them if they have already been set.
 808       *
 809       * @param array $identifiers
 810       * @return bool false if no identifiers where changed, true otherwise.
 811       * @throws coding_exception
 812       */
 813      public function set_identifiers(array $identifiers = array()) {
 814          if ($this->identifiers !== null) {
 815              throw new coding_exception("You can only set identifiers on initial definition creation." .
 816                  " Define a new cache to set different identifiers.");
 817          }
 818          if (!empty($identifiers) && !empty($this->invalidationevents)) {
 819              throw new coding_exception("You cannot use event invalidation and identifiers at the same time.");
 820          }
 821  
 822          foreach ($this->requireidentifiers as $identifier) {
 823              if (!isset($identifiers[$identifier])) {
 824                  throw new coding_exception('Identifier required for cache has not been provided: '.$identifier);
 825              }
 826          }
 827  
 828          $this->identifiers = array();
 829  
 830          foreach ($identifiers as $name => $value) {
 831              $this->identifiers[$name] = (string)$value;
 832          }
 833          // Reset the key prefix's they need updating now.
 834          $this->keyprefixsingle = null;
 835          $this->keyprefixmulti = null;
 836  
 837          return true;
 838      }
 839  
 840      /**
 841       * Returns the requirements of this definition as a binary flag.
 842       * @return int
 843       */
 844      public function get_requirements_bin() {
 845          $requires = 0;
 846          if ($this->require_data_guarantee()) {
 847              $requires += cache_store::SUPPORTS_DATA_GUARANTEE;
 848          }
 849          if ($this->require_multiple_identifiers()) {
 850              $requires += cache_store::SUPPORTS_MULTIPLE_IDENTIFIERS;
 851          }
 852          if ($this->require_searchable()) {
 853              $requires += cache_store::IS_SEARCHABLE;
 854          }
 855          return $requires;
 856      }
 857  
 858      /**
 859       * Please call {@link cache_definition::use_static_acceleration()} instead.
 860       *
 861       * @see cache_definition::use_static_acceleration()
 862       * @deprecated since 2.6
 863       */
 864      public function should_be_persistent() {
 865          throw new coding_exception('cache_definition::should_be_persistent() can not be used anymore.' .
 866              ' Please use cache_definition::use_static_acceleration() instead.');
 867      }
 868  
 869      /**
 870       * Returns true if we should hold onto the data flowing through the cache.
 871       *
 872       * If set to true data flowing through the cache will be stored in a static variable
 873       * to make subsequent requests for the data much faster.
 874       *
 875       * @return bool
 876       */
 877      public function use_static_acceleration() {
 878          if ($this->mode === cache_store::MODE_REQUEST) {
 879              // Request caches should never use static acceleration - it just doesn't make sense.
 880              return false;
 881          }
 882          return $this->staticacceleration;
 883      }
 884  
 885      /**
 886       * Please call {@link cache_definition::get_static_acceleration_size()} instead.
 887       *
 888       * @see cache_definition::get_static_acceleration_size()
 889       * @deprecated since 2.6
 890       */
 891      public function get_persistent_max_size() {
 892          throw new coding_exception('cache_definition::get_persistent_max_size() can not be used anymore.' .
 893              ' Please use cache_definition::get_static_acceleration_size() instead.');
 894      }
 895  
 896      /**
 897       * Returns the max size for the static acceleration array.
 898       * @return int
 899       */
 900      public function get_static_acceleration_size() {
 901          return $this->staticaccelerationsize;
 902      }
 903  
 904      /**
 905       * Generates a hash of this definition and returns it.
 906       * @return string
 907       */
 908      public function generate_definition_hash() {
 909          if ($this->definitionhash === null) {
 910              $this->definitionhash = md5("{$this->mode} {$this->component} {$this->area}");
 911          }
 912          return $this->definitionhash;
 913      }
 914  
 915      /**
 916       * Generates a single key prefix for this definition
 917       *
 918       * @return string
 919       */
 920      public function generate_single_key_prefix() {
 921          if ($this->keyprefixsingle === null) {
 922              $this->keyprefixsingle = $this->mode.'/'.$this->component.'/'.$this->area;
 923              $this->keyprefixsingle .= '/'.$this->get_cache_identifier();
 924              $identifiers = $this->get_identifiers();
 925              if ($identifiers) {
 926                  foreach ($identifiers as $key => $value) {
 927                      $this->keyprefixsingle .= '/'.$key.'='.$value;
 928                  }
 929              }
 930              $this->keyprefixsingle = md5($this->keyprefixsingle);
 931          }
 932          return $this->keyprefixsingle;
 933      }
 934  
 935      /**
 936       * Generates a multi key prefix for this definition
 937       *
 938       * @return array
 939       */
 940      public function generate_multi_key_parts() {
 941          if ($this->keyprefixmulti === null) {
 942              $this->keyprefixmulti = array(
 943                  'mode' => $this->mode,
 944                  'component' => $this->component,
 945                  'area' => $this->area,
 946                  'siteidentifier' => $this->get_cache_identifier()
 947              );
 948              if (isset($this->identifiers) && !empty($this->identifiers)) {
 949                  $identifiers = array();
 950                  foreach ($this->identifiers as $key => $value) {
 951                      $identifiers[] = htmlentities($key, ENT_QUOTES, 'UTF-8').'='.htmlentities($value, ENT_QUOTES, 'UTF-8');
 952                  }
 953                  $this->keyprefixmulti['identifiers'] = join('&', $identifiers);
 954              }
 955          }
 956          return $this->keyprefixmulti;
 957      }
 958  
 959      /**
 960       * Check if this definition should invalidate on the given event.
 961       *
 962       * @param string $event
 963       * @return bool True if the definition should invalidate on the event. False otherwise.
 964       */
 965      public function invalidates_on_event($event) {
 966          return (in_array($event, $this->invalidationevents));
 967      }
 968  
 969      /**
 970       * Check if the definition has any invalidation events.
 971       *
 972       * @return bool True if it does, false otherwise
 973       */
 974      public function has_invalidation_events() {
 975          return !empty($this->invalidationevents);
 976      }
 977  
 978      /**
 979       * Returns all of the invalidation events for this definition.
 980       *
 981       * @return array
 982       */
 983      public function get_invalidation_events() {
 984          return $this->invalidationevents;
 985      }
 986  
 987      /**
 988       * Returns a cache identification string.
 989       *
 990       * @return string A string to be used as part of keys.
 991       */
 992      protected function get_cache_identifier() {
 993          $identifiers = array();
 994          if ($this->selectedsharingoption & self::SHARING_ALL) {
 995              // Nothing to do here.
 996          } else {
 997              if ($this->selectedsharingoption & self::SHARING_SITEID) {
 998                  $identifiers[] = cache_helper::get_site_identifier();
 999              }
1000              if ($this->selectedsharingoption & self::SHARING_VERSION) {
1001                  $identifiers[] = cache_helper::get_site_version();
1002              }
1003              if ($this->selectedsharingoption & self::SHARING_INPUT && !empty($this->userinputsharingkey)) {
1004                  $identifiers[] = $this->userinputsharingkey;
1005              }
1006          }
1007          return join('/', $identifiers);
1008      }
1009  
1010      /**
1011       * Returns true if this definition requires identifiers.
1012       *
1013       * @param bool
1014       */
1015      public function has_required_identifiers() {
1016          return (count($this->requireidentifiers) > 0);
1017      }
1018  
1019      /**
1020       * Returns the possible sharing options that can be used with this defintion.
1021       *
1022       * @return int
1023       */
1024      public function get_sharing_options() {
1025          return $this->sharingoptions;
1026      }
1027  
1028      /**
1029       * Returns the user entered sharing key for this definition.
1030       *
1031       * @return string
1032       */
1033      public function get_user_input_sharing_key() {
1034          return $this->userinputsharingkey;
1035      }
1036  
1037      /**
1038       * Returns the user selected sharing option for this definition.
1039       *
1040       * @return int
1041       */
1042      public function get_selected_sharing_option() {
1043          return $this->selectedsharingoption;
1044      }
1045  }