[TASK] Re-work/simplify copyright header in PHP files - Part 2
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Cache / Backend / WincacheBackend.php
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 /**
17 * A caching backend which stores cache entries by using wincache.
18 *
19 * This backend uses the following types of keys:
20 * - tag_xxx
21 * xxx is tag name, value is array of associated identifiers identifier. This
22 * is "forward" tag index. It is mainly used for obtaining content by tag
23 * (get identifier by tag -> get content by identifier)
24 * - ident_xxx
25 * xxx is identifier, value is array of associated tags. This is "reverse" tag
26 * index. It provides quick access for all tags associated with this identifier
27 * and used when removing the identifier
28 *
29 * Each key is prepended with a prefix. By default prefix consists from two parts
30 * separated by underscore character and ends in yet another underscore character:
31 * - "TYPO3"
32 * - MD5 of script path and filename and SAPI name
33 * This prefix makes sure that keys from the different installations do not
34 * conflict.
35 *
36 * @author Tobias Burger <tobias_burger@hotmail.com>
37 */
38 class WincacheBackend extends \TYPO3\CMS\Core\Cache\Backend\AbstractBackend implements \TYPO3\CMS\Core\Cache\Backend\TaggableBackendInterface {
39
40 /**
41 * A prefix to seperate stored data from other data possible stored in the wincache
42 *
43 * @var string
44 */
45 protected $identifierPrefix;
46
47 /**
48 * Constructs this backend
49 *
50 * @param string $context FLOW3's application context
51 * @param array $options Configuration options
52 * @throws \TYPO3\CMS\Core\Cache\Exception If wincache PHP extension is not loaded
53 */
54 public function __construct($context, array $options = array()) {
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
61 /**
62 * Saves data in the cache
63 *
64 * @param string $entryIdentifier An identifier for this specific cache entry
65 * @param string $data The data to be stored
66 * @param array $tags Tags to associate with this cache entry
67 * @param integer $lifetime Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited liftime.
68 * @return void
69 * @throws \TYPO3\CMS\Core\Cache\Exception if no cache frontend has been set
70 * @throws \InvalidArgumentException if the identifier is not valid
71 * @throws \TYPO3\CMS\Core\Cache\Exception\InvalidDataException if $data is not a string
72 */
73 public function set($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) {
74 if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
75 throw new \TYPO3\CMS\Core\Cache\Exception('No cache frontend has been set yet via setCache().', 1343331521);
76 }
77 if (!is_string($data)) {
78 throw new \TYPO3\CMS\Core\Cache\Exception\InvalidDataException('The specified data is of type "' . gettype($data) . '" but a string is expected.', 1343331522);
79 }
80 $tags[] = '%WCBE%' . $this->cache->getIdentifier();
81 $expiration = $lifetime !== NULL ? $lifetime : $this->defaultLifetime;
82 $success = wincache_ucache_set($this->identifierPrefix . $entryIdentifier, $data, $expiration);
83 if ($success === TRUE) {
84 $this->removeIdentifierFromAllTags($entryIdentifier);
85 $this->addIdentifierToTags($entryIdentifier, $tags);
86 } else {
87 throw new \TYPO3\CMS\Core\Cache\Exception('Could not set value.', 1343331523);
88 }
89 }
90
91 /**
92 * Loads data from the cache
93 *
94 * @param string $entryIdentifier An identifier which describes the cache entry to load
95 * @return mixed The cache entry's content as a string or FALSE if the cache entry could not be loaded
96 */
97 public function get($entryIdentifier) {
98 $success = FALSE;
99 $value = wincache_ucache_get($this->identifierPrefix . $entryIdentifier, $success);
100 return $success ? $value : $success;
101 }
102
103 /**
104 * Checks if a cache entry with the specified identifier exists
105 *
106 * @param string $entryIdentifier An identifier specifying the cache entry
107 * @return boolean TRUE if such an entry exists, FALSE if not
108 */
109 public function has($entryIdentifier) {
110 return wincache_ucache_exists($this->identifierPrefix . $entryIdentifier);
111 }
112
113 /**
114 * Removes all cache entries matching the specified identifier.
115 * Usually this only affects one entry but if - for what reason ever -
116 * old entries for the identifier still exist, they are removed as well.
117 *
118 * @param string $entryIdentifier Specifies the cache entry to remove
119 * @return boolean TRUE if (at least) an entry could be removed or FALSE if no entry was found
120 */
121 public function remove($entryIdentifier) {
122 $this->removeIdentifierFromAllTags($entryIdentifier);
123 return wincache_ucache_delete($this->identifierPrefix . $entryIdentifier);
124 }
125
126 /**
127 * Finds and returns all cache entry identifiers which are tagged by the
128 * specified tag.
129 *
130 * @param string $tag The tag to search for
131 * @return array An array with identifiers of all matching entries. An empty array if no entries matched
132 */
133 public function findIdentifiersByTag($tag) {
134 $success = FALSE;
135 $identifiers = wincache_ucache_get($this->identifierPrefix . 'tag_' . $tag, $success);
136 if ($success === FALSE) {
137 return array();
138 } else {
139 return (array) $identifiers;
140 }
141 }
142
143 /**
144 * Finds all tags for the given identifier. This function uses reverse tag
145 * index to search for tags.
146 *
147 * @param string $identifier Identifier to find tags by
148 * @return array Array with tags
149 */
150 protected function findTagsByIdentifier($identifier) {
151 $success = FALSE;
152 $tags = wincache_ucache_get($this->identifierPrefix . 'ident_' . $identifier, $success);
153 return $success ? (array) $tags : array();
154 }
155
156 /**
157 * Removes all cache entries of this cache
158 *
159 * @return void
160 */
161 public function flush() {
162 if (!$this->cache instanceof \TYPO3\CMS\Core\Cache\Frontend\FrontendInterface) {
163 throw new \TYPO3\CMS\Core\Cache\Exception('Yet no cache frontend has been set via setCache().', 1343331524);
164 }
165 $this->flushByTag('%WCBE%' . $this->cache->getIdentifier());
166 }
167
168 /**
169 * Removes all cache entries of this cache which are tagged by the specified
170 * tag.
171 *
172 * @param string $tag The tag the entries must have
173 * @return void
174 */
175 public function flushByTag($tag) {
176 $identifiers = $this->findIdentifiersByTag($tag);
177 foreach ($identifiers as $identifier) {
178 $this->remove($identifier);
179 }
180 }
181
182 /**
183 * Associates the identifier with the given tags
184 *
185 * @param string $entryIdentifier
186 * @param array $tags
187 * @return void
188 */
189 protected function addIdentifierToTags($entryIdentifier, array $tags) {
190 foreach ($tags as $tag) {
191 // Update tag-to-identifier index
192 $identifiers = $this->findIdentifiersByTag($tag);
193 if (array_search($entryIdentifier, $identifiers) === FALSE) {
194 $identifiers[] = $entryIdentifier;
195 wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
196 }
197 // Update identifier-to-tag index
198 $existingTags = $this->findTagsByIdentifier($entryIdentifier);
199 if (array_search($entryIdentifier, $existingTags) === FALSE) {
200 wincache_ucache_set($this->identifierPrefix . 'ident_' . $entryIdentifier, array_merge($existingTags, $tags));
201 }
202 }
203 }
204
205 /**
206 * Removes association of the identifier with the given tags
207 *
208 * @param string $entryIdentifier
209 * @return void
210 */
211 protected function removeIdentifierFromAllTags($entryIdentifier) {
212 // Get tags for this identifier
213 $tags = $this->findTagsByIdentifier($entryIdentifier);
214 // Deassociate tags with this identifier
215 foreach ($tags as $tag) {
216 $identifiers = $this->findIdentifiersByTag($tag);
217 // Formally array_search() below should never return false due to
218 // the behavior of findTagsByIdentifier(). But if reverse index is
219 // corrupted, we still can get 'false' from array_search(). This is
220 // not a problem because we are removing this identifier from
221 // anywhere.
222 if (($key = array_search($entryIdentifier, $identifiers)) !== FALSE) {
223 unset($identifiers[$key]);
224 if (count($identifiers)) {
225 wincache_ucache_set($this->identifierPrefix . 'tag_' . $tag, $identifiers);
226 } else {
227 wincache_ucache_delete($this->identifierPrefix . 'tag_' . $tag);
228 }
229 }
230 }
231 // Clear reverse tag index for this identifier
232 wincache_ucache_delete($this->identifierPrefix . 'ident_' . $entryIdentifier);
233 }
234
235 /**
236 * Does nothing, as wincache does GC itself
237 *
238 * @return void
239 */
240 public function collectGarbage() {
241
242 }
243
244 }