‪TYPO3CMS  9.5
ApcuBackend.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
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  $processUser = $this->‪getCurrentUserData();
99  $pathHash = GeneralUtility::shortMD5(‪Environment::getProjectPath() . $processUser['name'] . $this->context . ‪$cache->‪getIdentifier(), 12);
100  $this->‪setIdentifierPrefix('TYPO3_' . $pathHash);
101  }
102 
109  protected function ‪getCurrentUserData()
110  {
111  return extension_loaded('posix') ? posix_getpwuid(posix_geteuid()) : ['name' => 'default'];
112  }
113 
124  public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
125  {
126  if (!$this->cache instanceof ‪FrontendInterface) {
127  throw new ‪Exception('No cache frontend has been set yet via setCache().', 1232986118);
128  }
129  if (!is_string($data)) {
130  throw new ‪InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1232986125);
131  }
132  $tags[] = '%APCBE%' . ‪$this->cacheIdentifier;
133  $expiration = $lifetime ?? ‪$this->defaultLifetime;
134  $success = apcu_store($this->‪getIdentifierPrefix() . $entryIdentifier, $data, $expiration);
135  if ($success === true) {
136  $this->‪removeIdentifierFromAllTags($entryIdentifier);
137  $this->‪addIdentifierToTags($entryIdentifier, $tags);
138  } else {
139  $this->logger->alert('Error using APCu: Could not save data in the cache.');
140  }
141  }
142 
149  public function get($entryIdentifier)
150  {
151  $success = false;
152  $value = apcu_fetch($this->‪getIdentifierPrefix() . $entryIdentifier, $success);
153  return $success ? $value : $success;
154  }
155 
162  public function ‪has($entryIdentifier)
163  {
164  $success = false;
165  apcu_fetch($this->‪getIdentifierPrefix() . $entryIdentifier, $success);
166  return $success;
167  }
168 
177  public function remove($entryIdentifier)
178  {
179  $this->‪removeIdentifierFromAllTags($entryIdentifier);
180  return apcu_delete($this->‪getIdentifierPrefix() . $entryIdentifier);
181  }
182 
190  public function ‪findIdentifiersByTag($tag)
191  {
192  $success = false;
193  $identifiers = apcu_fetch($this->‪getIdentifierPrefix() . 'tag_' . $tag, $success);
194  if ($success === false) {
195  return [];
196  }
197  return (array)$identifiers;
198  }
199 
207  protected function ‪findTagsByIdentifier($identifier)
208  {
209  $success = false;
210  $tags = apcu_fetch($this->‪getIdentifierPrefix() . 'ident_' . $identifier, $success);
211  return $success ? (array)$tags : [];
212  }
213 
219  public function ‪flush()
220  {
221  if (!$this->cache instanceof ‪FrontendInterface) {
222  throw new ‪Exception('Yet no cache frontend has been set via setCache().', 1232986571);
223  }
224  $this->‪flushByTag('%APCBE%' . $this->cacheIdentifier);
225  }
226 
232  public function ‪flushByTag($tag)
233  {
234  $identifiers = $this->‪findIdentifiersByTag($tag);
235  foreach ($identifiers as $identifier) {
236  $this->remove($identifier);
237  }
238  }
239 
246  protected function ‪addIdentifierToTags($entryIdentifier, array $tags)
247  {
248  // Get identifier-to-tag index to look for updates
249  $existingTags = $this->‪findTagsByIdentifier($entryIdentifier);
250  $existingTagsUpdated = false;
251 
252  foreach ($tags as $tag) {
253  // Update tag-to-identifier index
254  $identifiers = $this->‪findIdentifiersByTag($tag);
255  if (!in_array($entryIdentifier, $identifiers, true)) {
256  $identifiers[] = $entryIdentifier;
257  apcu_store($this->‪getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
258  }
259  // Test if identifier-to-tag index needs update
260  if (!in_array($tag, $existingTags, true)) {
261  $existingTags[] = $tag;
262  $existingTagsUpdated = true;
263  }
264  }
265 
266  // Update identifier-to-tag index if needed
267  if ($existingTagsUpdated) {
268  apcu_store($this->‪getIdentifierPrefix() . 'ident_' . $entryIdentifier, $existingTags);
269  }
270  }
271 
277  protected function ‪removeIdentifierFromAllTags($entryIdentifier)
278  {
279  // Get tags for this identifier
280  $tags = $this->‪findTagsByIdentifier($entryIdentifier);
281  // De-associate tags with this identifier
282  foreach ($tags as $tag) {
283  $identifiers = $this->‪findIdentifiersByTag($tag);
284  // Formally array_search() below should never return FALSE due to
285  // the behavior of findTagsByIdentifier(). But if reverse index is
286  // corrupted, we still can get 'FALSE' from array_search(). This is
287  // not a problem because we are removing this identifier from
288  // anywhere.
289  if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
290  unset($identifiers[$key]);
291  if (!empty($identifiers)) {
292  apcu_store($this->‪getIdentifierPrefix() . 'tag_' . $tag, $identifiers);
293  } else {
294  apcu_delete($this->‪getIdentifierPrefix() . 'tag_' . $tag);
295  }
296  }
297  }
298  // Clear reverse tag index for this identifier
299  apcu_delete($this->‪getIdentifierPrefix() . 'ident_' . $entryIdentifier);
300  }
301 
305  public function ‪collectGarbage()
306  {
307  }
308 }
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\addIdentifierToTags
‪addIdentifierToTags($entryIdentifier, array $tags)
Definition: ApcuBackend.php:245
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\getCurrentUserData
‪array getCurrentUserData()
Definition: ApcuBackend.php:108
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface\getIdentifier
‪string getIdentifier()
‪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:161
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\getIdentifierPrefix
‪string getIdentifierPrefix()
Definition: ApcuBackend.php:66
‪TYPO3\CMS\Core\Cache\Backend\TaggableBackendInterface
Definition: TaggableBackendInterface.php:21
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\collectGarbage
‪collectGarbage()
Definition: ApcuBackend.php:304
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$defaultLifetime
‪int $defaultLifetime
Definition: AbstractBackend.php:54
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\flushByTag
‪flushByTag($tag)
Definition: ApcuBackend.php:231
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\findIdentifiersByTag
‪array findIdentifiersByTag($tag)
Definition: ApcuBackend.php:189
‪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:142
‪TYPO3\CMS\Core\Cache\Exception
Definition: DuplicateIdentifierException.php:2
‪TYPO3\CMS\Core\Cache\Exception\InvalidDataException
Definition: InvalidDataException.php:21
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\setCache
‪setCache(FrontendInterface $cache)
Definition: ApcuBackend.php:94
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$cache
‪TYPO3 CMS Core Cache Frontend FrontendInterface $cache
Definition: AbstractBackend.php:35
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\findTagsByIdentifier
‪array findTagsByIdentifier($identifier)
Definition: ApcuBackend.php:206
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:21
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$cacheIdentifier
‪string $cacheIdentifier
Definition: AbstractBackend.php:39
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend
Definition: AbstractBackend.php:26
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:39
‪TYPO3\CMS\Core\Cache\Backend
Definition: AbstractBackend.php:2
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\removeIdentifierFromAllTags
‪removeIdentifierFromAllTags($entryIdentifier)
Definition: ApcuBackend.php:276
‪TYPO3\CMS\Core\Cache\Backend\AbstractBackend\$context
‪string $context
Definition: AbstractBackend.php:48
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\setIdentifierPrefix
‪setIdentifierPrefix($identifierPrefix)
Definition: ApcuBackend.php:56
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Core\Cache\Backend\ApcuBackend\flush
‪flush()
Definition: ApcuBackend.php:218
‪TYPO3\CMS\Core\Cache\Exception
Definition: Exception.php:21