‪TYPO3CMS  10.4
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 
23 
45 {
51  protected ‪$identifierPrefix;
52 
59  {
60  $this->identifierPrefix = ‪$identifierPrefix;
61  }
62 
68  protected function ‪getIdentifierPrefix()
69  {
71  }
72 
80  public function ‪__construct(‪$context, array $options = [])
81  {
82  if (!extension_loaded('apcu')) {
83  throw new ‪Exception('The PHP extension "apcu" must be installed and loaded in order to use the APCu backend.', 1232985914);
84  }
85  if (PHP_SAPI === 'cli' && ini_get('apc.enable_cli') == 0) {
86  throw new ‪Exception('The APCu backend cannot be used because apcu is disabled on CLI.', 1232985915);
87  }
88  parent::__construct(‪$context, $options);
89  }
90 
97  {
98  parent::setCache(‪$cache);
99  $pathHash = GeneralUtility::shortMD5(‪Environment::getProjectPath() . $this->context . ‪$cache->‪getIdentifier(), 12);
100  $this->‪setIdentifierPrefix('TYPO3_' . $pathHash);
101  }
102 
113  public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
114  {
115  if (!$this->cache instanceof ‪FrontendInterface) {
116  throw new ‪Exception('No cache frontend has been set yet via setCache().', 1232986118);
117  }
118  if (!is_string($data)) {
119  throw new ‪InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1232986125);
120  }
121  $tags[] = '%APCBE%' . ‪$this->cacheIdentifier;
122  $expiration = $lifetime ?? ‪$this->defaultLifetime;
123  $success = apcu_store($this->‪getIdentifierPrefix() . $entryIdentifier, $data, $expiration);
124  if ($success === true) {
125  $this->‪removeIdentifierFromAllTags($entryIdentifier);
126  $this->‪addIdentifierToTags($entryIdentifier, $tags);
127  } else {
128  $this->logger->alert('Error using APCu: Could not save data in the cache.');
129  }
130  }
131 
138  public function get($entryIdentifier)
139  {
140  $success = false;
141  $value = apcu_fetch($this->‪getIdentifierPrefix() . $entryIdentifier, $success);
142  return $success ? $value : $success;
143  }
144 
151  public function ‪has($entryIdentifier)
152  {
153  $success = false;
154  apcu_fetch($this->‪getIdentifierPrefix() . $entryIdentifier, $success);
155  return $success;
156  }
157 
166  public function remove($entryIdentifier)
167  {
168  $this->‪removeIdentifierFromAllTags($entryIdentifier);
169  return apcu_delete($this->‪getIdentifierPrefix() . $entryIdentifier);
170  }
171 
179  public function ‪findIdentifiersByTag($tag)
180  {
181  $success = false;
182  $identifiers = apcu_fetch($this->‪getIdentifierPrefix() . 'tag_' . $tag, $success);
183  if ($success === false) {
184  return [];
185  }
186  return (array)$identifiers;
187  }
188 
196  protected function ‪findTagsByIdentifier($identifier)
197  {
198  $success = false;
199  $tags = apcu_fetch($this->‪getIdentifierPrefix() . 'ident_' . $identifier, $success);
200  return $success ? (array)$tags : [];
201  }
202 
208  public function ‪flush()
209  {
210  if (!$this->cache instanceof ‪FrontendInterface) {
211  throw new ‪Exception('Yet no cache frontend has been set via setCache().', 1232986571);
212  }
213  $this->‪flushByTag('%APCBE%' . $this->cacheIdentifier);
214  }
215 
221  public function ‪flushByTag($tag)
222  {
223  $identifiers = $this->‪findIdentifiersByTag($tag);
224  foreach ($identifiers as $identifier) {
225  $this->remove($identifier);
226  }
227  }
228 
235  protected function ‪addIdentifierToTags($entryIdentifier, array $tags)
236  {
237  // Get identifier-to-tag index to look for updates
238  $existingTags = $this->‪findTagsByIdentifier($entryIdentifier);
239  $existingTagsUpdated = false;
240 
241  foreach ($tags as $tag) {
242  // Update tag-to-identifier index
243  $identifiers = $this->‪findIdentifiersByTag($tag);
244  if (!in_array($entryIdentifier, $identifiers, true)) {
245  $identifiers[] = $entryIdentifier;
246  apcu_store($this->‪getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
247  }
248  // Test if identifier-to-tag index needs update
249  if (!in_array($tag, $existingTags, true)) {
250  $existingTags[] = $tag;
251  $existingTagsUpdated = true;
252  }
253  }
254 
255  // Update identifier-to-tag index if needed
256  if ($existingTagsUpdated) {
257  apcu_store($this->‪getIdentifierPrefix() . 'ident_' . $entryIdentifier, $existingTags);
258  }
259  }
260 
266  protected function ‪removeIdentifierFromAllTags($entryIdentifier)
267  {
268  // Get tags for this identifier
269  $tags = $this->‪findTagsByIdentifier($entryIdentifier);
270  // De-associate tags with this identifier
271  foreach ($tags as $tag) {
272  $identifiers = $this->‪findIdentifiersByTag($tag);
273  // Formally array_search() below should never return FALSE due to
274  // the behavior of findTagsByIdentifier(). But if reverse index is
275  // corrupted, we still can get 'FALSE' from array_search(). This is
276  // not a problem because we are removing this identifier from
277  // anywhere.
278  if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
279  unset($identifiers[$key]);
280  if (!empty($identifiers)) {
281  apcu_store($this->‪getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
282  } else {
283  apcu_delete($this->‪getIdentifierPrefix() . 'tag_' . $tag);
284  }
285  }
286  }
287  // Clear reverse tag index for this identifier
288  apcu_delete($this->‪getIdentifierPrefix() . 'ident_' . $entryIdentifier);
289  }
290 
294  public function ‪collectGarbage()
295  {
296  }
297 }
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\addIdentifierToTags
‪addIdentifierToTags($entryIdentifier, array $tags)
Definition: ApcuBackend.php:234
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface\getIdentifier
‪string getIdentifier()
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\__construct
‪__construct($context, array $options=[])
Definition: ApcuBackend.php:79
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\has
‪bool has($entryIdentifier)
Definition: ApcuBackend.php:150
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\getIdentifierPrefix
‪string getIdentifierPrefix()
Definition: ApcuBackend.php:67
‪TYPO3\CMS\Core\Cache\Backend\TaggableBackendInterface
Definition: TaggableBackendInterface.php:22
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\collectGarbage
‪collectGarbage()
Definition: ApcuBackend.php:293
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$defaultLifetime
‪int $defaultLifetime
Definition: AbstractBackend.php:56
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\flushByTag
‪flushByTag($tag)
Definition: ApcuBackend.php:220
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\findIdentifiersByTag
‪array findIdentifiersByTag($tag)
Definition: ApcuBackend.php:178
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend
Definition: ApcuBackend.php:45
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\$identifierPrefix
‪string $identifierPrefix
Definition: ApcuBackend.php:50
‪TYPO3\CMS\Core\Core\Environment\getProjectPath
‪static string getProjectPath()
Definition: Environment.php:169
‪TYPO3\CMS\Core\Cache\Exception
Definition: DuplicateIdentifierException.php:16
‪TYPO3\CMS\Core\Cache\Exception\InvalidDataException
Definition: InvalidDataException.php:24
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\setCache
‪setCache(FrontendInterface $cache)
Definition: ApcuBackend.php:95
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$cache
‪TYPO3 CMS Core Cache Frontend FrontendInterface $cache
Definition: AbstractBackend.php:37
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\findTagsByIdentifier
‪array findTagsByIdentifier($identifier)
Definition: ApcuBackend.php:195
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$cacheIdentifier
‪string $cacheIdentifier
Definition: AbstractBackend.php:41
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend
Definition: AbstractBackend.php:28
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:40
‪TYPO3\CMS\Core\Cache\Backend
Definition: AbstractBackend.php:16
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\removeIdentifierFromAllTags
‪removeIdentifierFromAllTags($entryIdentifier)
Definition: ApcuBackend.php:265
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$context
‪string $context
Definition: AbstractBackend.php:50
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\setIdentifierPrefix
‪setIdentifierPrefix($identifierPrefix)
Definition: ApcuBackend.php:57
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\flush
‪flush()
Definition: ApcuBackend.php:207
‪TYPO3\CMS\Core\Cache\Exception
Definition: Exception.php:22