MDL-36768 cache: Implemented abstract cache store base class
[moodle.git] / cache / stores / session / lib.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  * The library file for the session cache store.
19  *
20  * This file is part of the session cache store, it contains the API for interacting with an instance of the store.
21  * This is used as a default cache store within the Cache API. It should never be deleted.
22  *
23  * @package    cachestore_session
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 Session store class.
33  *
34  * @copyright  2012 Sam Hemelryk
35  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36  */
37 class cachestore_session extends session_data_store implements cache_is_key_aware {
39     /**
40      * The name of the store
41      * @var store
42      */
43     protected $name;
45     /**
46      * The store id (should be unique)
47      * @var string
48      */
49     protected $storeid;
51     /**
52      * The store we use for data.
53      * @var array
54      */
55     protected $store;
57     /**
58      * The ttl if there is one. Hopefully not.
59      * @var int
60      */
61     protected $ttl = 0;
63     /**
64      * Constructs the store instance.
65      *
66      * Noting that this function is not an initialisation. It is used to prepare the store for use.
67      * The store will be initialised when required and will be provided with a cache_definition at that time.
68      *
69      * @param string $name
70      * @param array $configuration
71      */
72     public function __construct($name, array $configuration = array()) {
73         $this->name = $name;
74     }
76     /**
77      * Returns the supported features as a combined int.
78      *
79      * @param array $configuration
80      * @return int
81      */
82     public static function get_supported_features(array $configuration = array()) {
83         return self::SUPPORTS_DATA_GUARANTEE +
84                self::SUPPORTS_NATIVE_TTL;
85     }
87     /**
88      * Returns the supported modes as a combined int.
89      *
90      * @param array $configuration
91      * @return int
92      */
93     public static function get_supported_modes(array $configuration = array()) {
94         return self::MODE_SESSION;
95     }
97     /**
98      * Returns true if the store requirements are met.
99      *
100      * @return bool
101      */
102     public static function are_requirements_met() {
103         return true;
104     }
106     /**
107      * Returns true if the given mode is supported by this store.
108      *
109      * @param int $mode One of cache_store::MODE_*
110      * @return bool
111      */
112     public static function is_supported_mode($mode) {
113         return ($mode === self::MODE_SESSION);
114     }
116     /**
117      * Initialises the cache.
118      *
119      * Once this has been done the cache is all set to be used.
120      *
121      * @param cache_definition $definition
122      */
123     public function initialise(cache_definition $definition) {
124         $this->storeid = $definition->generate_definition_hash();
125         $this->store = &self::register_store_id($definition->get_id());
126         $this->ttl = $definition->get_ttl();
127     }
129     /**
130      * Returns true once this instance has been initialised.
131      *
132      * @return bool
133      */
134     public function is_initialised() {
135         return (is_array($this->store));
136     }
138     /**
139      * Returns true if this store instance is ready to be used.
140      * @return bool
141      */
142     public function is_ready() {
143         return true;
144     }
146     /**
147      * Retrieves an item from the cache store given its key.
148      *
149      * @param string $key The key to retrieve
150      * @return mixed The data that was associated with the key, or false if the key did not exist.
151      */
152     public function get($key) {
153         $maxtime = cache::now() - $this->ttl;
154         if (array_key_exists($key, $this->store)) {
155             if ($this->ttl == 0) {
156                 return $this->store[$key];
157             } else if ($this->store[$key][1] >= $maxtime) {
158                 return $this->store[$key][0];
159             }
160         }
161         return false;
162     }
164     /**
165      * Retrieves several items from the cache store in a single transaction.
166      *
167      * If not all of the items are available in the cache then the data value for those that are missing will be set to false.
168      *
169      * @param array $keys The array of keys to retrieve
170      * @return array An array of items from the cache. There will be an item for each key, those that were not in the store will
171      *      be set to false.
172      */
173     public function get_many($keys) {
174         $return = array();
175         $maxtime = cache::now() - $this->ttl;
176         foreach ($keys as $key) {
177             $return[$key] = false;
178             if (array_key_exists($key, $this->store)) {
179                 if ($this->ttl == 0) {
180                     $return[$key] = $this->store[$key];
181                 } else if ($this->store[$key][1] >= $maxtime) {
182                     $return[$key] = $this->store[$key][0];
183                 }
184             }
185         }
186         return $return;
187     }
189     /**
190      * Sets an item in the cache given its key and data value.
191      *
192      * @param string $key The key to use.
193      * @param mixed $data The data to set.
194      * @return bool True if the operation was a success false otherwise.
195      */
196     public function set($key, $data) {
197         if ($this->ttl == 0) {
198             $this->store[$key] = $data;
199         } else {
200             $this->store[$key] = array($data, cache::now());
201         }
202         return true;
203     }
205     /**
206      * Sets many items in the cache in a single transaction.
207      *
208      * @param array $keyvaluearray An array of key value pairs. Each item in the array will be an associative array with two
209      *      keys, 'key' and 'value'.
210      * @return int The number of items successfully set. It is up to the developer to check this matches the number of items
211      *      sent ... if they care that is.
212      */
213     public function set_many(array $keyvaluearray) {
214         $count = 0;
215         foreach ($keyvaluearray as $pair) {
216             $this->set($pair['key'], $pair['value']);
217             $count++;
218         }
219         return $count;
220     }
222     /**
223      * Checks if the store has a record for the given key and returns true if so.
224      *
225      * @param string $key
226      * @return bool
227      */
228     public function has($key) {
229         $maxtime = cache::now() - $this->ttl;
230         if (array_key_exists($key, $this->store)) {
231             if ($this->ttl == 0) {
232                 return true;
233             } else if ($this->store[$key][1] >= $maxtime) {
234                 return true;
235             }
236         }
237         return false;
238     }
240     /**
241      * Returns true if the store contains records for all of the given keys.
242      *
243      * @param array $keys
244      * @return bool
245      */
246     public function has_all(array $keys) {
247         $maxtime = cache::now() - $this->ttl;
248         foreach ($keys as $key) {
249             if (!array_key_exists($key, $this->store)) {
250                 return false;
251             }
252             if ($this->ttl != 0 && $this->store[$key][1] < $maxtime) {
253                 return false;
254             }
255         }
256         return true;
257     }
259     /**
260      * Returns true if the store contains records for any of the given keys.
261      *
262      * @param array $keys
263      * @return bool
264      */
265     public function has_any(array $keys) {
266         $maxtime = cache::now() - $this->ttl;
267         foreach ($keys as $key) {
268             if (array_key_exists($key, $this->store) && ($this->ttl == 0 || $this->store[$key][1] >= $maxtime)) {
269                 return true;
270             }
271         }
272         return false;
273     }
275     /**
276      * Deletes an item from the cache store.
277      *
278      * @param string $key The key to delete.
279      * @return bool Returns true if the operation was a success, false otherwise.
280      */
281     public function delete($key) {
282         unset($this->store[$key]);
283         return true;
284     }
286     /**
287      * Deletes several keys from the cache in a single action.
288      *
289      * @param array $keys The keys to delete
290      * @return int The number of items successfully deleted.
291      */
292     public function delete_many(array $keys) {
293         $count = 0;
294         foreach ($keys as $key) {
295             unset($this->store[$key]);
296             $count++;
297         }
298         return $count;
299     }
301     /**
302      * Purges the cache deleting all items within it.
303      *
304      * @return boolean True on success. False otherwise.
305      */
306     public function purge() {
307         $this->store = array();
308     }
310     /**
311      * Returns true if the user can add an instance of the store plugin.
312      *
313      * @return bool
314      */
315     public static function can_add_instance() {
316         return false;
317     }
319     /**
320      * Performs any necessary clean up when the store instance is being deleted.
321      */
322     public function cleanup() {
323         $this->purge();
324     }
326     /**
327      * Generates an instance of the cache store that can be used for testing.
328      *
329      * @param cache_definition $definition
330      * @return false
331      */
332     public static function initialise_test_instance(cache_definition $definition) {
333         // Do something here perhaps.
334         $cache = new cachestore_session('Session test');
335         $cache->initialise($definition);
336         return $cache;
337     }
339     /**
340      * Returns the name of this instance.
341      * @return string
342      */
343     public function my_name() {
344         return $this->name;
345     }
348 /**
349  * The session data store class.
350  *
351  * @copyright  2012 Sam Hemelryk
352  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
353  */
354 abstract class session_data_store extends cache_store_base {
356     /**
357      * Used for the actual storage.
358      * @var array
359      */
360     private static $sessionstore = null;
362     /**
363      * Returns a static store by reference... REFERENCE SUPER IMPORTANT.
364      *
365      * @param string $id
366      * @return array
367      */
368     protected static function &register_store_id($id) {
369         if (is_null(self::$sessionstore)) {
370             global $SESSION;
371             if (!isset($SESSION->cachestore_session)) {
372                 $SESSION->cachestore_session = array();
373             }
374             self::$sessionstore =& $SESSION->cachestore_session;
375         }
376         if (!array_key_exists($id, self::$sessionstore)) {
377             self::$sessionstore[$id] = array();
378         }
379         return self::$sessionstore[$id];
380     }
382     /**
383      * Flushes the data belong to the given store id.
384      * @param string $id
385      */
386     protected static function flush_store_by_id($id) {
387         unset(self::$sessionstore[$id]);
388         self::$sessionstore[$id] = array();
389     }
391     /**
392      * Flushes the store of all data.
393      */
394     protected static function flush_store() {
395         $ids = array_keys(self::$sessionstore);
396         unset(self::$sessionstore);
397         self::$sessionstore = array();
398         foreach ($ids as $id) {
399             self::$sessionstore[$id] = array();
400         }
401     }