1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\Cache; 13 14use Psr\Cache\CacheItemInterface; 15use Psr\Log\LoggerInterface; 16use Symfony\Component\Cache\Exception\InvalidArgumentException; 17 18/** 19 * @author Nicolas Grekas <p@tchwork.com> 20 */ 21final class CacheItem implements CacheItemInterface 22{ 23 protected $key; 24 protected $value; 25 protected $isHit = false; 26 protected $expiry; 27 protected $tags = []; 28 protected $prevTags = []; 29 protected $innerItem; 30 protected $poolHash; 31 32 /** 33 * {@inheritdoc} 34 */ 35 public function getKey() 36 { 37 return $this->key; 38 } 39 40 /** 41 * {@inheritdoc} 42 */ 43 public function get() 44 { 45 return $this->value; 46 } 47 48 /** 49 * {@inheritdoc} 50 */ 51 public function isHit() 52 { 53 return $this->isHit; 54 } 55 56 /** 57 * {@inheritdoc} 58 * 59 * @return $this 60 */ 61 public function set($value) 62 { 63 $this->value = $value; 64 65 return $this; 66 } 67 68 /** 69 * {@inheritdoc} 70 * 71 * @return $this 72 */ 73 public function expiresAt($expiration) 74 { 75 if (null === $expiration) { 76 $this->expiry = null; 77 } elseif ($expiration instanceof \DateTimeInterface) { 78 $this->expiry = (int) $expiration->format('U'); 79 } else { 80 throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given.', \is_object($expiration) ? \get_class($expiration) : \gettype($expiration))); 81 } 82 83 return $this; 84 } 85 86 /** 87 * {@inheritdoc} 88 * 89 * @return $this 90 */ 91 public function expiresAfter($time) 92 { 93 if (null === $time) { 94 $this->expiry = null; 95 } elseif ($time instanceof \DateInterval) { 96 $this->expiry = (int) \DateTime::createFromFormat('U', time())->add($time)->format('U'); 97 } elseif (\is_int($time)) { 98 $this->expiry = $time + time(); 99 } else { 100 throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($time) ? \get_class($time) : \gettype($time))); 101 } 102 103 return $this; 104 } 105 106 /** 107 * Adds a tag to a cache item. 108 * 109 * @param string|string[] $tags A tag or array of tags 110 * 111 * @return $this 112 * 113 * @throws InvalidArgumentException When $tag is not valid 114 */ 115 public function tag($tags) 116 { 117 if (!\is_array($tags)) { 118 $tags = [$tags]; 119 } 120 foreach ($tags as $tag) { 121 if (!\is_string($tag)) { 122 throw new InvalidArgumentException(sprintf('Cache tag must be string, "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag))); 123 } 124 if (isset($this->tags[$tag])) { 125 continue; 126 } 127 if ('' === $tag) { 128 throw new InvalidArgumentException('Cache tag length must be greater than zero.'); 129 } 130 if (false !== strpbrk($tag, '{}()/\@:')) { 131 throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:.', $tag)); 132 } 133 $this->tags[$tag] = $tag; 134 } 135 136 return $this; 137 } 138 139 /** 140 * Returns the list of tags bound to the value coming from the pool storage if any. 141 * 142 * @return array 143 */ 144 public function getPreviousTags() 145 { 146 return $this->prevTags; 147 } 148 149 /** 150 * Validates a cache key according to PSR-6. 151 * 152 * @param string $key The key to validate 153 * 154 * @return string 155 * 156 * @throws InvalidArgumentException When $key is not valid 157 */ 158 public static function validateKey($key) 159 { 160 if (!\is_string($key)) { 161 throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); 162 } 163 if ('' === $key) { 164 throw new InvalidArgumentException('Cache key length must be greater than zero.'); 165 } 166 if (false !== strpbrk($key, '{}()/\@:')) { 167 throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters {}()/\@:.', $key)); 168 } 169 170 return $key; 171 } 172 173 /** 174 * Internal logging helper. 175 * 176 * @internal 177 */ 178 public static function log(LoggerInterface $logger = null, $message, $context = []) 179 { 180 if ($logger) { 181 $logger->warning($message, $context); 182 } else { 183 $replace = []; 184 foreach ($context as $k => $v) { 185 if (is_scalar($v)) { 186 $replace['{'.$k.'}'] = $v; 187 } 188 } 189 @trigger_error(strtr($message, $replace), \E_USER_WARNING); 190 } 191 } 192} 193