TYPO3  7.6
WincacheBackend.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Cache\Backend;
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 
38 {
44  protected $identifierPrefix;
45 
53  public function __construct($context, array $options = array())
54  {
55  if (!extension_loaded('wincache')) {
56  throw new \TYPO3\CMS\Core\Cache\Exception('The PHP extension "wincache" must be installed and loaded in order to use the wincache backend.', 1343331520);
57  }
58  parent::__construct($context, $options);
59  }
60 
73  public function set($entryIdentifier, $data, array $tags = array(), $lifetime = null)
74  {
75  if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
76  throw new \TYPO3\CMS\Core\Cache\Exception('No cache frontend has been set yet via setCache().', 1343331521);
77  }
78  if (!is_string($data)) {
79  throw new \TYPO3\CMS\Core\Cache\Exception\InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1343331522);
80  }
81  $tags[] = '%WCBE%' . $this->cache->getIdentifier();
82  $expiration = $lifetime !== null ? $lifetime : $this->defaultLifetime;
83  $success = wincache_ucache_set($this->identifierPrefix . $entryIdentifier, $data, $expiration);
84  if ($success === true) {
85  $this->removeIdentifierFromAllTags($entryIdentifier);
86  $this->addIdentifierToTags($entryIdentifier, $tags);
87  } else {
88  throw new \TYPO3\CMS\Core\Cache\Exception('Could not set value.', 1343331523);
89  }
90  }
91 
98  public function get($entryIdentifier)
99  {
100  $success = false;
101  $value = wincache_ucache_get($this->identifierPrefix . $entryIdentifier, $success);
102  return $success ? $value : $success;
103  }
104 
111  public function has($entryIdentifier)
112  {
113  return wincache_ucache_exists($this->identifierPrefix . $entryIdentifier);
114  }
115 
124  public function remove($entryIdentifier)
125  {
126  $this->removeIdentifierFromAllTags($entryIdentifier);
127  return wincache_ucache_delete($this->identifierPrefix . $entryIdentifier);
128  }
129 
137  public function findIdentifiersByTag($tag)
138  {
139  $success = false;
140  $identifiers = wincache_ucache_get($this->identifierPrefix . 'tag_' . $tag, $success);
141  if ($success === false) {
142  return array();
143  } else {
144  return (array)$identifiers;
145  }
146  }
147 
155  protected function findTagsByIdentifier($identifier)
156  {
157  $success = false;
158  $tags = wincache_ucache_get($this->identifierPrefix . 'ident_' . $identifier, $success);
159  return $success ? (array)$tags : array();
160  }
161 
168  public function flush()
169  {
170  if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
171  throw new \TYPO3\CMS\Core\Cache\Exception('Yet no cache frontend has been set via setCache().', 1343331524);
172  }
173  $this->flushByTag('%WCBE%' . $this->cache->getIdentifier());
174  }
175 
183  public function flushByTag($tag)
184  {
185  $identifiers = $this->findIdentifiersByTag($tag);
186  foreach ($identifiers as $identifier) {
187  $this->remove($identifier);
188  }
189  }
190 
198  protected function addIdentifierToTags($entryIdentifier, array $tags)
199  {
200  // Get identifier-to-tag index to look for updates
201  $existingTags = $this->findTagsByIdentifier($entryIdentifier);
202  $existingTagsUpdated = false;
203 
204  foreach ($tags as $tag) {
205  // Update tag-to-identifier index
206  $identifiers = $this->findIdentifiersByTag($tag);
207  if (!in_array($entryIdentifier, $identifiers, true)) {
208  $identifiers[] = $entryIdentifier;
209  wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
210  }
211  // Test if identifier-to-tag index needs update
212  if (!in_array($tag, $existingTags, true)) {
213  $existingTags[] = $tag;
214  $existingTagsUpdated = true;
215  }
216  }
217 
218  // Update identifier-to-tag index if needed
219  if ($existingTagsUpdated) {
220  wincache_ucache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, $existingTags);
221  }
222  }
223 
230  protected function removeIdentifierFromAllTags($entryIdentifier)
231  {
232  // Get tags for this identifier
233  $tags = $this->findTagsByIdentifier($entryIdentifier);
234  // Deassociate tags with this identifier
235  foreach ($tags as $tag) {
236  $identifiers = $this->findIdentifiersByTag($tag);
237  // Formally array_search() below should never return false due to
238  // the behavior of findTagsByIdentifier(). But if reverse index is
239  // corrupted, we still can get 'false' from array_search(). This is
240  // not a problem because we are removing this identifier from
241  // anywhere.
242  if (($key = array_search($entryIdentifier, $identifiers)) !== false) {
243  unset($identifiers[$key]);
244  if (!empty($identifiers)) {
245  wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
246  } else {
247  wincache_ucache_delete($this->identifierPrefix . 'tag_' . $tag);
248  }
249  }
250  }
251  // Clear reverse tag index for this identifier
252  wincache_ucache_delete($this->identifierPrefix . 'ident_' . $entryIdentifier);
253  }
254 
260  public function collectGarbage()
261  {
262  }
263 }