diff --git a/features/main/operation.feature b/features/main/operation.feature index b81805498ea..8c70d1c2b99 100644 --- a/features/main/operation.feature +++ b/features/main/operation.feature @@ -55,3 +55,11 @@ Feature: Operation support } } """ + + Scenario: Get the collection of a resource that have disabled item operation + When I send a "GET" request to "/disable_item_operations" + Then the response status code should be 200 + + Scenario: Get a 404 response for the disabled item operation + When I send a "GET" request to "/disable_item_operations/1" + Then the response status code should be 404 diff --git a/src/Action/NotFoundAction.php b/src/Action/NotFoundAction.php new file mode 100644 index 00000000000..465e86e8ad6 --- /dev/null +++ b/src/Action/NotFoundAction.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Action; + +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + +/** + * Not found action. + * + * @author Antoine Bluchet + */ +final class NotFoundAction +{ + public function __invoke() + { + throw new NotFoundHttpException(); + } +} diff --git a/src/Bridge/Symfony/Bundle/Resources/config/api.xml b/src/Bridge/Symfony/Bundle/Resources/config/api.xml index 2508cc8ff92..f34847662f7 100644 --- a/src/Bridge/Symfony/Bundle/Resources/config/api.xml +++ b/src/Bridge/Symfony/Bundle/Resources/config/api.xml @@ -229,6 +229,8 @@ + + diff --git a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php index 620ef4ce6f1..11f23d41b3f 100644 --- a/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php +++ b/tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Tests\Bridge\Symfony\Bundle\DependencyInjection; +use ApiPlatform\Core\Action\NotFoundAction; use ApiPlatform\Core\Api\FilterInterface; use ApiPlatform\Core\Api\IdentifiersExtractorInterface; use ApiPlatform\Core\Api\IriConverterInterface; @@ -843,6 +844,7 @@ private function getPartialContainerBuilderProphecy() 'api_platform.action.documentation', 'api_platform.action.entrypoint', 'api_platform.action.exception', + 'api_platform.action.not_found', 'api_platform.action.placeholder', 'api_platform.cache.identifiers_extractor', 'api_platform.cache.metadata.property', @@ -938,23 +940,24 @@ private function getPartialContainerBuilderProphecy() 'api_platform.property_accessor' => 'property_accessor', 'api_platform.property_info' => 'property_info', 'api_platform.serializer' => 'serializer', - Pagination::class => 'api_platform.pagination', - IriConverterInterface::class => 'api_platform.iri_converter', - UrlGeneratorInterface::class => 'api_platform.router', - SerializerContextBuilderInterface::class => 'api_platform.serializer.context_builder', CollectionDataProviderInterface::class => 'api_platform.collection_data_provider', - ItemDataProviderInterface::class => 'api_platform.item_data_provider', - SubresourceDataProviderInterface::class => 'api_platform.subresource_data_provider', DataPersisterInterface::class => 'api_platform.data_persister', - ResourceNameCollectionFactoryInterface::class => 'api_platform.metadata.resource.name_collection_factory', - ResourceMetadataFactoryInterface::class => 'api_platform.metadata.resource.metadata_factory', + GroupFilter::class => 'api_platform.serializer.group_filter', + IdentifiersExtractorInterface::class => 'api_platform.identifiers_extractor.cached', + IriConverterInterface::class => 'api_platform.iri_converter', + ItemDataProviderInterface::class => 'api_platform.item_data_provider', + NotFoundAction::class => 'api_platform.action.not_found', + OperationAwareFormatsProviderInterface::class => 'api_platform.formats_provider', + Pagination::class => 'api_platform.pagination', + PropertyFilter::class => 'api_platform.serializer.property_filter', PropertyNameCollectionFactoryInterface::class => 'api_platform.metadata.property.name_collection_factory', PropertyMetadataFactoryInterface::class => 'api_platform.metadata.property.metadata_factory', ResourceClassResolverInterface::class => 'api_platform.resource_class_resolver', - PropertyFilter::class => 'api_platform.serializer.property_filter', - GroupFilter::class => 'api_platform.serializer.group_filter', - OperationAwareFormatsProviderInterface::class => 'api_platform.formats_provider', - IdentifiersExtractorInterface::class => 'api_platform.identifiers_extractor.cached', + ResourceNameCollectionFactoryInterface::class => 'api_platform.metadata.resource.name_collection_factory', + ResourceMetadataFactoryInterface::class => 'api_platform.metadata.resource.metadata_factory', + SerializerContextBuilderInterface::class => 'api_platform.serializer.context_builder', + SubresourceDataProviderInterface::class => 'api_platform.subresource_data_provider', + UrlGeneratorInterface::class => 'api_platform.router', ]; foreach ($aliases as $alias => $service) { diff --git a/tests/Fixtures/TestBundle/Document/DisableItemOperation.php b/tests/Fixtures/TestBundle/Document/DisableItemOperation.php new file mode 100644 index 00000000000..4e300aa889e --- /dev/null +++ b/tests/Fixtures/TestBundle/Document/DisableItemOperation.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Document; + +use ApiPlatform\Core\Action\NotFoundAction; +use ApiPlatform\Core\Annotation\ApiResource; +use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; + +/** + * DisableItemOperation. + * + * @ApiResource( + * collectionOperations={ + * "get", + * }, + * itemOperations={ + * "get"={ + * "controller"=NotFoundAction::class, + * "read"=false, + * "output"=false, + * }, + * }, + * ) + * @ODM\Document + */ +class DisableItemOperation +{ + /** + * @ODM\Id(strategy="INCREMENT", type="integer") + */ + private $id; + + /** + * @var string The dummy name + * + * @ODM\Field + */ + public $name; + + public function getId() + { + return $this->id; + } +} diff --git a/tests/Fixtures/TestBundle/Entity/DisableItemOperation.php b/tests/Fixtures/TestBundle/Entity/DisableItemOperation.php new file mode 100644 index 00000000000..2b367cfc3a4 --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/DisableItemOperation.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity; + +use ApiPlatform\Core\Action\NotFoundAction; +use ApiPlatform\Core\Annotation\ApiResource; +use Doctrine\ORM\Mapping as ORM; + +/** + * DisableItemOperation. + * + * @ApiResource( + * collectionOperations={ + * "get", + * }, + * itemOperations={ + * "get"={ + * "controller"=NotFoundAction::class, + * "read"=false, + * "output"=false, + * }, + * }, + * ) + * @ORM\Entity + */ +class DisableItemOperation +{ + /** + * @var int The id + * + * @ORM\Column(type="integer", nullable=true) + * @ORM\Id + * @ORM\GeneratedValue(strategy="AUTO") + */ + private $id; + + /** + * @var string The dummy name + * + * @ORM\Column + */ + public $name; + + public function getId() + { + return $this->id; + } +} diff --git a/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php b/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php index f6e74c1bef4..86e234df469 100644 --- a/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php +++ b/tests/JsonSchema/Command/JsonSchemaGenerateCommandTest.php @@ -68,7 +68,7 @@ public function testExecuteWithTooManyOptions() { $this->tester->run(['command' => 'api:json-schema:generate', 'resource' => $this->entityClass, '--collectionOperation' => 'get', '--itemOperation' => 'get', '--type' => 'output']); - $this->assertStringStartsWith('[ERROR] You can only use one of "--itemOperation" and "--collectionOperation"', trim(str_replace(["\r", "\n"], '', $this->tester->getDisplay()))); + $this->assertStringStartsWith('[ERROR] You can only use one of "--itemOperation" and "--collectionOperation" options at the same time.', trim(preg_replace('/\s+/', ' ', $this->tester->getDisplay()))); } public function testExecuteWithJsonldFormatOption()