Skip to content

Commit 0f608ff

Browse files
Toflardunglas
authored andcommitted
Allow to specify a route prefix per resource (#1685)
* Allow to specify a route prefix per resource * Move routePrefix to attributes * CS * Sanitize path as Symfony does internally too
1 parent 30f76ff commit 0f608ff

File tree

5 files changed

+43
-15
lines changed

5 files changed

+43
-15
lines changed

src/Bridge/Symfony/Routing/ApiLoader.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use ApiPlatform\Core\Exception\RuntimeException;
1919
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
2020
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
21+
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
2122
use ApiPlatform\Core\Operation\Factory\SubresourceOperationFactoryInterface;
2223
use ApiPlatform\Core\PathResolver\OperationPathResolverInterface;
2324
use Symfony\Component\Config\FileLocator;
@@ -91,13 +92,13 @@ public function load($data, $type = null): RouteCollection
9192

9293
if (null !== $collectionOperations = $resourceMetadata->getCollectionOperations()) {
9394
foreach ($collectionOperations as $operationName => $operation) {
94-
$this->addRoute($routeCollection, $resourceClass, $operationName, $operation, $resourceShortName, OperationType::COLLECTION);
95+
$this->addRoute($routeCollection, $resourceClass, $operationName, $operation, $resourceMetadata, OperationType::COLLECTION);
9596
}
9697
}
9798

9899
if (null !== $itemOperations = $resourceMetadata->getItemOperations()) {
99100
foreach ($itemOperations as $operationName => $operation) {
100-
$this->addRoute($routeCollection, $resourceClass, $operationName, $operation, $resourceShortName, OperationType::ITEM);
101+
$this->addRoute($routeCollection, $resourceClass, $operationName, $operation, $resourceMetadata, OperationType::ITEM);
101102
}
102103
}
103104

@@ -170,17 +171,12 @@ private function loadExternalFiles(RouteCollection $routeCollection)
170171
/**
171172
* Creates and adds a route for the given operation to the route collection.
172173
*
173-
* @param RouteCollection $routeCollection
174-
* @param string $resourceClass
175-
* @param string $operationName
176-
* @param array $operation
177-
* @param string $resourceShortName
178-
* @param string $operationType
179-
*
180174
* @throws RuntimeException
181175
*/
182-
private function addRoute(RouteCollection $routeCollection, string $resourceClass, string $operationName, array $operation, string $resourceShortName, string $operationType)
176+
private function addRoute(RouteCollection $routeCollection, string $resourceClass, string $operationName, array $operation, ResourceMetadata $resourceMetadata, string $operationType)
183177
{
178+
$resourceShortName = $resourceMetadata->getShortName();
179+
184180
if (isset($operation['route_name'])) {
185181
return;
186182
}
@@ -197,8 +193,11 @@ private function addRoute(RouteCollection $routeCollection, string $resourceClas
197193
}
198194
}
199195

196+
$path = trim(trim($resourceMetadata->getAttribute('routePrefix', '')), '/');
197+
$path .= $this->operationPathResolver->resolveOperationPath($resourceShortName, $operation, $operationType, $operationName);
198+
200199
$route = new Route(
201-
$this->operationPathResolver->resolveOperationPath($resourceShortName, $operation, $operationType, $operationName),
200+
$path,
202201
[
203202
'_controller' => $controller,
204203
'_format' => null,

tests/Annotation/AnnotatedClass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* itemOperations={"foo":{"bar"}},
2424
* collectionOperations={"bar":{"foo"}},
2525
* graphql={"query"={"normalization_context"={"groups"={"foo", "bar"}}}},
26-
* attributes={"foo":"bar"}
26+
* attributes={"foo":"bar", "routePrefix"="/whatever"},
2727
* )
2828
*
2929
* @author Marcus Speight <marcus@pmconnect.co.uk>

tests/Annotation/ApiResourceTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,6 @@ public function testApiResourceAnnotation()
5151
$this->assertSame('http://example.com/res', $resource->iri);
5252
$this->assertSame(['bar' => ['foo']], $resource->collectionOperations);
5353
$this->assertSame(['query' => ['normalization_context' => ['groups' => ['foo', 'bar']]]], $resource->graphql);
54-
$this->assertSame(['foo' => 'bar'], $resource->attributes);
54+
$this->assertSame(['foo' => 'bar', 'routePrefix' => '/whatever'], $resource->attributes);
5555
}
5656
}

