vendor/api-platform/core/src/Core/Bridge/Symfony/Routing/IriConverter.php line 137

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\Bridge\Symfony\Routing;
  12. use ApiPlatform\Core\Api\IdentifiersExtractor;
  13. use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
  14. use ApiPlatform\Core\Api\IriConverterInterface;
  15. use ApiPlatform\Core\Api\OperationType;
  16. use ApiPlatform\Core\Api\ResourceClassResolverInterface;
  17. use ApiPlatform\Core\Api\UrlGeneratorInterface;
  18. use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
  19. use ApiPlatform\Core\DataProvider\OperationDataProviderTrait;
  20. use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface;
  21. use ApiPlatform\Core\Identifier\CompositeIdentifierParser;
  22. use ApiPlatform\Core\Identifier\IdentifierConverterInterface;
  23. use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
  24. use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
  25. use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
  26. use ApiPlatform\Exception\InvalidArgumentException;
  27. use ApiPlatform\Exception\InvalidIdentifierException;
  28. use ApiPlatform\Exception\ItemNotFoundException;
  29. use ApiPlatform\Exception\RuntimeException;
  30. use ApiPlatform\Symfony\Routing\IriConverter as NewIriConverter;
  31. use ApiPlatform\Util\AttributesExtractor;
  32. use ApiPlatform\Util\ResourceClassInfoTrait;
  33. use Symfony\Component\PropertyAccess\PropertyAccess;
  34. use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
  35. use Symfony\Component\Routing\Exception\ExceptionInterface as RoutingExceptionInterface;
  36. use Symfony\Component\Routing\RouterInterface;
  37. /**
  38. * {@inheritdoc}
  39. *
  40. * @author Kévin Dunglas <dunglas@gmail.com>
  41. */
  42. final class IriConverter implements IriConverterInterface
  43. {
  44. use OperationDataProviderTrait;
  45. use ResourceClassInfoTrait;
  46. private $routeNameResolver;
  47. private $router;
  48. private $identifiersExtractor;
  49. public function __construct(PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ItemDataProviderInterface $itemDataProvider, RouteNameResolverInterface $routeNameResolver, RouterInterface $router, PropertyAccessorInterface $propertyAccessor = null, IdentifiersExtractorInterface $identifiersExtractor = null, SubresourceDataProviderInterface $subresourceDataProvider = null, IdentifierConverterInterface $identifierConverter = null, ResourceClassResolverInterface $resourceClassResolver = null, ResourceMetadataFactoryInterface $resourceMetadataFactory = null)
  50. {
  51. $this->itemDataProvider = $itemDataProvider;
  52. $this->routeNameResolver = $routeNameResolver;
  53. $this->router = $router;
  54. $this->subresourceDataProvider = $subresourceDataProvider;
  55. $this->identifierConverter = $identifierConverter;
  56. $this->resourceClassResolver = $resourceClassResolver;
  57. $this->identifiersExtractor = $identifiersExtractor ?: new IdentifiersExtractor($propertyNameCollectionFactory, $propertyMetadataFactory, $propertyAccessor ?? PropertyAccess::createPropertyAccessor());
  58. $this->resourceMetadataFactory = $resourceMetadataFactory;
  59. trigger_deprecation('api-platform/core', '2.7', sprintf('The service "%s" is deprecated, use %s instead.', self::class, NewIriConverter::class));
  60. }
  61. /**
  62. * {@inheritdoc}
  63. *
  64. * @return object
  65. */
  66. public function getItemFromIri(string $iri, array $context = [])
  67. {
  68. try {
  69. $parameters = $this->router->match($iri);
  70. } catch (RoutingExceptionInterface $e) {
  71. throw new InvalidArgumentException(sprintf('No route matches "%s".', $iri), $e->getCode(), $e);
  72. }
  73. if (!isset($parameters['_api_resource_class'])) {
  74. throw new InvalidArgumentException(sprintf('No resource associated to "%s".', $iri));
  75. }
  76. if (isset($parameters['_api_collection_operation_name'])) {
  77. throw new InvalidArgumentException(sprintf('The iri "%s" references a collection not an item.', $iri));
  78. }
  79. $attributes = AttributesExtractor::extractAttributes($parameters);
  80. try {
  81. $identifiers = $this->extractIdentifiers($parameters, $attributes);
  82. } catch (InvalidIdentifierException $e) {
  83. throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e);
  84. }
  85. if ($this->identifierConverter) {
  86. $context[IdentifierConverterInterface::HAS_IDENTIFIER_CONVERTER] = true;
  87. }
  88. if (isset($attributes['subresource_operation_name'])) {
  89. if (($item = $this->getSubresourceData($identifiers, $attributes, $context)) && !\is_array($item)) {
  90. return $item;
  91. }
  92. throw new ItemNotFoundException(sprintf('Item not found for "%s".', $iri));
  93. }
  94. if ($item = $this->getItemData($identifiers, $attributes, $context)) {
  95. return $item;
  96. }
  97. throw new ItemNotFoundException(sprintf('Item not found for "%s".', $iri));
  98. }
  99. /**
  100. * {@inheritdoc}
  101. */
  102. public function getIriFromItem($item, int $referenceType = null): string
  103. {
  104. $resourceClass = $this->getResourceClass($item, true);
  105. try {
  106. $identifiers = $this->identifiersExtractor->getIdentifiersFromItem($item);
  107. } catch (RuntimeException $e) {
  108. throw new InvalidArgumentException(sprintf('Unable to generate an IRI for the item of type "%s"', $resourceClass), $e->getCode(), $e);
  109. }
  110. return $this->getItemIriFromResourceClass($resourceClass, $identifiers, $this->getReferenceType($resourceClass, $referenceType));
  111. }
  112. /**
  113. * {@inheritdoc}
  114. */
  115. public function getIriFromResourceClass(string $resourceClass, int $referenceType = null): string
  116. {
  117. try {
  118. return $this->router->generate($this->routeNameResolver->getRouteName($resourceClass, OperationType::COLLECTION), [], $this->getReferenceType($resourceClass, $referenceType));
  119. } catch (RoutingExceptionInterface $e) {
  120. throw new InvalidArgumentException(sprintf('Unable to generate an IRI for "%s".', $resourceClass), $e->getCode(), $e);
  121. }
  122. }
  123. /**
  124. * {@inheritdoc}
  125. */
  126. public function getItemIriFromResourceClass(string $resourceClass, array $identifiers, int $referenceType = null): string
  127. {
  128. $routeName = $this->routeNameResolver->getRouteName($resourceClass, OperationType::ITEM);
  129. $metadata = $this->resourceMetadataFactory->create($resourceClass);
  130. if (\count($identifiers) > 1 && true === $metadata->getAttribute('composite_identifier', true)) {
  131. $identifiers = ['id' => CompositeIdentifierParser::stringify($identifiers)];
  132. }
  133. try {
  134. return $this->router->generate($routeName, $identifiers, $this->getReferenceType($resourceClass, $referenceType));
  135. } catch (RoutingExceptionInterface $e) {
  136. throw new InvalidArgumentException(sprintf('Unable to generate an IRI for "%s".', $resourceClass), $e->getCode(), $e);
  137. }
  138. }
  139. /**
  140. * {@inheritdoc}
  141. */
  142. public function getSubresourceIriFromResourceClass(string $resourceClass, array $context, int $referenceType = null): string
  143. {
  144. try {
  145. return $this->router->generate($this->routeNameResolver->getRouteName($resourceClass, OperationType::SUBRESOURCE, $context), $context['subresource_identifiers'], $this->getReferenceType($resourceClass, $referenceType));
  146. } catch (RoutingExceptionInterface $e) {
  147. throw new InvalidArgumentException(sprintf('Unable to generate an IRI for "%s".', $resourceClass), $e->getCode(), $e);
  148. }
  149. }
  150. private function getReferenceType(string $resourceClass, ?int $referenceType): ?int
  151. {
  152. if (null === $referenceType && null !== $this->resourceMetadataFactory) {
  153. $metadata = $this->resourceMetadataFactory->create($resourceClass);
  154. $referenceType = $metadata->getAttribute('url_generation_strategy');
  155. }
  156. return $referenceType ?? UrlGeneratorInterface::ABS_PATH;
  157. }
  158. }