vendor/api-platform/core/src/Core/Api/CachedIdentifiersExtractor.php line 39

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of the API Platform project.
  4. *
  5. * (c) Kévin Dunglas <dunglas@gmail.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. declare(strict_types=1);
  11. namespace ApiPlatform\Core\Api;
  12. use ApiPlatform\Util\ResourceClassInfoTrait;
  13. use Psr\Cache\CacheException;
  14. use Psr\Cache\CacheItemPoolInterface;
  15. use Symfony\Component\PropertyAccess\PropertyAccess;
  16. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  17. /**
  18. * {@inheritdoc}
  19. *
  20. * @author Antoine Bluchet <soyuka@gmail.com>
  21. */
  22. final class CachedIdentifiersExtractor implements IdentifiersExtractorInterface
  23. {
  24. use ResourceClassInfoTrait;
  25. public const CACHE_KEY_PREFIX = 'iri_identifiers';
  26. private $cacheItemPool;
  27. private $propertyAccessor;
  28. private $decorated;
  29. private $localCache = [];
  30. private $localResourceCache = [];
  31. public function __construct(CacheItemPoolInterface $cacheItemPool, IdentifiersExtractorInterface $decorated, PropertyAccessorInterface $propertyAccessor = null, ResourceClassResolverInterface $resourceClassResolver = null)
  32. {
  33. $this->cacheItemPool = $cacheItemPool;
  34. $this->propertyAccessor = $propertyAccessor ?? PropertyAccess::createPropertyAccessor();
  35. $this->decorated = $decorated;
  36. $this->resourceClassResolver = $resourceClassResolver;
  37. if (null === $this->resourceClassResolver) {
  38. @trigger_error(sprintf('Not injecting %s in the CachedIdentifiersExtractor might introduce cache issues with object identifiers.', ResourceClassResolverInterface::class), \E_USER_DEPRECATED);
  39. }
  40. }
  41. /**
  42. * {@inheritdoc}
  43. */
  44. public function getIdentifiersFromResourceClass(string $resourceClass): array
  45. {
  46. if (isset($this->localResourceCache[$resourceClass])) {
  47. return $this->localResourceCache[$resourceClass];
  48. }
  49. return $this->localResourceCache[$resourceClass] = $this->decorated->getIdentifiersFromResourceClass($resourceClass);
  50. }
  51. /**
  52. * {@inheritdoc}
  53. */
  54. public function getIdentifiersFromItem($item): array
  55. {
  56. $keys = $this->getKeys($item, function ($item) use (&$identifiers) {
  57. return $identifiers = $this->decorated->getIdentifiersFromItem($item);
  58. });
  59. if (null !== $identifiers) {
  60. return $identifiers;
  61. }
  62. $identifiers = [];
  63. foreach ($keys as $propertyName) {
  64. $identifiers[$propertyName] = $this->propertyAccessor->getValue($item, $propertyName);
  65. if (!\is_object($identifiers[$propertyName])) {
  66. continue;
  67. }
  68. if (null === $relatedResourceClass = $this->getResourceClass($identifiers[$propertyName])) {
  69. continue;
  70. }
  71. if (!$relatedIdentifiers = $this->localCache[$relatedResourceClass] ?? false) {
  72. $relatedCacheKey = self::CACHE_KEY_PREFIX.md5($relatedResourceClass);
  73. try {
  74. $relatedCacheItem = $this->cacheItemPool->getItem($relatedCacheKey);
  75. if (!$relatedCacheItem->isHit()) {
  76. return $this->decorated->getIdentifiersFromItem($item);
  77. }
  78. } catch (CacheException $e) {
  79. return $this->decorated->getIdentifiersFromItem($item);
  80. }
  81. $relatedIdentifiers = $relatedCacheItem->get();
  82. }
  83. $identifiers[$propertyName] = $this->propertyAccessor->getValue($identifiers[$propertyName], $relatedIdentifiers[0]);
  84. }
  85. return $identifiers;
  86. }
  87. private function getKeys($item, callable $retriever): array
  88. {
  89. $resourceClass = $this->getObjectClass($item);
  90. if (isset($this->localCache[$resourceClass])) {
  91. return $this->localCache[$resourceClass];
  92. }
  93. try {
  94. $cacheItem = $this->cacheItemPool->getItem(self::CACHE_KEY_PREFIX.md5($resourceClass));
  95. } catch (CacheException $e) {
  96. return $this->localCache[$resourceClass] = array_keys($retriever($item));
  97. }
  98. if ($cacheItem->isHit()) {
  99. return $this->localCache[$resourceClass] = $cacheItem->get();
  100. }
  101. $keys = array_keys($retriever($item));
  102. $cacheItem->set($keys);
  103. $this->cacheItemPool->save($cacheItem);
  104. return $this->localCache[$resourceClass] = $keys;
  105. }
  106. }