1 | <?php |
||||
2 | |||||
3 | /** |
||||
4 | * TCache and cache dependency classes. |
||||
5 | * |
||||
6 | * @author Qiang Xue <[email protected]> |
||||
7 | * @link https://github.com/pradosoft/prado |
||||
8 | * @license https://github.com/pradosoft/prado/blob/master/LICENSE |
||||
9 | */ |
||||
10 | |||||
11 | namespace Prado\Caching; |
||||
12 | |||||
13 | use Prado\Exceptions\TConfigurationException; |
||||
14 | use Prado\Exceptions\TNotSupportedException; |
||||
15 | use Prado\TPropertyValue; |
||||
16 | |||||
17 | /** |
||||
18 | * TCache class |
||||
19 | * |
||||
20 | * TCache is the base class for cache classes with different cache storage implementation. |
||||
21 | * |
||||
22 | * TCache implements the interface {@see \Prado\Caching\ICache} with the following methods, |
||||
23 | * - {@see get()} : retrieve the value with a key (if any) from cache |
||||
24 | * - {@see set()} : store the value with a key into cache |
||||
25 | * - {@see add()} : store the value only if cache does not have this key |
||||
26 | * - {@see delete()} : delete the value with the specified key from cache |
||||
27 | * - {@see flush()} : delete all values from cache |
||||
28 | * |
||||
29 | * Each value is associated with an expiration time. The {@see get()} operation |
||||
30 | * ensures that any expired value will not be returned. The expiration time by |
||||
31 | * the number of seconds. A expiration time 0 represents never expire. |
||||
32 | * |
||||
33 | * By definition, cache does not ensure the existence of a value |
||||
34 | * even if it never expires. Cache is not meant to be an persistent storage. |
||||
35 | * |
||||
36 | * Child classes must implement the following methods: |
||||
37 | * - {@see getValue()} |
||||
38 | * - {@see setValue()} |
||||
39 | * - {@see addValue()} |
||||
40 | * - {@see deleteValue()} |
||||
41 | * |
||||
42 | * and optionally {@see flush()} |
||||
43 | * |
||||
44 | * Since version 3.1.2, TCache implements the \ArrayAccess interface such that |
||||
45 | * the cache acts as an array. |
||||
46 | * |
||||
47 | * @author Qiang Xue <[email protected]> |
||||
48 | * @since 3.0 |
||||
49 | */ |
||||
50 | abstract class TCache extends \Prado\TModule implements ICache, \ArrayAccess |
||||
51 | { |
||||
52 | private $_prefix; |
||||
53 | private $_primary = true; |
||||
54 | |||||
55 | /** |
||||
56 | * Initializes the cache module. |
||||
57 | * This method initializes the cache key prefix and registers the cache module |
||||
58 | * with the application if the cache is primary. |
||||
59 | * @param \Prado\Xml\TXmlElement $config the module configuration |
||||
60 | */ |
||||
61 | 17 | public function init($config) |
|||
62 | { |
||||
63 | 17 | if ($this->_prefix === null) { |
|||
64 | 7 | $this->_prefix = $this->getApplication()->getUniqueID(); |
|||
65 | } |
||||
66 | 17 | if ($this->_primary) { |
|||
67 | 17 | if ($this->getApplication()->getCache() === null) { |
|||
68 | 17 | $this->getApplication()->setCache($this); |
|||
69 | } else { |
||||
70 | throw new TConfigurationException('cache_primary_duplicated', $this::class); |
||||
71 | } |
||||
72 | } |
||||
73 | 17 | parent::init($config); |
|||
74 | } |
||||
75 | |||||
76 | /** |
||||
77 | * @return bool whether this cache module is used as primary/system cache. |
||||
78 | * A primary cache is used by PRADO core framework to cache data such as |
||||
79 | * parsed templates, themes, etc. |
||||
80 | 1 | */ |
|||
81 | public function getPrimaryCache() |
||||
82 | 1 | { |
|||
83 | return $this->_primary; |
||||
84 | } |
||||
85 | |||||
86 | /** |
||||
87 | * @param bool $value whether this cache module is used as primary/system cache. Defaults to false. |
||||
88 | * @see getPrimaryCache |
||||
89 | 1 | */ |
|||
90 | public function setPrimaryCache($value) |
||||
91 | 1 | { |
|||
92 | 1 | $this->_primary = TPropertyValue::ensureBoolean($value); |
|||
93 | } |
||||
94 | |||||
95 | /** |
||||
96 | * @return string a unique prefix for the keys of cached values. |
||||
97 | * If it is not explicitly set, it will take the value of {@see \Prado\TApplication::getUniqueID}. |
||||
98 | 1 | */ |
|||
99 | public function getKeyPrefix() |
||||
100 | 1 | { |
|||
101 | return $this->_prefix; |
||||
102 | } |
||||
103 | |||||
104 | /** |
||||
105 | * @param string $value a unique prefix for the keys of cached values |
||||
106 | 11 | */ |
|||
107 | public function setKeyPrefix($value) |
||||
108 | 11 | { |
|||
109 | 11 | $this->_prefix = $value; |
|||
110 | } |
||||
111 | |||||
112 | /** |
||||
113 | * @param string $key a key identifying a value to be cached |
||||
114 | * @return string a key generated from the provided key which ensures the uniqueness across applications |
||||
115 | 4 | */ |
|||
116 | protected function generateUniqueKey($key) |
||||
117 | 4 | { |
|||
118 | return md5($this->_prefix . $key); |
||||
119 | } |
||||
120 | |||||
121 | /** |
||||
122 | * Retrieves a value from cache with a specified key. |
||||
123 | * @param string $id a key identifying the cached value |
||||
124 | * @return false|mixed the value stored in cache, false if the value is not in the cache or expired. |
||||
125 | 4 | */ |
|||
126 | public function get($id) |
||||
127 | 4 | { |
|||
128 | 3 | if (($data = $this->getValue($this->generateUniqueKey($id))) !== false) { |
|||
129 | if (!is_array($data)) { |
||||
0 ignored issues
–
show
introduced
by
![]() |
|||||
130 | return false; |
||||
131 | 3 | } |
|||
132 | 3 | if (!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged()) { |
|||
133 | return $data[0]; |
||||
134 | } |
||||
135 | 1 | } |
|||
136 | return false; |
||||
137 | } |
||||
138 | |||||
139 | /** |
||||
140 | * Stores a value identified by a key into cache. |
||||
141 | * If the cache already contains such a key, the existing value and |
||||
142 | * expiration time will be replaced with the new ones. If the value is |
||||
143 | * empty, the cache key will be deleted. |
||||
144 | * |
||||
145 | * @param string $id the key identifying the value to be cached |
||||
146 | * @param mixed $value the value to be cached |
||||
147 | * @param int $expire the number of seconds in which the cached value will expire. 0 means never expire. |
||||
148 | * @param ICacheDependency $dependency dependency of the cached item. If the dependency changes, the item is labeled invalid. |
||||
149 | * @return bool true if the value is successfully stored into cache, false otherwise |
||||
150 | 2 | */ |
|||
151 | public function set($id, $value, $expire = 0, $dependency = null) |
||||
152 | 2 | { |
|||
153 | if (empty($value) && $expire === 0) { |
||||
154 | return $this->delete($id); |
||||
155 | 2 | } else { |
|||
156 | 2 | $data = [$value, $dependency]; |
|||
157 | return $this->setValue($this->generateUniqueKey($id), $data, $expire); |
||||
0 ignored issues
–
show
$data of type array<integer,Prado\Cach...eDependency|mixed|null> is incompatible with the type string expected by parameter $value of Prado\Caching\TCache::setValue() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
158 | } |
||||
159 | } |
||||
160 | |||||
161 | /** |
||||
162 | * Stores a value identified by a key into cache if the cache does not contain this key. |
||||
163 | * Nothing will be done if the cache already contains the key or if value is empty. |
||||
164 | * @param string $id the key identifying the value to be cached |
||||
165 | * @param mixed $value the value to be cached |
||||
166 | * @param int $expire the number of seconds in which the cached value will expire. 0 means never expire. |
||||
167 | * @param ICacheDependency $dependency dependency of the cached item. If the dependency changes, the item is labeled invalid. |
||||
168 | * @return bool true if the value is successfully stored into cache, false otherwise |
||||
169 | 1 | */ |
|||
170 | public function add($id, $value, $expire = 0, $dependency = null) |
||||
171 | 1 | { |
|||
172 | if (empty($value) && $expire === 0) { |
||||
173 | return false; |
||||
174 | 1 | } |
|||
175 | 1 | $data = [$value, $dependency]; |
|||
176 | return $this->addValue($this->generateUniqueKey($id), $data, $expire); |
||||
0 ignored issues
–
show
$data of type array<integer,Prado\Cach...eDependency|mixed|null> is incompatible with the type string expected by parameter $value of Prado\Caching\TCache::addValue() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
177 | } |
||||
178 | |||||
179 | /** |
||||
180 | * Deletes a value with the specified key from cache |
||||
181 | * @param string $id the key of the value to be deleted |
||||
182 | * @return bool if no error happens during deletion |
||||
183 | 1 | */ |
|||
184 | public function delete($id) |
||||
185 | 1 | { |
|||
186 | return $this->deleteValue($this->generateUniqueKey($id)); |
||||
187 | } |
||||
188 | |||||
189 | /** |
||||
190 | * Deletes all values from cache. |
||||
191 | * Be careful of performing this operation if the cache is shared by multiple applications. |
||||
192 | * Child classes may implement this method to realize the flush operation. |
||||
193 | * @throws TNotSupportedException if this method is not overridden by child classes |
||||
194 | */ |
||||
195 | public function flush() |
||||
196 | { |
||||
197 | throw new TNotSupportedException('cache_flush_unsupported'); |
||||
198 | } |
||||
199 | |||||
200 | /** |
||||
201 | * Retrieves a value from cache with a specified key. |
||||
202 | * This method should be implemented by child classes to store the data |
||||
203 | * in specific cache storage. The uniqueness and dependency are handled |
||||
204 | * in {@see \Prado\Caching\TCache::get()} already. So only the implementation of data retrieval |
||||
205 | * is needed. |
||||
206 | * @param string $key a unique key identifying the cached value |
||||
207 | * @return false|string the value stored in cache, false if the value is not in the cache or expired. |
||||
208 | */ |
||||
209 | abstract protected function getValue($key); |
||||
210 | |||||
211 | /** |
||||
212 | * Stores a value identified by a key in cache. |
||||
213 | * This method should be implemented by child classes to store the data |
||||
214 | * in specific cache storage. The uniqueness and dependency are handled |
||||
215 | * in {@see \Prado\Caching\TCache::set()} already. So only the implementation of data storage |
||||
216 | * is needed. |
||||
217 | * |
||||
218 | * @param string $key the key identifying the value to be cached |
||||
219 | * @param string $value the value to be cached |
||||
220 | * @param int $expire the number of seconds in which the cached value will expire. 0 means never expire. |
||||
221 | * @return bool true if the value is successfully stored into cache, false otherwise |
||||
222 | */ |
||||
223 | abstract protected function setValue($key, $value, $expire); |
||||
224 | |||||
225 | /** |
||||
226 | * Stores a value identified by a key into cache if the cache does not contain this key. |
||||
227 | * This method should be implemented by child classes to store the data |
||||
228 | * in specific cache storage. The uniqueness and dependency are handled |
||||
229 | * in {@see \Prado\Caching\TCache::add()} already. So only the implementation of data storage |
||||
230 | * is needed. |
||||
231 | * |
||||
232 | * @param string $key the key identifying the value to be cached |
||||
233 | * @param string $value the value to be cached |
||||
234 | * @param int $expire the number of seconds in which the cached value will expire. 0 means never expire. |
||||
235 | * @return bool true if the value is successfully stored into cache, false otherwise |
||||
236 | */ |
||||
237 | abstract protected function addValue($key, $value, $expire); |
||||
238 | |||||
239 | /** |
||||
240 | * Deletes a value with the specified key from cache |
||||
241 | * This method should be implemented by child classes to delete the data from actual cache storage. |
||||
242 | * @param string $key the key of the value to be deleted |
||||
243 | * @return bool if no error happens during deletion |
||||
244 | */ |
||||
245 | abstract protected function deleteValue($key); |
||||
246 | |||||
247 | /** |
||||
248 | * Returns whether there is a cache entry with a specified key. |
||||
249 | * This method is required by the interface \ArrayAccess. |
||||
250 | * @param string $id a key identifying the cached value |
||||
251 | * @return bool |
||||
252 | */ |
||||
253 | public function offsetExists($id): bool |
||||
254 | { |
||||
255 | return $this->get($id) !== false; |
||||
256 | } |
||||
257 | |||||
258 | /** |
||||
259 | * Retrieves the value from cache with a specified key. |
||||
260 | * This method is required by the interface \ArrayAccess. |
||||
261 | * @param string $id a key identifying the cached value |
||||
262 | * @return false|mixed the value stored in cache, false if the value is not in the cache or expired. |
||||
263 | */ |
||||
264 | #[\ReturnTypeWillChange] |
||||
265 | public function offsetGet($id) |
||||
266 | { |
||||
267 | return $this->get($id); |
||||
268 | } |
||||
269 | |||||
270 | /** |
||||
271 | * Stores the value identified by a key into cache. |
||||
272 | * If the cache already contains such a key, the existing value will be |
||||
273 | * replaced with the new ones. To add expiration and dependencies, use the set() method. |
||||
274 | * This method is required by the interface \ArrayAccess. |
||||
275 | * @param string $id the key identifying the value to be cached |
||||
276 | * @param mixed $value the value to be cached |
||||
277 | */ |
||||
278 | public function offsetSet($id, $value): void |
||||
279 | { |
||||
280 | $this->set($id, $value); |
||||
281 | } |
||||
282 | |||||
283 | /** |
||||
284 | * Deletes the value with the specified key from cache |
||||
285 | * This method is required by the interface \ArrayAccess. |
||||
286 | * @param string $id the key of the value to be deleted |
||||
287 | */ |
||||
288 | public function offsetUnset($id): void |
||||
289 | { |
||||
290 | $this->delete($id); |
||||
291 | } |
||||
292 | } |
||||
293 |