pradosoft /
prado
| 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
Loading history...
|
|||||
| 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
Loading history...
|
|||||
| 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
Loading history...
|
|||||
| 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 |