‪TYPO3CMS  11.5
ApcuBackend.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
22 
44 {
50  protected ‪$identifierPrefix;
51 
58  {
59  $this->identifierPrefix = ‪$identifierPrefix;
60  }
61 
67  protected function ‪getIdentifierPrefix()
68  {
70  }
71 
79  public function ‪__construct(‪$context, array $options = [])
80  {
81  if (!extension_loaded('apcu')) {
82  throw new ‪Exception('The PHP extension "apcu" must be installed and loaded in order to use the APCu backend.', 1232985914);
83  }
84  if (PHP_SAPI === 'cli' && ini_get('apc.enable_cli') == 0) {
85  throw new ‪Exception('The APCu backend cannot be used because apcu is disabled on CLI.', 1232985915);
86  }
87  parent::__construct(‪$context, $options);
88  }
89 
96  {
97  parent::setCache(‪$cache);
98  $pathHash = md5(‪Environment::getProjectPath() . $this->context . ‪$cache->‪getIdentifier());
99  $this->‪setIdentifierPrefix('TYPO3_' . $pathHash);
100  }
101 
112  public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
113  {
114  if (!$this->cache instanceof ‪FrontendInterface) {
115  throw new ‪Exception('No cache frontend has been set yet via setCache().', 1232986118);
116  }
117  if (!is_string($data)) {
118  throw new ‪InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1232986125);
119  }
120  $tags[] = '%APCBE%' . ‪$this->cacheIdentifier;
121  $expiration = $lifetime ?? ‪$this->defaultLifetime;
122  $success = apcu_store($this->‪getIdentifierPrefix() . $entryIdentifier, $data, $expiration);
123  if ($success === true) {
124  $this->‪removeIdentifierFromAllTags($entryIdentifier);
125  $this->‪addIdentifierToTags($entryIdentifier, $tags);
126  } else {
127  $this->logger->alert('Error using APCu: Could not save data in the cache.');
128  }
129  }
130 
137  public function get($entryIdentifier)
138  {
139  $success = false;
140  $value = apcu_fetch($this->‪getIdentifierPrefix() . $entryIdentifier, $success);
141  return $success ? $value : $success;
142  }
143 
150  public function ‪has($entryIdentifier)
151  {
152  $success = false;
153  apcu_fetch($this->‪getIdentifierPrefix() . $entryIdentifier, $success);
154  return $success;
155  }
156 
165  public function remove($entryIdentifier)
166  {
167  $this->‪removeIdentifierFromAllTags($entryIdentifier);
168  return apcu_delete($this->‪getIdentifierPrefix() . $entryIdentifier);
169  }
170 
178  public function ‪findIdentifiersByTag($tag)
179  {
180  $success = false;
181  $identifiers = apcu_fetch($this->‪getIdentifierPrefix() . 'tag_' . $tag, $success);
182  if ($success === false) {
183  return [];
184  }
185  return (array)$identifiers;
186  }
187 
195  protected function ‪findTagsByIdentifier($identifier)
196  {
197  $success = false;
198  $tags = apcu_fetch($this->‪getIdentifierPrefix() . 'ident_' . $identifier, $success);
199  return $success ? (array)$tags : [];
200  }
201 
207  public function ‪flush()
208  {
209  if (!$this->cache instanceof ‪FrontendInterface) {
210  throw new ‪Exception('Yet no cache frontend has been set via setCache().', 1232986571);
211  }
212  $this->‪flushByTag('%APCBE%' . $this->cacheIdentifier);
213  }
214 
220  public function ‪flushByTag($tag)
221  {
222  $identifiers = $this->‪findIdentifiersByTag($tag);
223  foreach ($identifiers as $identifier) {
224  $this->remove($identifier);
225  }
226  }
227 
234  protected function ‪addIdentifierToTags($entryIdentifier, array $tags)
235  {
236  // Get identifier-to-tag index to look for updates
237  $existingTags = $this->‪findTagsByIdentifier($entryIdentifier);
238  $existingTagsUpdated = false;
239 
240  foreach ($tags as $tag) {
241  // Update tag-to-identifier index
242  $identifiers = $this->‪findIdentifiersByTag($tag);
243  if (!in_array($entryIdentifier, $identifiers, true)) {
244  $identifiers[] = $entryIdentifier;
245  apcu_store($this->‪getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
246  }
247  // Test if identifier-to-tag index needs update
248  if (!in_array($tag, $existingTags, true)) {
249  $existingTags[] = $tag;
250  $existingTagsUpdated = true;
251  }
252  }
253 
254  // Update identifier-to-tag index if needed
255  if ($existingTagsUpdated) {
256  apcu_store($this->‪getIdentifierPrefix() . 'ident_' . $entryIdentifier, $existingTags);
257  }
258  }
259 
265  protected function ‪removeIdentifierFromAllTags($entryIdentifier)
266  {
267  // Get tags for this identifier
268  $tags = $this->‪findTagsByIdentifier($entryIdentifier);
269  // De-associate tags with this identifier
270  foreach ($tags as $tag) {
271  $identifiers = $this->‪findIdentifiersByTag($tag);
272  // Formally array_search() below should never return FALSE due to
273  // the behavior of findTagsByIdentifier(). But if reverse index is
274  // corrupted, we still can get 'FALSE' from array_search(). This is
275  // not a problem because we are removing this identifier from
276  // anywhere.
277  if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
278  unset($identifiers[$key]);
279  if (!empty($identifiers)) {
280  apcu_store($this->‪getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
281  } else {
282  apcu_delete($this->‪getIdentifierPrefix() . 'tag_' . $tag);
283  }
284  }
285  }
286  // Clear reverse tag index for this identifier
287  apcu_delete($this->‪getIdentifierPrefix() . 'ident_' . $entryIdentifier);
288  }
289 
293  public function ‪collectGarbage() {}
294 }
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\addIdentifierToTags
‪addIdentifierToTags($entryIdentifier, array $tags)
Definition: ApcuBackend.php:233
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface\getIdentifier
‪string getIdentifier()
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$cache
‪FrontendInterface $cache
Definition: AbstractBackend.php:38
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\__construct
‪__construct($context, array $options=[])
Definition: ApcuBackend.php:78
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\has
‪bool has($entryIdentifier)
Definition: ApcuBackend.php:149
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\getIdentifierPrefix
‪string getIdentifierPrefix()
Definition: ApcuBackend.php:66
‪TYPO3\CMS\Core\Cache\Backend\TaggableBackendInterface
Definition: TaggableBackendInterface.php:22
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\collectGarbage
‪collectGarbage()
Definition: ApcuBackend.php:292
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$defaultLifetime
‪int $defaultLifetime
Definition: AbstractBackend.php:57
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\flushByTag
‪flushByTag($tag)
Definition: ApcuBackend.php:219
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\findIdentifiersByTag
‪array findIdentifiersByTag($tag)
Definition: ApcuBackend.php:177
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend
Definition: ApcuBackend.php:44
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\$identifierPrefix
‪string $identifierPrefix
Definition: ApcuBackend.php:49
‪TYPO3\CMS\Core\Core\Environment\getProjectPath
‪static string getProjectPath()
Definition: Environment.php:177
‪TYPO3\CMS\Core\Cache\Exception
Definition: DuplicateIdentifierException.php:16
‪TYPO3\CMS\Core\Cache\Exception\InvalidDataException
Definition: InvalidDataException.php:23
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\setCache
‪setCache(FrontendInterface $cache)
Definition: ApcuBackend.php:94
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\findTagsByIdentifier
‪array findTagsByIdentifier($identifier)
Definition: ApcuBackend.php:194
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$cacheIdentifier
‪string $cacheIdentifier
Definition: AbstractBackend.php:42
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend
Definition: AbstractBackend.php:28
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Core\Cache\Backend
Definition: AbstractBackend.php:16
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\removeIdentifierFromAllTags
‪removeIdentifierFromAllTags($entryIdentifier)
Definition: ApcuBackend.php:264
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$context
‪string $context
Definition: AbstractBackend.php:51
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\setIdentifierPrefix
‪setIdentifierPrefix($identifierPrefix)
Definition: ApcuBackend.php:56
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\flush
‪flush()
Definition: ApcuBackend.php:206
‪TYPO3\CMS\Core\Cache\Exception
Definition: Exception.php:21