TYPO3 CMS  TYPO3_7-6
XcacheBackend.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 
18 
40 {
46  protected $identifierPrefix;
47 
55  public function __construct($context, array $options = [])
56  {
57  if (!extension_loaded('xcache')) {
58  throw new Exception(
59  'The PHP extension "xcache" must be installed and loaded in order to use the xcache backend.',
60  1363116592
61  );
62  }
63  parent::__construct($context, $options);
64  }
65 
77  public function set($entryIdentifier, $data, array $tags = [], $lifetime = null)
78  {
80  return;
81  }
82  if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
83  throw new Exception(
84  'No cache frontend has been set yet via setCache().',
85  1363117491
86  );
87  }
88  if (!is_string($data)) {
89  throw new Exception\InvalidDataException(
90  'The specified data is of type "' . gettype($data) . '" but a string is expected.',
91  1363117435
92  );
93  }
94  $tags[] = '%XCBE%' . $this->cache->getIdentifier();
95  $expiration = $lifetime !== null ? $lifetime : $this->defaultLifetime;
96  $success = xcache_set($this->identifierPrefix . $entryIdentifier, $data, $expiration);
97  if ($success === true) {
98  $this->removeIdentifierFromAllTags($entryIdentifier);
99  $this->addIdentifierToTags($entryIdentifier, $tags);
100  } else {
101  throw new Exception(
102  'Could not set value.',
103  1363117507
104  );
105  }
106  }
107 
114  public function get($entryIdentifier)
115  {
116  if ($this->runningFromCliOrWrongConfiguration()) {
117  return false;
118  }
119  $value = xcache_get($this->identifierPrefix . $entryIdentifier);
120  return $value ?: false;
121  }
122 
129  public function has($entryIdentifier)
130  {
131  if ($this->runningFromCliOrWrongConfiguration()) {
132  return false;
133  }
134  return xcache_isset($this->identifierPrefix . $entryIdentifier);
135  }
136 
145  public function remove($entryIdentifier)
146  {
147  if ($this->runningFromCliOrWrongConfiguration()) {
148  return false;
149  }
150  $this->removeIdentifierFromAllTags($entryIdentifier);
151  return xcache_unset($this->identifierPrefix . $entryIdentifier);
152  }
153 
161  public function findIdentifiersByTag($tag)
162  {
163  if ($this->runningFromCliOrWrongConfiguration()) {
164  return [];
165  }
166  $identifiers = xcache_get($this->identifierPrefix . 'tag_' . $tag);
167  return $identifiers ?: [];
168  }
169 
177  protected function findTagsByIdentifier($identifier)
178  {
179  if ($this->runningFromCliOrWrongConfiguration()) {
180  return [];
181  }
182  $tags = xcache_get($this->identifierPrefix . 'ident_' . $identifier);
183  return $tags ?: [];
184  }
185 
192  public function flush()
193  {
194  if ($this->runningFromCliOrWrongConfiguration()) {
195  return;
196  }
197  if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
198  throw new Exception(
199  'Yet no cache frontend has been set via setCache().',
200  1363117531
201  );
202  }
203  $this->flushByTag('%XCBE%' . $this->cache->getIdentifier());
204  }
205 
213  public function flushByTag($tag)
214  {
215  $identifiers = $this->findIdentifiersByTag($tag);
216  foreach ($identifiers as $identifier) {
217  $this->remove($identifier);
218  }
219  }
220 
228  protected function addIdentifierToTags($entryIdentifier, array $tags)
229  {
230  if ($this->runningFromCliOrWrongConfiguration()) {
231  return;
232  }
233 
234  // Get identifier-to-tag index to look for updates
235  $existingTags = $this->findTagsByIdentifier($entryIdentifier);
236  $existingTagsUpdated = false;
237 
238  foreach ($tags as $tag) {
239  // Update tag-to-identifier index
240  $identifiers = $this->findIdentifiersByTag($tag);
241  if (!in_array($entryIdentifier, $identifiers, true)) {
242  $identifiers[] = $entryIdentifier;
243  xcache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
244  }
245  // Test if identifier-to-tag index needs update
246  if (!in_array($tag, $existingTags, true)) {
247  $existingTags[] = $tag;
248  $existingTagsUpdated = true;
249  }
250  }
251 
252  // Update identifier-to-tag index if needed
253  if ($existingTagsUpdated) {
254  xcache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags);
255  }
256  }
257 
264  protected function removeIdentifierFromAllTags($entryIdentifier)
265  {
266  if ($this->runningFromCliOrWrongConfiguration()) {
267  return;
268  }
269  // Get tags for this identifier
270  $tags = $this->findTagsByIdentifier($entryIdentifier);
271  // Disassociate tags with this identifier
272  foreach ($tags as $tag) {
273  $identifiers = $this->findIdentifiersByTag($tag);
274  // Formally array_search() below should never return false due to
275  // the behavior of findTagsByIdentifier(). But if reverse index is
276  // corrupted, we still can get 'false' from array_search(). This is
277  // not a problem because we are removing this identifier from
278  // anywhere.
279  if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
280  unset($identifiers[$key]);
281  if (!empty($identifiers)) {
282  xcache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
283  } else {
284  xcache_unset($this->identifierPrefix . 'tag_' . $tag);
285  }
286  }
287  }
288  // Clear reverse tag index for this identifier
289  xcache_unset($this->identifierPrefix . 'ident_' . $entryIdentifier);
290  }
291 
297  public function collectGarbage()
298  {
299  }
300 
309  {
310  $varSize = ini_get('xcache.var_size');
311  return php_sapi_name() === 'cli' || empty($varSize);
312  }
313 }
addIdentifierToTags($entryIdentifier, array $tags)
__construct($context, array $options=[])