2cc2674bc295871d1ddc95b897fe359efd6f7508
[Packages/TYPO3.CMS.git] / t3lib / cache / backend / class.t3lib_cache_backend_dbbackend.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2008-2009 Ingo Renner <ingo@typo3.org>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25
26 /**
27 * A caching backend which stores cache entries in files
28 *
29 * @package TYPO3
30 * @subpackage t3lib_cache
31 * @version $Id$
32 */
33 class t3lib_cache_backend_DbBackend extends t3lib_cache_backend_AbstractBackend {
34
35 protected $cacheTable;
36
37 /**
38 * Saves data in a cache file.
39 *
40 * @param string An identifier for this specific cache entry
41 * @param string The data to be stored
42 * @param array Tags to associate with this cache entry
43 * @param integer Lifetime of this cache entry in seconds. If NULL is specified, the default lifetime is used. "0" means unlimited liftime.
44 * @return void
45 * @throws t3lib_cache_Exception if no cache frontend has been set.
46 * @throws t3lib_cache_exception_InvalidData if the data to be stored is not a string.
47 * @author Ingo Renner <ingo@typo3.org>
48 */
49 public function set($entryIdentifier, $data, array $tags = array(), $lifetime = NULL) {
50 if (!$this->cache instanceof t3lib_cache_frontend_Frontend) {
51 throw new t3lib_cache_Exception(
52 'No cache frontend has been set via setCache() yet.',
53 1236518288
54 );
55 }
56
57 if (!is_string($data)) {
58 throw new t3lib_cache_exception_InvalidData(
59 'The specified data is of type "' . gettype($data) . '" but a string is expected.',
60 1236518298
61 );
62 }
63
64 if (is_null($lifetime)) {
65 $lifetime = $this->defaultLifetime;
66 }
67
68 $this->remove($entryIdentifier);
69
70 $GLOBALS['TYPO3_DB']->exec_INSERTquery(
71 $this->cacheTable,
72 array(
73 'identifier' => $entryIdentifier,
74 'crdate' => time(),
75 'content' => $data,
76 'tags' => implode(',', $tags),
77 'lifetime' => $lifetime
78 )
79 );
80 }
81
82 /**
83 * Loads data from a cache file.
84 *
85 * @param string An identifier which describes the cache entry to load
86 * @return mixed The cache entry's data as a string or FALSE if the cache entry could not be loaded
87 * @author Ingo Renner <ingo@typo3.org>
88 */
89 public function get($entryIdentifier) {
90 $cacheEntry = false;
91
92 $cacheEntries = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
93 'content',
94 $this->cacheTable,
95 'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable) . ' '
96 . 'AND (crdate + lifetime >= ' . time() . ' OR lifetime = 0)'
97 );
98
99 if (count($cacheEntries) == 1) {
100 $cacheEntry = $cacheEntries[0]['content'];
101 }
102
103 return $cacheEntry;
104 }
105
106 /**
107 * Checks if a cache entry with the specified identifier exists.
108 *
109 * @param unknown_type
110 * @return boolean TRUE if such an entry exists, FALSE if not
111 * @author Ingo Renner <ingo@typo3.org>
112 */
113 public function has($entryIdentifier) {
114 $hasEntry = false;
115
116 $cacheEntries = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
117 'content',
118 $this->cacheTable,
119 'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable) . ' '
120 . 'AND crdate + lifetime >= ' . time()
121 );
122
123 if (count($cacheEntries) == 1) {
124 $hasEntry = true;
125 }
126
127 return $hasEntry;
128 }
129
130 /**
131 * Removes all cache entries matching the specified identifier.
132 * Usually this only affects one entry.
133 *
134 * @param string Specifies the cache entry to remove
135 * @return boolean TRUE if (at least) an entry could be removed or FALSE if no entry was found
136 * @author Ingo Renner <ingo@typo3.org>
137 */
138 public function remove($entryIdentifier) {
139 $entryRemoved = false;
140
141 $res = $GLOBALS['TYPO3_DB']->exec_DELETEquery(
142 $this->cacheTable,
143 'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($entryIdentifier, $this->cacheTable)
144 );
145
146 if($GLOBALS['TYPO3_DB']->sql_affected_rows($res) == 1) {
147 $entryRemoved = true;
148 }
149
150 return $entryRemoved;
151 }
152
153 /**
154 * Finds and returns all cache entries which are tagged by the specified tag.
155 *
156 * @param string The tag to search for
157 * @return array An array with identifiers of all matching entries. An empty array if no entries matched
158 * @author Ingo Renner <ingo@typo3.org>
159 */
160 public function findIdentifiersByTag($tag) {
161 $cacheEntryIdentifiers = array();
162
163 $cacheEntryIdentifierRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
164 'identifier',
165 $this->cacheTable,
166 $this->getListQueryForTag($tag) . ' AND (crdate + lifetime >= ' . time() . ' OR lifetime = 0)'
167 );
168
169 foreach ($cacheEntryIdentifierRows as $cacheEntryIdentifierRow) {
170 $cacheEntryIdentifiers[$cacheEntryIdentifierRow['identifier']] = $cacheEntryIdentifierRow['identifier'];
171 }
172
173 return $cacheEntryIdentifiers;
174 }
175
176 /**
177 * Finds and returns all cache entry identifiers which are tagged by the
178 * specified tags.
179 *
180 * @param array Array of tags to search for
181 * @return array An array with identifiers of all matching entries. An empty array if no entries matched
182 * @author Ingo Renner <ingo@typo3.org>
183 */
184 public function findIdentifiersByTags(array $tags) {
185 $cacheEntryIdentifiers = array();
186 $whereClause = array();
187
188 foreach ($tags as $tag) {
189 $whereClause[] = $this->getListQueryForTag($tag);
190 }
191 $whereClause[] = '(crdate + lifetime >= ' . time() . ' OR lifetime = 0)';
192
193 $cacheEntryIdentifierRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
194 'identifier',
195 $this->cacheTable,
196 implode(' AND ', $whereClause)
197 );
198
199 foreach ($cacheEntryIdentifierRows as $cacheEntryIdentifierRow) {
200 $cacheEntryIdentifiers[$cacheEntryIdentifierRow['identifier']] = $cacheEntryIdentifierRow['identifier'];
201 }
202
203 return $cacheEntryIdentifiers;
204 }
205
206 /**
207 * Removes all cache entries of this cache.
208 *
209 * @return void
210 * @author Ingo Renner <ingo@typo3.org>
211 */
212 public function flush() {
213 $GLOBALS['TYPO3_DB']->sql_query('TRUNCATE ' . $this->cacheTable);
214 }
215
216 /**
217 * Removes all cache entries of this cache which are tagged by the specified tag.
218 *
219 * @param string The tag the entries must have
220 * @return void
221 */
222 public function flushByTag($tag) {
223 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
224 $this->cacheTable,
225 $this->getListQueryForTag($tag)
226 );
227 }
228
229 /**
230 * Removes all cache entries of this cache which are tagged by the specified tags.
231 *
232 * @param array The tags the entries must have
233 * @return void
234 */
235 public function flushByTags(array $tags) {
236 $tmpListQuery = array();
237 foreach ($tags as $tag) {
238 $tmpListQuery[$tag] = $this->getListQueryForTag($tag);
239 }
240 $listQuery = implode(' OR ',$tmpListQuery);
241 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
242 $this->cacheTable,
243 $listQuery
244 );
245 }
246
247 /**
248 * Does garbage collection
249 *
250 * @return void
251 * @author Ingo Renner <ingo@typo3.org>
252 */
253 public function collectGarbage() {
254 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
255 $this->cacheTable,
256 'crdate + lifetime < ' . time() . ' AND lifetime > 0'
257 );
258 }
259
260 /**
261 * Sets the table where the cache entries are stored. The specified table
262 * must exist already.
263 *
264 * @param string The table.
265 * @return void
266 * @throws t3lib_cache_Exception if the table does not exist.
267 * @author Ingo Renner <ingo@typo3.org>
268 */
269 public function setCacheTable($cacheTable) {
270 /*
271
272 TODO reenable this check or remove it before 4.3 final
273
274 This check causes mysql warnings when not being logged in and calling
275 typo3/backend.php or the install tool.
276 Reason: the caches in typo3/init.php get initialized before a DB connection
277 has been established.
278 Related Question: Why aren't there warnings in the FE as the caches get
279 initialized in tslib_fe's constructor which is also before a DB conection
280 exsits?
281 Assumption Ingo Renner: Is a custom error_reporting level causing that?
282
283 There's also an unit test for that check (also deactivated for now).
284
285 $result = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
286 'id',
287 $cacheTable,
288 '',
289 '',
290 '',
291 1
292 );
293
294 if (!is_array($result)) {
295 throw new t3lib_cache_Exception(
296 'The table "' . $cacheTable . '" does not exist.',
297 1236516444
298 );
299 }
300 */
301 $this->cacheTable = $cacheTable;
302 }
303
304 /**
305 * Returns the table where the cache entries are stored.
306 *
307 * @return string The cache table.
308 * @author Ingo Renner <ingo@typo3.org>
309 */
310 public function getCacheTable() {
311 return $this->cacheTable;
312 }
313
314 /**
315 * Gets the query to be used for selecting entries by a tag. The asterisk ("*")
316 * is allowed as a wildcard at the beginning and the end of a tag.
317 *
318 * @param string The tag to search for, the "*" wildcard is supported
319 * @return string the query to be used for selecting entries
320 * @author Oliver Hader <oliver@typo3.org>
321 */
322 protected function getListQueryForTag($tag) {
323 return str_replace('*', '%', $GLOBALS['TYPO3_DB']->listQuery('tags', $tag, $this->cacheTable));
324 }
325 }
326
327
328 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_dbbackend.php']) {
329 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_dbbackend.php']);
330 }
331
332 ?>