diff --git a/src/Metadata/ApiResource.php b/src/Metadata/ApiResource.php index 1f8a1836fc6..42d3eda932a 100644 --- a/src/Metadata/ApiResource.php +++ b/src/Metadata/ApiResource.php @@ -958,6 +958,7 @@ public function __construct( $provider = null, $processor = null, protected ?OptionsInterface $stateOptions = null, + protected ?bool $throwOnNotFound = null, protected array $extraProperties = [], ) { parent::__construct( @@ -998,6 +999,7 @@ class: $class, provider: $provider, processor: $processor, stateOptions: $stateOptions, + throwOnNotFound: $throwOnNotFound, extraProperties: $extraProperties ); diff --git a/src/Metadata/Delete.php b/src/Metadata/Delete.php index b381971746d..6bebddf5044 100644 --- a/src/Metadata/Delete.php +++ b/src/Metadata/Delete.php @@ -92,6 +92,7 @@ public function __construct( $provider = null, $processor = null, OptionsInterface $stateOptions = null, + bool $throwOnNotFound = null, array $extraProperties = [], ) { parent::__construct( @@ -167,6 +168,7 @@ class: $class, processor: $processor, extraProperties: $extraProperties, collectDenormalizationErrors: $collectDenormalizationErrors, + throwOnNotFound: $throwOnNotFound, stateOptions: $stateOptions, ); } diff --git a/src/Metadata/Get.php b/src/Metadata/Get.php index ad1e6d08408..9ac0d400d3b 100644 --- a/src/Metadata/Get.php +++ b/src/Metadata/Get.php @@ -92,6 +92,7 @@ public function __construct( $provider = null, $processor = null, OptionsInterface $stateOptions = null, + bool $throwOnNotFound = null, array $extraProperties = [], ) { parent::__construct( @@ -166,6 +167,7 @@ class: $class, provider: $provider, processor: $processor, stateOptions: $stateOptions, + throwOnNotFound: $throwOnNotFound, extraProperties: $extraProperties, ); } diff --git a/src/Metadata/GetCollection.php b/src/Metadata/GetCollection.php index b9b2073dabc..be5b55d45aa 100644 --- a/src/Metadata/GetCollection.php +++ b/src/Metadata/GetCollection.php @@ -93,6 +93,7 @@ public function __construct( $processor = null, OptionsInterface $stateOptions = null, array $extraProperties = [], + bool $throwOnNotFound = null, private ?string $itemUriTemplate = null, ) { parent::__construct( @@ -166,8 +167,9 @@ class: $class, name: $name, provider: $provider, processor: $processor, - extraProperties: $extraProperties, + throwOnNotFound: $throwOnNotFound, stateOptions: $stateOptions, + extraProperties: $extraProperties, ); } diff --git a/src/Metadata/HttpOperation.php b/src/Metadata/HttpOperation.php index ed77bb58604..e4d85c38031 100644 --- a/src/Metadata/HttpOperation.php +++ b/src/Metadata/HttpOperation.php @@ -197,6 +197,7 @@ public function __construct( $provider = null, $processor = null, OptionsInterface $stateOptions = null, + bool $throwOnNotFound = null, array $extraProperties = [], ) { parent::__construct( @@ -244,6 +245,7 @@ class: $class, provider: $provider, processor: $processor, stateOptions: $stateOptions, + throwOnNotFound: $throwOnNotFound, extraProperties: $extraProperties ); } diff --git a/src/Metadata/Metadata.php b/src/Metadata/Metadata.php index 0b409ac8c34..4c628eaec87 100644 --- a/src/Metadata/Metadata.php +++ b/src/Metadata/Metadata.php @@ -69,6 +69,7 @@ public function __construct( protected $provider = null, protected $processor = null, protected ?OptionsInterface $stateOptions = null, + protected ?bool $throwOnNotFound = null, protected array $extraProperties = [] ) { } @@ -566,6 +567,19 @@ public function withStateOptions(?OptionsInterface $stateOptions): static return $self; } + public function getThrowOnNotFound(): ?bool + { + return $this->throwOnNotFound; + } + + public function withThrowOnNotFound(bool $throwOnNotFound): bool + { + $self = clone $this; + $self->throwOnNotFound = $throwOnNotFound; + + return $self; + } + public function getExtraProperties(): ?array { return $this->extraProperties; diff --git a/src/Metadata/Operation.php b/src/Metadata/Operation.php index d1f56e98da1..590a0bc5b2f 100644 --- a/src/Metadata/Operation.php +++ b/src/Metadata/Operation.php @@ -799,6 +799,7 @@ public function __construct( protected $provider = null, protected $processor = null, protected ?OptionsInterface $stateOptions = null, + protected ?bool $throwOnNotFound = null, protected array $extraProperties = [], ) { parent::__construct( @@ -839,6 +840,7 @@ class: $class, provider: $provider, processor: $processor, stateOptions: $stateOptions, + throwOnNotFound: $throwOnNotFound, extraProperties: $extraProperties, ); } diff --git a/src/Metadata/Patch.php b/src/Metadata/Patch.php index ba6e61f196a..2d33ef27aca 100644 --- a/src/Metadata/Patch.php +++ b/src/Metadata/Patch.php @@ -91,6 +91,7 @@ public function __construct( string $name = null, $provider = null, $processor = null, + bool $throwOnNotFound = null, OptionsInterface $stateOptions = null, array $extraProperties = [], ) { @@ -167,6 +168,7 @@ class: $class, provider: $provider, processor: $processor, stateOptions: $stateOptions, + throwOnNotFound: $throwOnNotFound, extraProperties: $extraProperties ); } diff --git a/src/Metadata/Post.php b/src/Metadata/Post.php index feba797ab9e..740987cd77d 100644 --- a/src/Metadata/Post.php +++ b/src/Metadata/Post.php @@ -92,6 +92,7 @@ public function __construct( $provider = null, $processor = null, OptionsInterface $stateOptions = null, + bool $throwOnNotFound = null, array $extraProperties = [], private ?string $itemUriTemplate = null ) { @@ -168,6 +169,7 @@ class: $class, provider: $provider, processor: $processor, stateOptions: $stateOptions, + throwOnNotFound: $throwOnNotFound, extraProperties: $extraProperties ); } diff --git a/src/Metadata/Put.php b/src/Metadata/Put.php index 3157ddf1fea..f55ab760e0c 100644 --- a/src/Metadata/Put.php +++ b/src/Metadata/Put.php @@ -92,6 +92,7 @@ public function __construct( $provider = null, $processor = null, OptionsInterface $stateOptions = null, + bool $throwOnNotFound = null, array $extraProperties = [], private ?bool $allowCreate = null, ) { @@ -168,6 +169,7 @@ class: $class, provider: $provider, processor: $processor, stateOptions: $stateOptions, + throwOnNotFound: $throwOnNotFound, extraProperties: $extraProperties ); } diff --git a/src/State/Provider/ReadProvider.php b/src/State/Provider/ReadProvider.php index a8b6d6e21f2..3f3f2e63c14 100644 --- a/src/State/Provider/ReadProvider.php +++ b/src/State/Provider/ReadProvider.php @@ -77,13 +77,7 @@ public function provide(Operation $operation, array $uriVariables = [], array $c $data = null; } - if ( - null === $data - && 'POST' !== $operation->getMethod() - && ('PUT' !== $operation->getMethod() - || ($operation instanceof Put && !($operation->getAllowCreate() ?? false)) - ) - ) { + if (null === $data && $operation->getThrowOnNotFound()) { throw new NotFoundHttpException('Not Found'); } diff --git a/src/Symfony/Controller/MainController.php b/src/Symfony/Controller/MainController.php index d9363848476..56505479b60 100644 --- a/src/Symfony/Controller/MainController.php +++ b/src/Symfony/Controller/MainController.php @@ -19,6 +19,7 @@ use ApiPlatform\Metadata\Error; use ApiPlatform\Metadata\Exception\RuntimeException; use ApiPlatform\Metadata\HttpOperation; +use ApiPlatform\Metadata\Put; use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface; use ApiPlatform\State\ProcessorInterface; use ApiPlatform\State\ProviderInterface; @@ -79,6 +80,15 @@ public function __invoke(Request $request): Response $operation = $operation->withDeserialize(\in_array($operation->getMethod(), ['POST', 'PUT', 'PATCH'], true)); } + if (null === $operation->getThrowOnNotFound() && $operation instanceof HttpOperation) { + $operation->withThrowOnNotFound( + 'POST' !== $operation->getMethod() + && ('PUT' !== $operation->getMethod() + || ($operation instanceof Put && !($operation->getAllowCreate() ?? false)) + ) + ); + } + $body = $this->provider->provide($operation, $uriVariables, $context); // The provider can change the Operation, extract it again from the Request attributes