vendor/api-platform/core/src/Core/Api/IdentifiersExtractor.php line 37

  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\Api\IdentifiersExtractor as NewIdentifiersExtractor;
  13. use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
  14. use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
  15. use ApiPlatform\Exception\RuntimeException;
  16. use ApiPlatform\Util\ResourceClassInfoTrait;
  17. use Symfony\Component\PropertyAccess\PropertyAccess;
  18. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  19. /**
  20.  * {@inheritdoc}
  21.  *
  22.  * @author Antoine Bluchet <soyuka@gmail.com>
  23.  */
  24. final class IdentifiersExtractor implements IdentifiersExtractorInterface
  25. {
  26.     use ResourceClassInfoTrait;
  27.     private $propertyNameCollectionFactory;
  28.     private $propertyMetadataFactory;
  29.     private $propertyAccessor;
  30.     public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactoryPropertyMetadataFactoryInterface $propertyMetadataFactoryPropertyAccessorInterface $propertyAccessor nullResourceClassResolverInterface $resourceClassResolver nullbool $metadataBackwardCompatibilityLayer null)
  31.     {
  32.         $this->propertyNameCollectionFactory $propertyNameCollectionFactory;
  33.         $this->propertyMetadataFactory $propertyMetadataFactory;
  34.         $this->propertyAccessor $propertyAccessor ?? PropertyAccess::createPropertyAccessor();
  35.         $this->resourceClassResolver $resourceClassResolver;
  36.         if (null === $this->resourceClassResolver) {
  37.             @trigger_error(sprintf('Not injecting %s in the IdentifiersExtractor might introduce cache issues with object identifiers.'ResourceClassResolverInterface::class), \E_USER_DEPRECATED);
  38.         }
  39.         if ($metadataBackwardCompatibilityLayer) {
  40.             trigger_deprecation('api-platform/core''2.7'sprintf('The service "%s" is deprecated, use %s instead.'self::class, NewIdentifiersExtractor::class));
  41.         }
  42.     }
  43.     /**
  44.      * {@inheritdoc}
  45.      */
  46.     public function getIdentifiersFromResourceClass(string $resourceClass): array
  47.     {
  48.         $identifiers = [];
  49.         foreach ($properties $this->propertyNameCollectionFactory->create($resourceClass) as $property) {
  50.             if ($this->propertyMetadataFactory->create($resourceClass$property)->isIdentifier() ?? false) {
  51.                 $identifiers[] = $property;
  52.             }
  53.         }
  54.         if (!$identifiers) {
  55.             if (\in_array('id'iterator_to_array($properties), true)) {
  56.                 return ['id'];
  57.             }
  58.             throw new RuntimeException(sprintf('No identifier defined in "%s". You should add #[\ApiPlatform\Core\Annotation\ApiProperty(identifier: true)]" on the property identifying the resource."'$resourceClass));
  59.         }
  60.         return $identifiers;
  61.     }
  62.     /**
  63.      * {@inheritdoc}
  64.      */
  65.     public function getIdentifiersFromItem($item): array
  66.     {
  67.         $identifiers = [];
  68.         $resourceClass $this->getResourceClass($itemtrue);
  69.         $identifierProperties $this->getIdentifiersFromResourceClass($resourceClass);
  70.         foreach ($this->propertyNameCollectionFactory->create($resourceClass) as $propertyName) {
  71.             if (!\in_array($propertyName$identifierPropertiestrue)) {
  72.                 continue;
  73.             }
  74.             $propertyMetadata $this->propertyMetadataFactory->create($resourceClass$propertyName);
  75.             $identifier $identifiers[$propertyName] = $this->propertyAccessor->getValue($item$propertyName);
  76.             if (!\is_object($identifier)) {
  77.                 continue;
  78.             }
  79.             if (null === $relatedResourceClass $this->getResourceClass($identifier)) {
  80.                 continue;
  81.             }
  82.             $relatedItem $identifier;
  83.             unset($identifiers[$propertyName]);
  84.             foreach ($this->propertyNameCollectionFactory->create($relatedResourceClass) as $relatedPropertyName) {
  85.                 $propertyMetadata $this->propertyMetadataFactory->create($relatedResourceClass$relatedPropertyName);
  86.                 if ($propertyMetadata->isIdentifier()) {
  87.                     if (isset($identifiers[$propertyName])) {
  88.                         throw new RuntimeException(sprintf('Composite identifiers not supported in "%s" through relation "%s" of "%s" used as identifier'$relatedResourceClass$propertyName$resourceClass));
  89.                     }
  90.                     $identifiers[$propertyName] = $this->propertyAccessor->getValue($relatedItem$relatedPropertyName);
  91.                 }
  92.             }
  93.             if (!isset($identifiers[$propertyName])) {
  94.                 throw new RuntimeException(sprintf('No identifier found in "%s" through relation "%s" of "%s" used as identifier'$relatedResourceClass$propertyName$resourceClass));
  95.             }
  96.         }
  97.         return $identifiers;
  98.     }
  99. }