Skip to content

Commit 4c9d78a

Browse files
Simperfitdunglas
authored andcommitted
hotfix: add exception when the action is not a builtin action (api-platform#586)
1 parent f2ce400 commit 4c9d78a

File tree

4 files changed

+49
-9
lines changed

4 files changed

+49
-9
lines changed

src/Bridge/Symfony/Bundle/Resources/config/api.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
2626
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
2727
<argument type="service" id="api_platform.routing.resource_path_generator" />
28-
28+
<argument type="service" id="service_container" />
2929
<tag name="routing.loader" />
3030
</service>
3131

src/Bridge/Symfony/Routing/ApiLoader.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Doctrine\Common\Inflector\Inflector;
2020
use Symfony\Component\Config\FileLocator;
2121
use Symfony\Component\Config\Loader\Loader;
22+
use Symfony\Component\DependencyInjection\ContainerInterface;
2223
use Symfony\Component\HttpKernel\KernelInterface;
2324
use Symfony\Component\Routing\Loader\XmlFileLoader;
2425
use Symfony\Component\Routing\Route;
@@ -34,13 +35,16 @@ final class ApiLoader extends Loader
3435
const ROUTE_NAME_PREFIX = 'api_';
3536
const DEFAULT_ACTION_PATTERN = 'api_platform.action.';
3637

38+
private $kernel;
3739
private $fileLoader;
3840
private $resourceNameCollectionFactory;
3941
private $resourceMetadataFactory;
4042
private $resourcePathGenerator;
43+
private $container;
4144

42-
public function __construct(KernelInterface $kernel, ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourcePathGeneratorInterface $resourcePathGenerator)
45+
public function __construct(KernelInterface $kernel, ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourcePathGeneratorInterface $resourcePathGenerator, ContainerInterface $container)
4346
{
47+
$this->container = $container;
4448
$this->fileLoader = new XmlFileLoader(new FileLocator($kernel->locateResource('@ApiPlatformBundle/Resources/config/routing')));
4549
$this->resourceNameCollectionFactory = $resourceNameCollectionFactory;
4650
$this->resourceMetadataFactory = $resourceMetadataFactory;
@@ -108,10 +112,15 @@ private function addRoute(RouteCollection $routeCollection, string $resourceClas
108112
}
109113

110114
$controller = $operation['controller'] ?? null;
111-
$actionName = sprintf('%s_%s', strtolower($operation['method']), $collection ? 'collection' : 'item');
115+
$collectionType = $collection ? 'collection' : 'item';
116+
$actionName = sprintf('%s_%s', strtolower($operation['method']), $collectionType);
112117

113118
if (null === $controller) {
114119
$controller = self::DEFAULT_ACTION_PATTERN.$actionName;
120+
121+
if (!$this->container->has($controller)) {
122+
throw new RuntimeException(sprintf('There is no builtin action for the %s %s operation. You need to define the controller yourself.', $collectionType, $operation['method']));
123+
}
115124
}
116125

117126
if ($operationName !== strtolower($operation['method'])) {

tests/Bridge/Symfony/Routing/ApiLoaderTest.php

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
use ApiPlatform\Core\Routing\ResourcePathGeneratorInterface;
2020
use ApiPlatform\Core\Tests\Fixtures\DummyEntity;
2121
use Prophecy\Argument;
22+
use Symfony\Component\DependencyInjection\ContainerInterface;
2223
use Symfony\Component\HttpKernel\KernelInterface;
2324
use Symfony\Component\Routing\Route;
2425

2526
/**
2627
* @author Antoine Bluchet <soyuka@gmail.com>
28+
* @author Amrouche Hamza <hamza.simperfit@gmail.com>
2729
*/
2830
class ApiLoaderTest extends \PHPUnit_Framework_TestCase
2931
{
@@ -99,6 +101,25 @@ public function testNoMethodApiLoader()
99101
$routeCollection = $this->getApiLoaderWithResourceMetadata($resourceMetadata)->load(null);
100102
}
101103

104+
/**
105+
* @expectedException \RuntimeException
106+
*/
107+
public function testWrongMethodApiLoader()
108+
{
109+
$resourceMetadata = new ResourceMetadata();
110+
$resourceMetadata = $resourceMetadata->withShortName('dummy');
111+
112+
$resourceMetadata = $resourceMetadata->withItemOperations([
113+
'post' => ['method' => 'POST'],
114+
]);
115+
116+
$resourceMetadata = $resourceMetadata->withCollectionOperations([
117+
'get' => ['method' => 'GET'],
118+
]);
119+
120+
$routeCollection = $this->getApiLoaderWithResourceMetadata($resourceMetadata)->load(null);
121+
}
122+
102123
/**
103124
* @expectedException \ApiPlatform\Core\Exception\InvalidResourceException
104125
*/
@@ -113,6 +134,20 @@ private function getApiLoaderWithResourceMetadata(ResourceMetadata $resourceMeta
113134

114135
$kernelProphecy = $this->prophesize(KernelInterface::class);
115136
$kernelProphecy->locateResource(Argument::any())->willReturn($routingConfig);
137+
$possibleArguments = [
138+
'api_platform.action.get_collection',
139+
'api_platform.action.post_collection',
140+
'api_platform.action.get_item',
141+
'api_platform.action.put_item',
142+
'api_platform.action.delete_item',
143+
];
144+
$containerProphecy = $this->prophesize(ContainerInterface::class);
145+
146+
foreach ($possibleArguments as $possibleArgument) {
147+
$containerProphecy->has($possibleArgument)->willReturn(true);
148+
}
149+
150+
$containerProphecy->has(Argument::type('string'))->willReturn(false);
116151

117152
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
118153
$resourceMetadataFactoryProphecy->create(DummyEntity::class)->willReturn($resourceMetadata);
@@ -123,7 +158,7 @@ private function getApiLoaderWithResourceMetadata(ResourceMetadata $resourceMeta
123158
$resourcePathGeneratorProphecy = $this->prophesize(ResourcePathGeneratorInterface::class);
124159
$resourcePathGeneratorProphecy->generateResourceBasePath('dummy')->willReturn('dummies');
125160

126-
$apiLoader = new ApiLoader($kernelProphecy->reveal(), $resourceNameCollectionFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), $resourcePathGeneratorProphecy->reveal());
161+
$apiLoader = new ApiLoader($kernelProphecy->reveal(), $resourceNameCollectionFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), $resourcePathGeneratorProphecy->reveal(), $containerProphecy->reveal());
127162

128163
return $apiLoader;
129164
}

tests/Fixtures/TestBundle/Entity/CustomAttributeDummy.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@
3131
* "normalization_context"={"groups"={"custom_attr_dummy_get"}},
3232
* "denormalization_context"={"groups"={"custom_attr_dummy_get"}}
3333
* },
34-
* "post"={"method"="POST",
35-
* "normalization_context"={"groups"={"custom_attr_dummy_post"}},
36-
* "denormalization_context"={"groups"={"custom_attr_dummy_post"}}
37-
* },
3834
* "put"={"method"="PUT",
3935
* "normalization_context"={"groups"={"custom_attr_dummy_put"}},
4036
* "denormalization_context"={"groups"={"custom_attr_dummy_put"}}
@@ -60,7 +56,7 @@ class CustomAttributeDummy
6056
*
6157
* @ORM\Column
6258
* @Assert\NotBlank
63-
* @Groups({"custom_attr_dummy_read", "custom_attr_dummy_write", "custom_attr_dummy_post", "custom_attr_dummy_get"})
59+
* @Groups({"custom_attr_dummy_read", "custom_attr_dummy_write", "custom_attr_dummy_get"})
6460
* @ApiProperty(iri="http://schema.org/name")
6561
*/
6662
private $name;

0 commit comments

Comments
 (0)