tests/Bridge/Symfony/Routing/ApiLoaderTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,35 @@ public function testApiLoader()
9797
);
9898
}
9999

100+
public function testApiLoaderWithPrefix()
101+
{
102+
$resourceMetadata = new ResourceMetadata();
103+
$resourceMetadata = $resourceMetadata->withShortName('dummy');
104+
$resourceMetadata = $resourceMetadata->withItemOperations([
105+
'get' => ['method' => 'GET', 'requirements' => ['id' => '\d+'], 'defaults' => ['my_default' => 'default_value', '_controller' => 'should_not_be_overriden']],
106+
'put' => ['method' => 'PUT'],
107+
'delete' => ['method' => 'DELETE'],
108+
]);
109+
$resourceMetadata = $resourceMetadata->withAttributes(['routePrefix' => '/foobar-prefix']);
110+
111+
$routeCollection = $this->getApiLoaderWithResourceMetadata($resourceMetadata)->load(null);
112+
113+
$this->assertEquals(
114+
$this->getRoute('/foobar-prefix/dummies/{id}.{_format}', 'api_platform.action.get_item', DummyEntity::class, 'get', ['GET'], false, ['id' => '\d+'], ['my_default' => 'default_value']),
115+
$routeCollection->get('api_dummies_get_item')
116+
);
117+
118+
$this->assertEquals(
119+
$this->getRoute('/foobar-prefix/dummies/{id}.{_format}', 'api_platform.action.delete_item', DummyEntity::class, 'delete', ['DELETE']),
120+
$routeCollection->get('api_dummies_delete_item')
121+
);
122+
123+
$this->assertEquals(
124+
$this->getRoute('/foobar-prefix/dummies/{id}.{_format}', 'api_platform.action.put_item', DummyEntity::class, 'put', ['PUT']),
125+
$routeCollection->get('api_dummies_put_item')
126+
);
127+
}
128+
100129
/**
101130
* @expectedException \RuntimeException
102131
*/

tests/Metadata/Resource/Factory/AnnotationResourceMetadataFactoryTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public function testCreate(ProphecyInterface $reader, ProphecyInterface $decorat
4343
$this->assertEquals(['foo' => ['bar' => true]], $metadata->getItemOperations());
4444
$this->assertEquals(['baz' => ['tab' => false]], $metadata->getCollectionOperations());
4545
$this->assertEquals(['sub' => ['bus' => false]], $metadata->getSubresourceOperations());
46-
$this->assertEquals(['a' => 1], $metadata->getAttributes());
46+
$this->assertEquals(['a' => 1, 'routePrefix' => '/foobar'], $metadata->getAttributes());
4747
$this->assertEquals(['foo' => 'bar'], $metadata->getGraphql());
4848
}
4949

@@ -56,7 +56,7 @@ public function getCreateDependencies()
5656
$annotation->itemOperations = ['foo' => ['bar' => true]];
5757
$annotation->collectionOperations = ['baz' => ['tab' => false]];
5858
$annotation->subresourceOperations = ['sub' => ['bus' => false]];
59-
$annotation->attributes = ['a' => 1];
59+
$annotation->attributes = ['a' => 1, 'routePrefix' => '/foobar'];
6060
$annotation->graphql = ['foo' => 'bar'];
6161

6262
$reader = $this->prophesize(Reader::class);

0 commit comments

Comments
 (0)