PropertyInfoCacheExtractor.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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\PropertyInfo;
  11. use Psr\Cache\CacheItemPoolInterface;
  12. /**
  13. * Adds a PSR-6 cache layer on top of an extractor.
  14. *
  15. * @author Kévin Dunglas <dunglas@gmail.com>
  16. *
  17. * @final
  18. */
  19. class PropertyInfoCacheExtractor implements PropertyInfoExtractorInterface, PropertyInitializableExtractorInterface
  20. {
  21. private $propertyInfoExtractor;
  22. private $cacheItemPool;
  23. private $arrayCache = [];
  24. public function __construct(PropertyInfoExtractorInterface $propertyInfoExtractor, CacheItemPoolInterface $cacheItemPool)
  25. {
  26. $this->propertyInfoExtractor = $propertyInfoExtractor;
  27. $this->cacheItemPool = $cacheItemPool;
  28. }
  29. /**
  30. * {@inheritdoc}
  31. */
  32. public function isReadable(string $class, string $property, array $context = []): ?bool
  33. {
  34. return $this->extract('isReadable', [$class, $property, $context]);
  35. }
  36. /**
  37. * {@inheritdoc}
  38. */
  39. public function isWritable(string $class, string $property, array $context = []): ?bool
  40. {
  41. return $this->extract('isWritable', [$class, $property, $context]);
  42. }
  43. /**
  44. * {@inheritdoc}
  45. */
  46. public function getShortDescription(string $class, string $property, array $context = []): ?string
  47. {
  48. return $this->extract('getShortDescription', [$class, $property, $context]);
  49. }
  50. /**
  51. * {@inheritdoc}
  52. */
  53. public function getLongDescription(string $class, string $property, array $context = []): ?string
  54. {
  55. return $this->extract('getLongDescription', [$class, $property, $context]);
  56. }
  57. /**
  58. * {@inheritdoc}
  59. */
  60. public function getProperties(string $class, array $context = []): ?array
  61. {
  62. return $this->extract('getProperties', [$class, $context]);
  63. }
  64. /**
  65. * {@inheritdoc}
  66. */
  67. public function getTypes(string $class, string $property, array $context = []): ?array
  68. {
  69. return $this->extract('getTypes', [$class, $property, $context]);
  70. }
  71. /**
  72. * {@inheritdoc}
  73. */
  74. public function isInitializable(string $class, string $property, array $context = []): ?bool
  75. {
  76. return $this->extract('isInitializable', [$class, $property, $context]);
  77. }
  78. /**
  79. * Retrieves the cached data if applicable or delegates to the decorated extractor.
  80. *
  81. * @return mixed
  82. */
  83. private function extract(string $method, array $arguments)
  84. {
  85. try {
  86. $serializedArguments = serialize($arguments);
  87. } catch (\Exception $exception) {
  88. // If arguments are not serializable, skip the cache
  89. return $this->propertyInfoExtractor->{$method}(...$arguments);
  90. }
  91. // Calling rawurlencode escapes special characters not allowed in PSR-6's keys
  92. $key = rawurlencode($method.'.'.$serializedArguments);
  93. if (\array_key_exists($key, $this->arrayCache)) {
  94. return $this->arrayCache[$key];
  95. }
  96. $item = $this->cacheItemPool->getItem($key);
  97. if ($item->isHit()) {
  98. return $this->arrayCache[$key] = $item->get();
  99. }
  100. $value = $this->propertyInfoExtractor->{$method}(...$arguments);
  101. $item->set($value);
  102. $this->cacheItemPool->save($item);
  103. return $this->arrayCache[$key] = $value;
  104. }
  105. }