17 use Doctrine\DBAL\FetchMode;
69 $this->tagsTable =
'cf_' . $this->cacheIdentifier .
'_tags';
70 $this->maximumLifetime = self::FAKED_UNLIMITED_EXPIRE -
$GLOBALS[
'EXEC_TIME'];
83 public function set($entryIdentifier, $data, array $tags = [], $lifetime =
null)
86 if (!is_string($data)) {
88 'The specified data is of type "' . gettype($data) .
'" but a string is expected.',
92 if ($lifetime ===
null) {
95 if ($lifetime === 0 || $lifetime > $this->maximumLifetime) {
98 $expires =
$GLOBALS[
'EXEC_TIME'] + $lifetime;
99 $this->
remove($entryIdentifier);
100 if ($this->compression) {
101 $data = gzcompress($data, $this->compressionLevel);
103 GeneralUtility::makeInstance(ConnectionPool::class)
104 ->getConnectionForTable($this->cacheTable)
108 'identifier' => $entryIdentifier,
109 'expires' => $expires,
118 foreach ($tags as $tag) {
119 $tagRows[] = [$entryIdentifier, $tag];
121 GeneralUtility::makeInstance(ConnectionPool::class)
122 ->getConnectionForTable($this->tagsTable)
123 ->bulkInsert($this->tagsTable, $tagRows, [
'identifier',
'tag']);
133 public function get($entryIdentifier)
136 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
137 ->getQueryBuilderForTable($this->cacheTable);
138 $cacheRow = $queryBuilder->select(
'content')
139 ->from($this->cacheTable)
141 $queryBuilder->expr()->eq(
143 $queryBuilder->createNamedParameter($entryIdentifier, \PDO::PARAM_STR)
145 $queryBuilder->expr()->gte(
147 $queryBuilder->createNamedParameter(
$GLOBALS[
'EXEC_TIME'], \PDO::PARAM_INT)
153 if (!empty($cacheRow)) {
154 $content = $cacheRow[
'content'];
156 if ($this->compression && (
string)$content !==
'') {
157 $content = gzuncompress($content);
159 return !empty($cacheRow) ? $content :
false;
168 public function has($entryIdentifier)
171 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
172 ->getQueryBuilderForTable($this->cacheTable);
173 $count = $queryBuilder->count(
'*')
174 ->from($this->cacheTable)
176 $queryBuilder->expr()->eq(
178 $queryBuilder->createNamedParameter($entryIdentifier, \PDO::PARAM_STR)
180 $queryBuilder->expr()->gte(
182 $queryBuilder->createNamedParameter(
$GLOBALS[
'EXEC_TIME'], \PDO::PARAM_INT)
197 public function remove($entryIdentifier)
200 $numberOfRowsRemoved = GeneralUtility::makeInstance(ConnectionPool::class)
201 ->getConnectionForTable($this->cacheTable)
204 [
'identifier' => $entryIdentifier]
206 GeneralUtility::makeInstance(ConnectionPool::class)
207 ->getConnectionForTable($this->tagsTable)
210 [
'identifier' => $entryIdentifier]
212 return (
bool)$numberOfRowsRemoved;
224 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
225 ->getQueryBuilderForTable($this->tagsTable);
226 $result = $queryBuilder->select($this->cacheTable .
'.identifier')
227 ->from($this->cacheTable)
228 ->from($this->tagsTable)
230 $queryBuilder->expr()->eq($this->cacheTable .
'.identifier', $queryBuilder->quoteIdentifier($this->tagsTable .
'.identifier')),
231 $queryBuilder->expr()->eq(
232 $this->tagsTable .
'.tag',
233 $queryBuilder->createNamedParameter($tag, \PDO::PARAM_STR)
235 $queryBuilder->expr()->gte(
236 $this->cacheTable .
'.expires',
237 $queryBuilder->createNamedParameter(
$GLOBALS[
'EXEC_TIME'], \PDO::PARAM_INT)
240 ->groupBy($this->cacheTable .
'.identifier')
242 $identifiers = $result->fetchAll(FetchMode::COLUMN, 0);
243 return array_combine($identifiers, $identifiers);
252 GeneralUtility::makeInstance(ConnectionPool::class)
253 ->getConnectionForTable($this->cacheTable)
254 ->truncate($this->cacheTable);
255 GeneralUtility::makeInstance(ConnectionPool::class)
256 ->getConnectionForTable($this->tagsTable)
257 ->truncate($this->tagsTable);
275 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->cacheTable);
279 if (count($tags) > 100) {
280 array_walk(array_chunk($tags, 100), [$this,
'flushByTags']);
286 $quotedTagList = array_map(
function ($value) {
287 return '\'' . $value .
'\'';
294 $connection->executeQuery(
295 'DELETE tags2, cache1'
296 .
' FROM ' . $this->tagsTable .
' AS tags1'
297 .
' JOIN ' . $this->tagsTable .
' AS tags2 ON tags1.identifier = tags2.identifier'
298 .
' JOIN ' . $this->cacheTable .
' AS cache1 ON tags1.identifier = cache1.identifier'
299 .
' WHERE tags1.tag IN (' . implode(
',', $quotedTagList) .
')'
302 $queryBuilder = $connection->createQueryBuilder();
303 $result = $queryBuilder->select(
'identifier')
304 ->from($this->tagsTable)
305 ->where(
'tag IN (' . implode(
',', $quotedTagList) .
')')
307 ->groupBy(
'identifier')
309 $cacheEntryIdentifiers = $result->fetchAll(FetchMode::COLUMN, 0);
310 $quotedIdentifiers = $queryBuilder->createNamedParameter($cacheEntryIdentifiers, Connection::PARAM_STR_ARRAY);
311 $queryBuilder->delete($this->cacheTable)
312 ->where($queryBuilder->expr()->in(
'identifier', $quotedIdentifiers))
314 $queryBuilder->delete($this->tagsTable)
315 ->where($queryBuilder->expr()->in(
'identifier', $quotedIdentifiers))
334 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->cacheTable);
336 $quotedTag =
'\'' . $tag .
'\'';
342 $connection->executeQuery(
343 'DELETE tags2, cache1'
344 .
' FROM ' . $this->tagsTable .
' AS tags1'
345 .
' JOIN ' . $this->tagsTable .
' AS tags2 ON tags1.identifier = tags2.identifier'
346 .
' JOIN ' . $this->cacheTable .
' AS cache1 ON tags1.identifier = cache1.identifier'
347 .
' WHERE tags1.tag = ' . $quotedTag
350 $queryBuilder = $connection->createQueryBuilder();
351 $result = $queryBuilder->select(
'identifier')
352 ->from($this->tagsTable)
353 ->where(
'tag = ' . $quotedTag)
355 ->groupBy(
'identifier')
357 $cacheEntryIdentifiers = $result->fetchAll(FetchMode::COLUMN, 0);
358 $quotedIdentifiers = $queryBuilder->createNamedParameter($cacheEntryIdentifiers, Connection::PARAM_STR_ARRAY);
359 $queryBuilder->delete($this->cacheTable)
360 ->where($queryBuilder->expr()->in(
'identifier', $quotedIdentifiers))
362 $queryBuilder->delete($this->tagsTable)
363 ->where($queryBuilder->expr()->in(
'identifier', $quotedIdentifiers))
375 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->cacheTable);
381 $connection->executeQuery(
383 .
' FROM ' . $this->cacheTable .
' AS cache'
384 .
' LEFT OUTER JOIN ' . $this->tagsTable .
' AS tags ON cache.identifier = tags.identifier'
385 .
' WHERE cache.expires < ?',
389 $connection->executeQuery(
391 .
' FROM ' . $this->tagsTable .
' AS tags'
392 .
' LEFT OUTER JOIN ' . $this->cacheTable .
' as cache ON tags.identifier = cache.identifier'
393 .
' WHERE cache.identifier IS NULL'
396 $queryBuilder = $connection->createQueryBuilder();
397 $result = $queryBuilder->select(
'identifier')
398 ->from($this->cacheTable)
399 ->where($queryBuilder->expr()->lt(
401 $queryBuilder->createNamedParameter(
$GLOBALS[
'EXEC_TIME'], \PDO::PARAM_INT)
404 ->groupBy(
'identifier')
408 $cacheEntryIdentifiers = $result->fetchAll(FetchMode::COLUMN, 0);
409 if (!empty($cacheEntryIdentifiers)) {
411 $quotedIdentifiers = $queryBuilder->createNamedParameter($cacheEntryIdentifiers, Connection::PARAM_STR_ARRAY);
412 $queryBuilder->delete($this->tagsTable)
413 ->where($queryBuilder->expr()->in(
'identifier', $quotedIdentifiers))
416 $queryBuilder->delete($this->cacheTable)
417 ->where($queryBuilder->expr()->lt(
419 $queryBuilder->createNamedParameter(
$GLOBALS[
'EXEC_TIME'], \PDO::PARAM_INT)
424 $queryBuilder = $connection->createQueryBuilder();
425 $result = $queryBuilder->select(
'tags.identifier')
426 ->from($this->tagsTable,
'tags')
431 $queryBuilder->expr()->eq(
'tags.identifier', $queryBuilder->quoteIdentifier(
'cache.identifier'))
433 ->where($queryBuilder->expr()->isNull(
'cache.identifier'))
434 ->groupBy(
'tags.identifier')
436 $tagsEntryIdentifiers = $result->fetchAll(FetchMode::COLUMN, 0);
438 if (!empty($tagsEntryIdentifiers)) {
439 $quotedIdentifiers = $queryBuilder->createNamedParameter($tagsEntryIdentifiers, Connection::PARAM_STR_ARRAY);
440 $queryBuilder->delete($this->tagsTable)
441 ->where($queryBuilder->expr()->in(
'identifier', $quotedIdentifiers))
502 $serverVersion = $connection->getServerVersion();
503 return (
bool)(strpos($serverVersion,
'MySQL') === 0);
513 if (!$this->cache instanceof FrontendInterface) {
514 throw new Exception(
'No cache frontend has been set via setCache() yet.', 1236518288);
527 $cacheTableSql = file_get_contents(
529 'Resources/Private/Sql/Cache/Backend/Typo3DatabaseBackendCache.sql'
531 $requiredTableStructures = str_replace(
'###CACHE_TABLE###', $this->cacheTable, $cacheTableSql) . LF . LF;
532 $tagsTableSql = file_get_contents(
534 'Resources/Private/Sql/Cache/Backend/Typo3DatabaseBackendTags.sql'
536 $requiredTableStructures .= str_replace(
'###TAGS_TABLE###', $this->tagsTable, $tagsTableSql) . LF;
537 return $requiredTableStructures;