CacheItem.php 5.0 KB

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