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