9c1069f8357977c79557f936c21b6141a6a3abf4
[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 database tables
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' => $GLOBALS['EXEC_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 >= ' . $GLOBALS['EXEC_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 >= ' . $GLOBALS['EXEC_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 >= ' . $GLOBALS['EXEC_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 >= ' . $GLOBALS['EXEC_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 $listQueryConditions = array();
237 foreach ($tags as $tag) {
238 $listQueryConditions[$tag] = $this->getListQueryForTag($tag);
239 }
240
241 $listQuery = implode(' OR ', $listQueryConditions);
242 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
243 $this->cacheTable,
244 $listQuery
245 );
246 }
247
248 /**
249 * Does garbage collection
250 *
251 * @return void
252 * @author Ingo Renner <ingo@typo3.org>
253 */
254 public function collectGarbage() {
255 $GLOBALS['TYPO3_DB']->exec_DELETEquery(
256 $this->cacheTable,
257 'crdate + lifetime < ' . $GLOBALS['EXEC_TIME'] . ' AND lifetime > 0'
258 );
259 }
260
261 /**
262 * Sets the table where the cache entries are stored. The specified table
263 * must exist already.
264 *
265 * @param string The table.
266 * @return void
267 * @throws t3lib_cache_Exception if the table does not exist.
268 * @author Ingo Renner <ingo@typo3.org>
269 */
270 public function setCacheTable($cacheTable) {
271 /*
272
273 TODO reenable this check or remove it before 4.3 final
274
275 This check causes mysql warnings when not being logged in and calling
276 typo3/backend.php or the install tool.
277 Reason: the caches in typo3/init.php get initialized before a DB connection
278 has been established.
279 Related Question: Why aren't there warnings in the FE as the caches get
280 initialized in tslib_fe's constructor which is also before a DB conection
281 exsits?
282 Assumption Ingo Renner: Is a custom error_reporting level causing that?
283
284 There's also an unit test for that check (also deactivated for now).
285
286 $result = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
287 'id',
288 $cacheTable,
289 '',
290 '',
291 '',
292 1
293 );
294
295 if (!is_array($result)) {
296 throw new t3lib_cache_Exception(
297 'The table "' . $cacheTable . '" does not exist.',
298 1236516444
299 );
300 }
301 */
302 $this->cacheTable = $cacheTable;
303 }
304
305 /**
306 * Returns the table where the cache entries are stored.
307 *
308 * @return string The cache table.
309 * @author Ingo Renner <ingo@typo3.org>
310 */
311 public function getCacheTable() {
312 return $this->cacheTable;
313 }
314
315 /**
316 * Gets the query to be used for selecting entries by a tag. The asterisk ("*")
317 * is allowed as a wildcard at the beginning and the end of a tag.
318 *
319 * @param string The tag to search for, the "*" wildcard is supported
320 * @return string the query to be used for selecting entries
321 * @author Oliver Hader <oliver@typo3.org>
322 */
323 protected function getListQueryForTag($tag) {
324 return str_replace('*', '%', $GLOBALS['TYPO3_DB']->listQuery('tags', $tag, $this->cacheTable));
325 }
326 }
327
328
329 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_dbbackend.php']) {
330 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/cache/backend/class.t3lib_cache_backend_dbbackend.php']);
331 }
332
333 ?>