da5cd4cc209d8a93da7ae67cfcda24b02b396a3a
[moodle.git] / cache / classes / definition.php
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/>.
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  */
29 defined('MOODLE_INTERNAL') || die();
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] Suplements the above setting indicated the file containing the class to be used. This file is included when
79  *          required.
80  *     + persistent
81  *          [bool] This setting does two important things. First it tells the cache API to only instantiate the cache structure for
82  *          this definition once, further requests will be given the original instance.
83  *          Second the cache loader will keep an array of the items set and retrieved to the cache during the request.
84  *          This has several advantages including better performance without needing to start passing the cache instance between
85  *          function calls, the downside is that the cache instance + the items used stay within memory.
86  *          Consider using this setting when you know that there are going to be many calls to the cache for the same information
87  *          or when you are converting existing code to the cache and need to access the cache within functions but don't want
88  *          to add it as an argument to the function.
89  *     + persistentmaxsize
90  *          [int] This supplements the above setting by limiting the number of items in the caches persistent array of items.
91  *          Tweaking this setting lower will allow you to minimise the memory implications above while hopefully still managing to
92  *          offset calls to the cache store.
93  *     + ttl
94  *          [int] A time to live for the data (in seconds). It is strongly recommended that you don't make use of this and
95  *          instead try to create an event driven invalidation system.
96  *          Not all cache stores will support this natively and there are undesired performance impacts if the cache store does not.
97  *     + mappingsonly
98  *          [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
99  *          advanced setting and should not be used unless absolutely required. It allows you to avoid the default stores for one
100  *          reason or another.
101  *     + invalidationevents
102  *          [array] An array of events that should cause this cache to invalidate some or all of the items within it.
103  *     + sharingoptions
104  *          [int] The sharing options that are appropriate for this definition. Should be the sum of the possible options.
105  *     + defaultsharing
106  *          [int] The default sharing option to use. It's highly recommended that you don't set this unless there is a very
107  *          specific reason not to use the system default.
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 {
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;
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;
138     /**
139      * The identifier for the definition
140      * @var string
141      */
142     protected $id;
144     /**
145      * The mode for the defintion. One of cache_store::MODE_*
146      * @var int
147      */
148     protected $mode;
150     /**
151      * The component this definition is associated with.
152      * @var string
153      */
154     protected $component;
156     /**
157      * The area this definition is associated with.
158      * @var string
159      */
160     protected $area;
162     /**
163      * If set to true we know the keys are simple. a-zA-Z0-9_
164      * @var bool
165      */
166     protected $simplekeys = false;
168     /**
169      * Set to true if we know the data is scalar or array of scalar.
170      * @var bool
171      */
172     protected $simpledata = false;
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();
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;
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;
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;
199     /**
200      * Set to true if this definition requires read locking.
201      * @var bool
202      */
203     protected $requirelockingread = false;
205     /**
206      * Gets set to true if this definition requires write locking.
207      * @var bool
208      */
209     protected $requirelockingwrite = false;
211     /**
212      * Gets set to true if this definition requires searchable stores.
213      * @since 2.4.4
214      * @var bool
215      */
216     protected $requiresearchable = false;
218     /**
219      * Sets the maximum number of items that can exist in the cache.
220      * 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.
221      * @var int
222      */
223     protected $maxsize = null;
225     /**
226      * The class to use as the cache loader for this definition.
227      * @var string
228      */
229     protected $overrideclass = null;
231     /**
232      * The file in which the override class exists. This will be included if required.
233      * @var string Absolute path
234      */
235     protected $overrideclassfile = null;
237     /**
238      * The data source class to use with this definition.
239      * @var string
240      */
241     protected $datasource = null;
243     /**
244      * The file in which the data source class exists. This will be included if required.
245      * @var string
246      */
247     protected $datasourcefile = null;
249     /**
250      * The data source class aggregate to use. This is a super advanced setting.
251      * @var string
252      */
253     protected $datasourceaggregate = null;
255     /**
256      * Set to true if the definitions cache should be persistent
257      * @var bool
258      */
259     protected $persistent = false;
261     /**
262      * The persistent item array max size.
263      * @var int
264      */
265     protected $persistentmaxsize = false;
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;
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;
279     /**
280      * An array of events that should cause this cache to invalidate.
281      * @var array
282      */
283     protected $invalidationevents = array();
285     /**
286      * An array of identifiers provided to this cache when it was initialised.
287      * @var array
288      */
289     protected $identifiers = array();
291     /**
292      * Key prefix for use with single key cache stores
293      * @var string
294      */
295     protected $keyprefixsingle = null;
297     /**
298      * Key prefix to use with cache stores that support multi keys.
299      * @var array
300      */
301     protected $keyprefixmulti = null;
303     /**
304      * A hash identifier of this definition.
305      * @var string
306      */
307     protected $definitionhash = null;
309     /**
310      * The selected sharing mode for this definition.
311      * @var int
312      */
313     protected $sharingoptions;
315     /**
316      * The selected sharing option.
317      * @var int One of self::SHARING_*
318      */
319     protected $selectedsharingoption = self::SHARING_DEFAULT;
321     /**
322      * The user input key to use if the SHARING_INPUT option has been selected.
323      * @var string Must be ALPHANUMEXT
324      */
325     protected $userinputsharingkey = '';
327     /**
328      * Creates a cache definition given a definition from the cache configuration or from a caches.php file.
329      *
330      * @param string $id
331      * @param array $definition
332      * @param string $datasourceaggregate
333      * @return cache_definition
334      * @throws coding_exception
335      */
336     public static function load($id, array $definition, $datasourceaggregate = null) {
337         global $CFG;
339         if (!array_key_exists('mode', $definition)) {
340             throw new coding_exception('You must provide a mode when creating a cache definition');
341         }
342         if (!array_key_exists('component', $definition)) {
343             throw new coding_exception('You must provide a component when creating a cache definition');
344         }
345         if (!array_key_exists('area', $definition)) {
346             throw new coding_exception('You must provide an area when creating a cache definition');
347         }
348         $mode = (int)$definition['mode'];
349         $component = (string)$definition['component'];
350         $area = (string)$definition['area'];
352         // Set the defaults.
353         $simplekeys = false;
354         $simpledata = false;
355         $requireidentifiers = array();
356         $requiredataguarantee = false;
357         $requiremultipleidentifiers = false;
358         $requirelockingread = false;
359         $requirelockingwrite = false;
360         $requiresearchable = ($mode === cache_store::MODE_SESSION) ? true : false;
361         $maxsize = null;
362         $overrideclass = null;
363         $overrideclassfile = null;
364         $datasource = null;
365         $datasourcefile = null;
366         $persistent = false;
367         $persistentmaxsize = false;
368         $ttl = 0;
369         $mappingsonly = false;
370         $invalidationevents = array();
371         $sharingoptions = self::SHARING_DEFAULT;
372         $selectedsharingoption = self::SHARING_DEFAULT;
373         $userinputsharingkey = '';
375         if (array_key_exists('simplekeys', $definition)) {
376             $simplekeys = (bool)$definition['simplekeys'];
377         }
378         if (array_key_exists('simpledata', $definition)) {
379             $simpledata = (bool)$definition['simpledata'];
380         }
381         if (array_key_exists('requireidentifiers', $definition)) {
382             $requireidentifiers = (array)$definition['requireidentifiers'];
383         }
384         if (array_key_exists('requiredataguarantee', $definition)) {
385             $requiredataguarantee = (bool)$definition['requiredataguarantee'];
386         }
387         if (array_key_exists('requiremultipleidentifiers', $definition)) {
388             $requiremultipleidentifiers = (bool)$definition['requiremultipleidentifiers'];
389         }
391         if (array_key_exists('requirelockingread', $definition)) {
392             $requirelockingread = (bool)$definition['requirelockingread'];
393         }
394         if (array_key_exists('requirelockingwrite', $definition)) {
395             $requirelockingwrite = (bool)$definition['requirelockingwrite'];
396         }
397         $requirelocking = $requirelockingwrite || $requirelockingread;
399         if (array_key_exists('requiresearchable', $definition)) {
400             $requiresearchable = (bool)$definition['requiresearchable'];
401         }
403         if (array_key_exists('maxsize', $definition)) {
404             $maxsize = (int)$definition['maxsize'];
405         }
407         if (array_key_exists('overrideclass', $definition)) {
408             $overrideclass = $definition['overrideclass'];
409         }
410         if (array_key_exists('overrideclassfile', $definition)) {
411             $overrideclassfile = $definition['overrideclassfile'];
412         }
414         if (array_key_exists('datasource', $definition)) {
415             $datasource = $definition['datasource'];
416         }
417         if (array_key_exists('datasourcefile', $definition)) {
418             $datasourcefile = $definition['datasourcefile'];
419         }
421         if (array_key_exists('persistent', $definition)) {
422             $persistent = (bool)$definition['persistent'];
423         }
424         if (array_key_exists('persistentmaxsize', $definition)) {
425             $persistentmaxsize = (int)$definition['persistentmaxsize'];
426         }
427         if (array_key_exists('ttl', $definition)) {
428             $ttl = (int)$definition['ttl'];
429         }
430         if (array_key_exists('mappingsonly', $definition)) {
431             $mappingsonly = (bool)$definition['mappingsonly'];
432         }
433         if (array_key_exists('invalidationevents', $definition)) {
434             $invalidationevents = (array)$definition['invalidationevents'];
435         }
436         if (array_key_exists('sharingoptions', $definition)) {
437             $sharingoptions = (int)$definition['sharingoptions'];
438         }
439         if (array_key_exists('selectedsharingoption', $definition)) {
440             $selectedsharingoption = (int)$definition['selectedsharingoption'];
441         } else if (array_key_exists('defaultsharing', $definition)) {
442             $selectedsharingoption = (int)$definition['defaultsharing'];
443         } else if ($sharingoptions ^ $selectedsharingoption) {
444             if ($sharingoptions & self::SHARING_SITEID) {
445                 $selectedsharingoption = self::SHARING_SITEID;
446             } else if ($sharingoptions & self::SHARING_VERSION) {
447                 $selectedsharingoption = self::SHARING_VERSION;
448             } else {
449                 $selectedsharingoption = self::SHARING_ALL;
450             }
451         }
453         if (array_key_exists('userinputsharingkey', $definition) && !empty($definition['userinputsharingkey'])) {
454             $userinputsharingkey = (string)$definition['userinputsharingkey'];
455         }
457         if (!is_null($overrideclass)) {
458             if (!is_null($overrideclassfile)) {
459                 if (strpos($overrideclassfile, $CFG->dirroot) !== 0) {
460                     $overrideclassfile = $CFG->dirroot.'/'.$overrideclassfile;
461                 }
462                 if (strpos($overrideclassfile, '../') !== false) {
463                     throw new coding_exception('No path craziness allowed within override class file path.');
464                 }
465                 if (!file_exists($overrideclassfile)) {
466                     throw new coding_exception('The override class file does not exist.');
467                 }
468                 require_once($overrideclassfile);
469             }
470             if (!class_exists($overrideclass)) {
471                 throw new coding_exception('The override class does not exist.');
472             }
474             // Make sure that the provided class extends the default class for the mode.
475             if (get_parent_class($overrideclass) !== cache_helper::get_class_for_mode($mode)) {
476                 throw new coding_exception('The override class does not immediately extend the relevant cache class.');
477             }
478         }
480         if (!is_null($datasource)) {
481             if (!is_null($datasourcefile)) {
482                 if (strpos($datasourcefile, $CFG->dirroot) !== 0) {
483                     $datasourcefile = $CFG->dirroot.'/'.$datasourcefile;
484                 }
485                 if (strpos($datasourcefile, '../') !== false) {
486                     throw new coding_exception('No path craziness allowed within data source file path.');
487                 }
488                 if (!file_exists($datasourcefile)) {
489                     throw new coding_exception('The data source class file does not exist.');
490                 }
491                 require_once($datasourcefile);
492             }
493             if (!class_exists($datasource)) {
494                 throw new coding_exception('The data source class does not exist.');
495             }
496             if (!array_key_exists('cache_data_source', class_implements($datasource))) {
497                 throw new coding_exception('Cache data source classes must implement the cache_data_source interface');
498             }
499         }
501         $cachedefinition = new cache_definition();
502         $cachedefinition->id = $id;
503         $cachedefinition->mode = $mode;
504         $cachedefinition->component = $component;
505         $cachedefinition->area = $area;
506         $cachedefinition->simplekeys = $simplekeys;
507         $cachedefinition->simpledata = $simpledata;
508         $cachedefinition->requireidentifiers = $requireidentifiers;
509         $cachedefinition->requiredataguarantee = $requiredataguarantee;
510         $cachedefinition->requiremultipleidentifiers = $requiremultipleidentifiers;
511         $cachedefinition->requirelocking = $requirelocking;
512         $cachedefinition->requirelockingread = $requirelockingread;
513         $cachedefinition->requirelockingwrite = $requirelockingwrite;
514         $cachedefinition->requiresearchable = $requiresearchable;
515         $cachedefinition->maxsize = $maxsize;
516         $cachedefinition->overrideclass = $overrideclass;
517         $cachedefinition->overrideclassfile = $overrideclassfile;
518         $cachedefinition->datasource = $datasource;
519         $cachedefinition->datasourcefile = $datasourcefile;
520         $cachedefinition->datasourceaggregate = $datasourceaggregate;
521         $cachedefinition->persistent = $persistent;
522         $cachedefinition->persistentmaxsize = $persistentmaxsize;
523         $cachedefinition->ttl = $ttl;
524         $cachedefinition->mappingsonly = $mappingsonly;
525         $cachedefinition->invalidationevents = $invalidationevents;
526         $cachedefinition->sharingoptions = $sharingoptions;
527         $cachedefinition->selectedsharingoption = $selectedsharingoption;
528         $cachedefinition->userinputsharingkey = $userinputsharingkey;
530         return $cachedefinition;
531     }
533     /**
534      * Creates an ah-hoc cache definition given the required params.
535      *
536      * Please note that when using an adhoc definition you cannot set any of the optional params.
537      * This is because we cannot guarantee consistent access and we don't want to mislead people into thinking that.
538      *
539      * @param int $mode One of cache_store::MODE_*
540      * @param string $component The component this definition relates to.
541      * @param string $area The area this definition relates to.
542      * @param array $options An array of options, available options are:
543      *   - simplekeys : Set to true if the keys you will use are a-zA-Z0-9_
544      *   - simpledata : Set to true if the type of the data you are going to store is scalar, or an array of scalar vars
545      *   - overrideclass : The class to use as the loader.
546      *   - persistent : If set to true the cache will persist construction requests.
547      * @return cache_application|cache_session|cache_request
548      */
549     public static function load_adhoc($mode, $component, $area, array $options = array()) {
550         $id = 'adhoc/'.$component.'_'.$area;
551         $definition = array(
552             'mode' => $mode,
553             'component' => $component,
554             'area' => $area,
555         );
556         if (!empty($options['simplekeys'])) {
557             $definition['simplekeys'] = $options['simplekeys'];
558         }
559         if (!empty($options['simpledata'])) {
560             $definition['simpledata'] = $options['simpledata'];
561         }
562         if (!empty($options['persistent'])) {
563             $definition['persistent'] = $options['persistent'];
564         }
565         if (!empty($options['overrideclass'])) {
566             $definition['overrideclass'] = $options['overrideclass'];
567         }
568         if (!empty($options['sharingoptions'])) {
569             $definition['sharingoptions'] = $options['sharingoptions'];
570         }
571         return self::load($id, $definition, null);
572     }
574     /**
575      * Returns the cache loader class that should be used for this definition.
576      * @return string
577      */
578     public function get_cache_class() {
579         if (!is_null($this->overrideclass)) {
580             return $this->overrideclass;
581         }
582         return cache_helper::get_class_for_mode($this->mode);
583     }
585     /**
586      * Returns the id of this definition.
587      * @return string
588      */
589     public function get_id() {
590         return $this->id;
591     }
593     /**
594      * Returns the name for this definition
595      * @return string
596      */
597     public function get_name() {
598         $identifier = 'cachedef_'.clean_param($this->area, PARAM_STRINGID);
599         $component = $this->component;
600         if ($component === 'core') {
601             $component = 'cache';
602         }
603         return new lang_string($identifier, $component);
604     }
606     /**
607      * Returns the mode of this definition
608      * @return int One more cache_store::MODE_
609      */
610     public function get_mode() {
611         return $this->mode;
612     }
614     /**
615      * Returns the area this definition is associated with.
616      * @return string
617      */
618     public function get_area() {
619         return $this->area;
620     }
622     /**
623      * Returns the component this definition is associated with.
624      * @return string
625      */
626     public function get_component() {
627         return $this->component;
628     }
630     /**
631      * Returns true if this definition is using simple keys.
632      *
633      * Simple keys contain only a-zA-Z0-9_
634      *
635      * @return bool
636      */
637     public function uses_simple_keys() {
638         return $this->simplekeys;
639     }
641     /**
642      * Returns the identifiers that are being used for this definition.
643      * @return array
644      */
645     public function get_identifiers() {
646         return $this->identifiers;
647     }
649     /**
650      * Returns the ttl in seconds for this definition if there is one, or null if not.
651      * @return int|null
652      */
653     public function get_ttl() {
654         return $this->ttl;
655     }
657     /**
658      * Returns the maximum number of items allowed in this cache.
659      * @return int
660      */
661     public function get_maxsize() {
662         return $this->maxsize;
663     }
665     /**
666      * Returns true if this definition should only be used with mappings.
667      * @return bool
668      */
669     public function is_for_mappings_only() {
670         return $this->mappingsonly;
671     }
673     /**
674      * Returns true if the data is known to be scalar or array of scalar.
675      * @return bool
676      */
677     public function uses_simple_data() {
678         return $this->simpledata;
679     }
681     /**
682      * Returns true if this definition requires a data guarantee from the cache stores being used.
683      * @return bool
684      */
685     public function require_data_guarantee() {
686         return $this->requiredataguarantee;
687     }
689     /**
690      * Returns true if this definition requires that the cache stores support multiple identifiers
691      * @return bool
692      */
693     public function require_multiple_identifiers() {
694         return $this->requiremultipleidentifiers;
695     }
697     /**
698      * Returns true if this definition requires locking functionality. Either read or write locking.
699      * @return bool
700      */
701     public function require_locking() {
702         return $this->requirelocking;
703     }
705     /**
706      * Returns true if this definition requires read locking.
707      * @return bool
708      */
709     public function require_locking_read() {
710         return $this->requirelockingread;
711     }
713     /**
714      * Returns true if this definition requires write locking.
715      * @return bool
716      */
717     public function require_locking_write() {
718         return $this->requirelockingwrite;
719     }
721     /**
722      * Returns true if this definition requires a searchable cache.
723      * @since 2.4.4
724      * @return bool
725      */
726     public function require_searchable() {
727         return $this->requiresearchable;
728     }
730     /**
731      * Returns true if this definition has an associated data source.
732      * @return bool
733      */
734     public function has_data_source() {
735         return !is_null($this->datasource);
736     }
738     /**
739      * Returns an instance of the data source class used for this definition.
740      *
741      * @return cache_data_source
742      * @throws coding_exception
743      */
744     public function get_data_source() {
745         if (!$this->has_data_source()) {
746             throw new coding_exception('This cache does not use a data source.');
747         }
748         return forward_static_call(array($this->datasource, 'get_instance_for_cache'), $this);
749     }
751     /**
752      * Sets the identifiers for this definition, or updates them if they have already been set.
753      *
754      * @param array $identifiers
755      * @throws coding_exception
756      */
757     public function set_identifiers(array $identifiers = array()) {
758         foreach ($this->requireidentifiers as $identifier) {
759             if (!isset($identifiers[$identifier])) {
760                 throw new coding_exception('Identifier required for cache has not been provided: '.$identifier);
761             }
762         }
763         foreach ($identifiers as $name => $value) {
764             $this->identifiers[$name] = (string)$value;
765         }
766         // Reset the key prefix's they need updating now.
767         $this->keyprefixsingle = null;
768         $this->keyprefixmulti = null;
769     }
771     /**
772      * Returns the requirements of this definition as a binary flag.
773      * @return int
774      */
775     public function get_requirements_bin() {
776         $requires = 0;
777         if ($this->require_data_guarantee()) {
778             $requires += cache_store::SUPPORTS_DATA_GUARANTEE;
779         }
780         if ($this->require_multiple_identifiers()) {
781             $requires += cache_store::SUPPORTS_MULTIPLE_IDENTIFIERS;
782         }
783         if ($this->require_searchable()) {
784             $requires += cache_store::IS_SEARCHABLE;
785         }
786         return $requires;
787     }
789     /**
790      * Returns true if this definitions cache should be made persistent.
791      * @return bool
792      */
793     public function should_be_persistent() {
794         return $this->persistent || $this->mode === cache_store::MODE_SESSION;
795     }
797     /**
798      * Returns the max size for the persistent item array in the cache.
799      * @return int
800      */
801     public function get_persistent_max_size() {
802         return $this->persistentmaxsize;
803     }
805     /**
806      * Generates a hash of this definition and returns it.
807      * @return string
808      */
809     public function generate_definition_hash() {
810         if ($this->definitionhash === null) {
811             $this->definitionhash = md5("{$this->mode} {$this->component} {$this->area}");
812         }
813         return $this->definitionhash;
814     }
816     /**
817      * Generates a single key prefix for this definition
818      *
819      * @return string
820      */
821     public function generate_single_key_prefix() {
822         if ($this->keyprefixsingle === null) {
823             $this->keyprefixsingle = $this->mode.'/'.$this->component.'/'.$this->area;
824             $this->keyprefixsingle .= '/'.$this->get_cache_identifier();
825             $identifiers = $this->get_identifiers();
826             if ($identifiers) {
827                 foreach ($identifiers as $key => $value) {
828                     $this->keyprefixsingle .= '/'.$key.'='.$value;
829                 }
830             }
831             $this->keyprefixsingle = md5($this->keyprefixsingle);
832         }
833         return $this->keyprefixsingle;
834     }
836     /**
837      * Generates a multi key prefix for this definition
838      *
839      * @return array
840      */
841     public function generate_multi_key_parts() {
842         if ($this->keyprefixmulti === null) {
843             $this->keyprefixmulti = array(
844                 'mode' => $this->mode,
845                 'component' => $this->component,
846                 'area' => $this->area,
847                 'siteidentifier' => $this->get_cache_identifier()
848             );
849             if (!empty($this->identifiers)) {
850                 $identifiers = array();
851                 foreach ($this->identifiers as $key => $value) {
852                     $identifiers[] = htmlentities($key, ENT_QUOTES, 'UTF-8').'='.htmlentities($value, ENT_QUOTES, 'UTF-8');
853                 }
854                 $this->keyprefixmulti['identifiers'] = join('&', $identifiers);
855             }
856         }
857         return $this->keyprefixmulti;
858     }
860     /**
861      * Check if this definition should invalidate on the given event.
862      *
863      * @param string $event
864      * @return bool True if the definition should invalidate on the event. False otherwise.
865      */
866     public function invalidates_on_event($event) {
867         return (in_array($event, $this->invalidationevents));
868     }
870     /**
871      * Check if the definition has any invalidation events.
872      *
873      * @return bool True if it does, false otherwise
874      */
875     public function has_invalidation_events() {
876         return !empty($this->invalidationevents);
877     }
879     /**
880      * Returns all of the invalidation events for this definition.
881      *
882      * @return array
883      */
884     public function get_invalidation_events() {
885         return $this->invalidationevents;
886     }
888     /**
889      * Returns a cache identification string.
890      *
891      * @return string A string to be used as part of keys.
892      */
893     protected function get_cache_identifier() {
894         $identifiers = array();
895         if ($this->selectedsharingoption & self::SHARING_ALL) {
896             // Nothing to do here.
897         } else {
898             if ($this->selectedsharingoption & self::SHARING_SITEID) {
899                 $identifiers[] = cache_helper::get_site_identifier();
900             }
901             if ($this->selectedsharingoption & self::SHARING_VERSION) {
902                 $identifiers[] = cache_helper::get_site_version();
903             }
904             if ($this->selectedsharingoption & self::SHARING_INPUT && !empty($this->userinputsharingkey)) {
905                 $identifiers[] = $this->userinputsharingkey;
906             }
907         }
908         return join('/', $identifiers);
909     }
911     /**
912      * Returns true if this definition requires identifiers.
913      *
914      * @param bool
915      */
916     public function has_required_identifiers() {
917         return (count($this->requireidentifiers) > 0);
918     }