2 namespace TYPO3\CMS\Core\Cache\Backend;
127 if (!extension_loaded(
'redis')) {
128 throw new \TYPO3\CMS\Core\Cache\Exception(
'The PHP extension "redis" must be installed and loaded in order to use the redis backend.', 1279462933);
130 parent::__construct(
$context, $options);
141 $this->redis = new \Redis();
143 $this->connected = $this->redis->connect($this->hostname, $this->
port);
147 if ($this->connected) {
148 if ($this->password !==
'') {
149 $success = $this->redis->auth($this->password);
151 throw new \TYPO3\CMS\Core\Cache\Exception(
'The given password was not accepted by the redis server.', 1279765134);
154 if ($this->database > 0) {
155 $success = $this->redis->select($this->database);
157 throw new \TYPO3\CMS\Core\Cache\Exception(
'The given database "' . $this->database .
'" could not be selected.', 1279765144);
198 throw new \InvalidArgumentException(
'The specified database number is of type "' . gettype(
$database) .
'" but an integer is expected.', 1279763057);
201 throw new \InvalidArgumentException(
'The specified database "' .
$database .
'" must be greater or equal than zero.', 1279763534);
229 throw new \InvalidArgumentException(
'The specified compression of type "' . gettype(
$compression) .
'" but a boolean is expected.', 1289679153);
247 throw new \InvalidArgumentException(
'The specified compression of type "' . gettype(
$compressionLevel) .
'" but an integer is expected.', 1289679154);
252 throw new \InvalidArgumentException(
'The specified compression level must be an integer between -1 and 9.', 1289679155);
271 public function set($entryIdentifier, $data, array $tags = array(), $lifetime = null)
274 throw new \InvalidArgumentException(
'The specified identifier is of type "' . gettype($entryIdentifier) .
'" which can\'t be converted to string.', 1377006651);
276 if (!is_string($data)) {
277 throw new \TYPO3\CMS\Core\Cache\Exception\InvalidDataException(
'The specified data is of type "' . gettype($data) .
'" but a string is expected.', 1279469941);
279 $lifetime = $lifetime === null ? $this->defaultLifetime : $lifetime;
280 if (!is_integer($lifetime)) {
281 throw new \InvalidArgumentException(
'The specified lifetime is of type "' . gettype($lifetime) .
'" but an integer or NULL is expected.', 1279488008);
284 throw new \InvalidArgumentException(
'The specified lifetime "' . $lifetime .
'" must be greater or equal than zero.', 1279487573);
286 if ($this->connected) {
287 $expiration = $lifetime === 0 ? self::FAKED_UNLIMITED_LIFETIME : $lifetime;
288 if ($this->compression) {
289 $data = gzcompress($data, $this->compressionLevel);
291 $this->redis->setex(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier, $expiration, $data);
293 $removeTags = array();
294 $existingTags = $this->redis->sMembers(self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier);
295 if (!empty($existingTags)) {
296 $addTags = array_diff($tags, $existingTags);
297 $removeTags = array_diff($existingTags, $tags);
299 if (!empty($removeTags) || !empty($addTags)) {
300 $queue = $this->redis->multi(\Redis::PIPELINE);
301 foreach ($removeTags as $tag) {
302 $queue->sRemove(self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier, $tag);
303 $queue->sRemove(self::TAG_IDENTIFIERS_PREFIX . $tag, $entryIdentifier);
305 foreach ($addTags as $tag) {
306 $queue->sAdd(self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier, $tag);
307 $queue->sAdd(self::TAG_IDENTIFIERS_PREFIX . $tag, $entryIdentifier);
324 public function get($entryIdentifier)
327 throw new \InvalidArgumentException(
'The specified identifier is of type "' . gettype($entryIdentifier) .
'" which can\'t be converted to string.', 1377006652);
329 $storedEntry =
false;
330 if ($this->connected) {
331 $storedEntry = $this->redis->get(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier);
333 if ($this->compression && (
string)$storedEntry !==
'') {
334 $storedEntry = gzuncompress($storedEntry);
349 public function has($entryIdentifier)
352 throw new \InvalidArgumentException(
'The specified identifier is of type "' . gettype($entryIdentifier) .
'" which can\'t be converted to string.', 1377006653);
354 return $this->connected && $this->redis->exists(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier);
368 public function remove($entryIdentifier)
371 throw new \InvalidArgumentException(
'The specified identifier is of type "' . gettype($entryIdentifier) .
'" which can\'t be converted to string.', 1377006654);
373 $elementsDeleted =
false;
374 if ($this->connected) {
375 if ($this->redis->exists(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier)) {
376 $assignedTags = $this->redis->sMembers(self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier);
377 $queue = $this->redis->multi(\Redis::PIPELINE);
378 foreach ($assignedTags as $tag) {
379 $queue->sRemove(self::TAG_IDENTIFIERS_PREFIX . $tag, $entryIdentifier);
381 $queue->delete(self::IDENTIFIER_DATA_PREFIX . $entryIdentifier, self::IDENTIFIER_TAGS_PREFIX . $entryIdentifier);
383 $elementsDeleted =
true;
386 return $elementsDeleted;
404 throw new \InvalidArgumentException(
'The specified tag is of type "' . gettype($tag) .
'" which can\'t be converted to string.', 1377006655);
406 $foundIdentifiers = array();
407 if ($this->connected) {
408 $foundIdentifiers = $this->redis->sMembers(self::TAG_IDENTIFIERS_PREFIX . $tag);
410 return $foundIdentifiers;
423 if ($this->connected) {
424 $this->redis->flushdb();
442 throw new \InvalidArgumentException(
'The specified tag is of type "' . gettype($tag) .
'" which can\'t be converted to string.', 1377006656);
444 if ($this->connected) {
445 $identifiers = $this->redis->sMembers(self::TAG_IDENTIFIERS_PREFIX . $tag);
446 if (!empty($identifiers)) {
465 $identifierToTagsKeys = $this->redis->getKeys(self::IDENTIFIER_TAGS_PREFIX .
'*');
466 foreach ($identifierToTagsKeys as $identifierToTagsKey) {
467 list(, $identifier) = explode(
':', $identifierToTagsKey);
469 if (!$this->redis->exists((self::IDENTIFIER_DATA_PREFIX . $identifier))) {
470 $tagsToRemoveIdentifierFrom = $this->redis->sMembers($identifierToTagsKey);
471 $queue = $this->redis->multi(\Redis::PIPELINE);
472 $queue->delete($identifierToTagsKey);
473 foreach ($tagsToRemoveIdentifierFrom as $tag) {
474 $queue->sRemove(self::TAG_IDENTIFIERS_PREFIX . $tag, $identifier);
497 $prefixedKeysToDelete = array($uniqueTempKey);
498 $prefixedIdentifierToTagsKeysToDelete = array();
499 foreach ($identifiers as $identifier) {
500 $prefixedKeysToDelete[] = self::IDENTIFIER_DATA_PREFIX . $identifier;
501 $prefixedIdentifierToTagsKeysToDelete[] = self::IDENTIFIER_TAGS_PREFIX . $identifier;
503 foreach ($tags as $tag) {
504 $prefixedKeysToDelete[] = self::TAG_IDENTIFIERS_PREFIX . $tag;
506 $tagToIdentifiersSetsToRemoveIdentifiersFrom = $this->redis->sUnion($prefixedIdentifierToTagsKeysToDelete);
508 $tagToIdentifiersSetsToRemoveIdentifiersFrom = array_diff($tagToIdentifiersSetsToRemoveIdentifiersFrom, $tags);
511 $queue = $this->redis->multi(\Redis::PIPELINE);
512 foreach ($identifiers as $identifier) {
513 $queue->sAdd($uniqueTempKey, $identifier);
515 foreach ($tagToIdentifiersSetsToRemoveIdentifiersFrom as $tagToIdentifiersSet) {
516 $queue->sDiffStore(self::TAG_IDENTIFIERS_PREFIX . $tagToIdentifiersSet, self::TAG_IDENTIFIERS_PREFIX . $tagToIdentifiersSet, $uniqueTempKey);
518 $queue->delete(array_merge($prefixedKeysToDelete, $prefixedIdentifierToTagsKeysToDelete));
530 return is_scalar($variable) || (is_object($variable) && method_exists($variable,
'__toString'));