Merge pull request #13400 from mfb/format-resource-url
[civicrm-core.git] / CRM / Utils / Cache / ArrayDecorator.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2019
32 */
33
34 /**
35 * Class CRM_Utils_Cache_ArrayDecorator
36 *
37 * This creates a two-tier cache-hierarchy: a thread-local, array-based cache
38 * combined with some third-party cache driver.
39 *
40 * Ex: $cache = new CRM_Utils_Cache_ArrayDecorator(new CRM_Utils_Cache_Redis(...));
41 */
42 class CRM_Utils_Cache_ArrayDecorator implements CRM_Utils_Cache_Interface {
43
44 use CRM_Utils_Cache_NaiveMultipleTrait; // TODO Consider native implementation.
45
46 /**
47 * @var int
48 * Default time-to-live (seconds) for cache items that don't have a TTL.
49 */
50 protected $defaultTimeout;
51
52 /**
53 * @var CRM_Utils_Cache_Interface
54 */
55 private $delegate;
56
57 /**
58 * @var array
59 * Array(string $cacheKey => mixed $cacheValue).
60 */
61 private $values = [];
62
63 /**
64 * @var array
65 * Array(string $cacheKey => int $expirationTime).
66 */
67 private $expires = [];
68
69 /**
70 * CRM_Utils_Cache_ArrayDecorator constructor.
71 * @param \CRM_Utils_Cache_Interface $delegate
72 * @param int $defaultTimeout
73 * Default number of seconds each cache-item should endure.
74 */
75 public function __construct(\CRM_Utils_Cache_Interface $delegate, $defaultTimeout = 3600) {
76 $this->defaultTimeout = $defaultTimeout;
77 $this->delegate = $delegate;
78 }
79
80 public function set($key, $value, $ttl = NULL) {
81 if (is_int($ttl) && $ttl <= 0) {
82 return $this->delete($key);
83 }
84
85 $expiresAt = CRM_Utils_Date::convertCacheTtlToExpires($ttl, $this->defaultTimeout);
86 if ($this->delegate->set($key, [$expiresAt, $value], $ttl)) {
87 $this->values[$key] = $this->reobjectify($value);
88 $this->expires[$key] = $expiresAt;
89 return TRUE;
90 }
91 else {
92 return FALSE;
93 }
94 }
95
96 public function get($key, $default = NULL) {
97 if (array_key_exists($key, $this->values) && $this->expires[$key] > CRM_Utils_Time::getTimeRaw()) {
98 return $this->reobjectify($this->values[$key]);
99 }
100
101 $nack = CRM_Utils_Cache::nack();
102 $value = $this->delegate->get($key, $nack);
103 if ($value === $nack) {
104 return $default;
105 }
106
107 $this->expires[$key] = $value[0];
108 $this->values[$key] = $value[1];
109 return $this->reobjectify($this->values[$key]);
110 }
111
112 public function delete($key) {
113 unset($this->values[$key]);
114 unset($this->expires[$key]);
115 return $this->delegate->delete($key);
116 }
117
118 public function flush() {
119 return $this->clear();
120 }
121
122 public function clear() {
123 $this->values = [];
124 $this->expires = [];
125 return $this->delegate->clear();
126 }
127
128 public function has($key) {
129 if (array_key_exists($key, $this->values) && $this->expires[$key] > CRM_Utils_Time::getTimeRaw()) {
130 return TRUE;
131 }
132 return $this->delegate->has($key);
133 }
134
135 private function reobjectify($value) {
136 return is_object($value) ? unserialize(serialize($value)) : $value;
137 }
138
139 }