Merge pull request #13068 from alifrumin/formLink
[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 CRM_Utils_Cache::assertValidKey($key);
98 if (array_key_exists($key, $this->values) && $this->expires[$key] > CRM_Utils_Time::getTimeRaw()) {
99 return $this->reobjectify($this->values[$key]);
100 }
101
102 $nack = CRM_Utils_Cache::nack();
103 $value = $this->delegate->get($key, $nack);
104 if ($value === $nack) {
105 return $default;
106 }
107
108 $this->expires[$key] = $value[0];
109 $this->values[$key] = $value[1];
110 return $this->reobjectify($this->values[$key]);
111 }
112
113 public function delete($key) {
114 CRM_Utils_Cache::assertValidKey($key);
115 unset($this->values[$key]);
116 unset($this->expires[$key]);
117 return $this->delegate->delete($key);
118 }
119
120 public function flush() {
121 return $this->clear();
122 }
123
124 public function clear() {
125 $this->values = [];
126 $this->expires = [];
127 return $this->delegate->clear();
128 }
129
130 public function has($key) {
131 CRM_Utils_Cache::assertValidKey($key);
132 if (array_key_exists($key, $this->values) && $this->expires[$key] > CRM_Utils_Time::getTimeRaw()) {
133 return TRUE;
134 }
135 return $this->delegate->has($key);
136 }
137
138 private function reobjectify($value) {
139 return is_object($value) ? unserialize(serialize($value)) : $value;
140 }
141
142 }