Skip to content

Commit 4eeea0d

Browse files
Fix #2759
1 parent 9222ded commit 4eeea0d

File tree

4 files changed

+68
-28
lines changed

4 files changed

+68
-28
lines changed

behat.yml.dist

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ default:
1818
- 'Behat\MinkExtension\Context\MinkContext'
1919
- 'Behatch\Context\RestContext'
2020
filters:
21-
tags: '~@postgres&&~@mongodb&&~@elasticsearch'
21+
tags: '~@postgres&&~@mongodb&&~@elasticsearch&&~@ko'
2222
postgres:
2323
contexts:
2424
- 'DoctrineContext':
@@ -37,7 +37,7 @@ default:
3737
- 'Behat\MinkExtension\Context\MinkContext'
3838
- 'Behatch\Context\RestContext'
3939
filters:
40-
tags: '~@sqlite&&~@mongodb&&~@elasticsearch'
40+
tags: '~@sqlite&&~@mongodb&&~@elasticsearch&&~@ko'
4141
mongodb:
4242
contexts:
4343
- 'DoctrineContext':
@@ -56,7 +56,7 @@ default:
5656
- 'Behat\MinkExtension\Context\MinkContext'
5757
- 'Behatch\Context\RestContext'
5858
filters:
59-
tags: '~@sqlite&&~@elasticsearch&&~@!mongodb'
59+
tags: '~@sqlite&&~@elasticsearch&&~@!mongodb&&~@ko'
6060
elasticsearch:
6161
paths:
6262
- '%paths.base%/features/elasticsearch'
@@ -70,7 +70,7 @@ default:
7070
- 'Behatch\Context\RestContext'
7171
- 'Behat\MinkExtension\Context\MinkContext'
7272
filters:
73-
tags: '@elasticsearch'
73+
tags: '@elasticsearch&&~@ko'
7474
extensions:
7575
'Behat\Symfony2Extension':
7676
kernel:
@@ -106,4 +106,4 @@ coverage:
106106
- 'Behat\MinkExtension\Context\MinkContext'
107107
- 'Behatch\Context\RestContext'
108108
filters:
109-
tags: '~@postgres&&~@mongodb&&~@elasticsearch'
109+
tags: '~@postgres&&~@mongodb&&~@elasticsearch&&~@ko'

features/graphql/non_resource.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# TODO: FIXME: GraphQL support for non-resources is non-existent
2-
2+
@ko
33
Feature: GraphQL non-resource handling
44
In order to use non-resource types
55
As a developer

src/Bridge/Symfony/Routing/RouteNameResolver.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public function getRouteName(string $resourceClass, $operationType /*, array $co
4545

4646
$operationType = OperationTypeDeprecationHelper::getOperationType($operationType);
4747

48+
// Try with strict class name
4849
foreach ($this->router->getRouteCollection()->all() as $routeName => $route) {
4950
$currentResourceClass = $route->getDefault('_api_resource_class');
5051
$operation = $route->getDefault(sprintf('_api_%s_operation_name', $operationType));
@@ -59,6 +60,21 @@ public function getRouteName(string $resourceClass, $operationType /*, array $co
5960
}
6061
}
6162

63+
// Maybe the parent class is a resource
64+
foreach ($this->router->getRouteCollection()->all() as $routeName => $route) {
65+
$currentResourceClass = $route->getDefault('_api_resource_class');
66+
$operation = $route->getDefault(sprintf('_api_%s_operation_name', $operationType));
67+
$methods = $route->getMethods();
68+
69+
if (null !== $currentResourceClass && is_a($resourceClass, $currentResourceClass, true) && null !== $operation && (empty($methods) || \in_array('GET', $methods, true))) {
70+
if (OperationType::SUBRESOURCE === $operationType && false === $this->isSameSubresource($context, $route->getDefault('_api_subresource_context'))) {
71+
continue;
72+
}
73+
74+
return $routeName;
75+
}
76+
}
77+
6278
throw new InvalidArgumentException(sprintf('No %s route associated with the type "%s".', $operationType, $resourceClass));
6379
}
6480

tests/Bridge/Symfony/Routing/RouteNameResolverTest.php

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
use ApiPlatform\Core\Api\OperationType;
1717
use ApiPlatform\Core\Bridge\Symfony\Routing\RouteNameResolver;
1818
use ApiPlatform\Core\Bridge\Symfony\Routing\RouteNameResolverInterface;
19+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\User;
20+
use FOS\UserBundle\Model\User as BaseUser;
1921
use PHPUnit\Framework\TestCase;
2022
use Symfony\Component\Routing\Route;
2123
use Symfony\Component\Routing\RouteCollection;
2224
use Symfony\Component\Routing\RouterInterface;
2325

2426
/**
2527
* @author Teoh Han Hui <[email protected]>
28+
* @author Vincent Chalamon <[email protected]>
2629
*/
2730
class RouteNameResolverTest extends TestCase
2831
{
@@ -38,19 +41,19 @@ public function testConstruct()
3841
public function testGetRouteNameForItemRouteWithNoMatchingRoute()
3942
{
4043
$this->expectException(\InvalidArgumentException::class);
41-
$this->expectExceptionMessage('No item route associated with the type "AppBundle\\Entity\\User".');
44+
$this->expectExceptionMessage('No item route associated with the type "ApiPlatform\\Core\\Tests\\Fixtures\\TestBundle\\Entity\\User".');
4245

4346
$routeCollection = new RouteCollection();
4447
$routeCollection->add('some_collection_route', new Route('/some/collection/path', [
45-
'_api_resource_class' => 'AppBundle\Entity\User',
48+
'_api_resource_class' => User::class,
4649
'_api_collection_operation_name' => 'some_collection_op',
4750
]));
4851

4952
$routerProphecy = $this->prophesize(RouterInterface::class);
5053
$routerProphecy->getRouteCollection()->willReturn($routeCollection);
5154

5255
$routeNameResolver = new RouteNameResolver($routerProphecy->reveal());
53-
$routeNameResolver->getRouteName('AppBundle\Entity\User', OperationType::ITEM);
56+
$routeNameResolver->getRouteName(User::class, OperationType::ITEM);
5457
}
5558

5659
/**
@@ -61,19 +64,19 @@ public function testGetRouteNameForItemRouteLegacy()
6164
{
6265
$routeCollection = new RouteCollection();
6366
$routeCollection->add('some_collection_route', new Route('/some/collection/path', [
64-
'_api_resource_class' => 'AppBundle\Entity\User',
67+
'_api_resource_class' => User::class,
6568
'_api_collection_operation_name' => 'some_collection_op',
6669
]));
6770
$routeCollection->add('some_item_route', new Route('/some/item/path/{id}', [
68-
'_api_resource_class' => 'AppBundle\Entity\User',
71+
'_api_resource_class' => User::class,
6972
'_api_item_operation_name' => 'some_item_op',
7073
]));
7174

7275
$routerProphecy = $this->prophesize(RouterInterface::class);
7376
$routerProphecy->getRouteCollection()->willReturn($routeCollection);
7477

7578
$routeNameResolver = new RouteNameResolver($routerProphecy->reveal());
76-
$actual = $routeNameResolver->getRouteName('AppBundle\Entity\User', false);
79+
$actual = $routeNameResolver->getRouteName(User::class, false);
7780

7881
$this->assertSame('some_item_route', $actual);
7982
}
@@ -82,39 +85,60 @@ public function testGetRouteNameForItemRoute()
8285
{
8386
$routeCollection = new RouteCollection();
8487
$routeCollection->add('some_collection_route', new Route('/some/collection/path', [
85-
'_api_resource_class' => 'AppBundle\Entity\User',
88+
'_api_resource_class' => User::class,
8689
'_api_collection_operation_name' => 'some_collection_op',
8790
]));
8891
$routeCollection->add('some_item_route', new Route('/some/item/path/{id}', [
89-
'_api_resource_class' => 'AppBundle\Entity\User',
92+
'_api_resource_class' => User::class,
9093
'_api_item_operation_name' => 'some_item_op',
9194
]));
9295

9396
$routerProphecy = $this->prophesize(RouterInterface::class);
9497
$routerProphecy->getRouteCollection()->willReturn($routeCollection);
9598

9699
$routeNameResolver = new RouteNameResolver($routerProphecy->reveal());
97-
$actual = $routeNameResolver->getRouteName('AppBundle\Entity\User', OperationType::ITEM);
100+
$actual = $routeNameResolver->getRouteName(User::class, OperationType::ITEM);
101+
102+
$this->assertSame('some_item_route', $actual);
103+
}
104+
105+
public function testGetRouteNameForItemRouteFromAbstract()
106+
{
107+
$routeCollection = new RouteCollection();
108+
$routeCollection->add('some_collection_route', new Route('/some/collection/path', [
109+
'_api_resource_class' => BaseUser::class,
110+
'_api_collection_operation_name' => 'some_collection_op',
111+
]));
112+
$routeCollection->add('some_item_route', new Route('/some/item/path/{id}', [
113+
'_api_resource_class' => BaseUser::class,
114+
'_api_item_operation_name' => 'some_item_op',
115+
]));
116+
117+
$routerProphecy = $this->prophesize(RouterInterface::class);
118+
$routerProphecy->getRouteCollection()->willReturn($routeCollection);
119+
120+
$routeNameResolver = new RouteNameResolver($routerProphecy->reveal());
121+
$actual = $routeNameResolver->getRouteName(User::class, OperationType::ITEM);
98122

99123
$this->assertSame('some_item_route', $actual);
100124
}
101125

102126
public function testGetRouteNameForCollectionRouteWithNoMatchingRoute()
103127
{
104128
$this->expectException(\InvalidArgumentException::class);
105-
$this->expectExceptionMessage('No collection route associated with the type "AppBundle\\Entity\\User".');
129+
$this->expectExceptionMessage('No collection route associated with the type "ApiPlatform\\Core\\Tests\\Fixtures\\TestBundle\\Entity\\User".');
106130

107131
$routeCollection = new RouteCollection();
108132
$routeCollection->add('some_item_route', new Route('/some/item/path/{id}', [
109-
'_api_resource_class' => 'AppBundle\Entity\User',
133+
'_api_resource_class' => User::class,
110134
'_api_item_operation_name' => 'some_item_op',
111135
]));
112136

113137
$routerProphecy = $this->prophesize(RouterInterface::class);
114138
$routerProphecy->getRouteCollection()->willReturn($routeCollection);
115139

116140
$routeNameResolver = new RouteNameResolver($routerProphecy->reveal());
117-
$routeNameResolver->getRouteName('AppBundle\Entity\User', OperationType::COLLECTION);
141+
$routeNameResolver->getRouteName(User::class, OperationType::COLLECTION);
118142
}
119143

120144
/**
@@ -125,19 +149,19 @@ public function testGetRouteNameForCollectionRouteLegacy()
125149
{
126150
$routeCollection = new RouteCollection();
127151
$routeCollection->add('some_item_route', new Route('/some/item/path/{id}', [
128-
'_api_resource_class' => 'AppBundle\Entity\User',
152+
'_api_resource_class' => User::class,
129153
'_api_item_operation_name' => 'some_item_op',
130154
]));
131155
$routeCollection->add('some_collection_route', new Route('/some/collection/path', [
132-
'_api_resource_class' => 'AppBundle\Entity\User',
156+
'_api_resource_class' => User::class,
133157
'_api_collection_operation_name' => 'some_collection_op',
134158
]));
135159

136160
$routerProphecy = $this->prophesize(RouterInterface::class);
137161
$routerProphecy->getRouteCollection()->willReturn($routeCollection);
138162

139163
$routeNameResolver = new RouteNameResolver($routerProphecy->reveal());
140-
$actual = $routeNameResolver->getRouteName('AppBundle\Entity\User', true);
164+
$actual = $routeNameResolver->getRouteName(User::class, true);
141165

142166
$this->assertSame('some_collection_route', $actual);
143167
}
@@ -146,19 +170,19 @@ public function testGetRouteNameForCollectionRoute()
146170
{
147171
$routeCollection = new RouteCollection();
148172
$routeCollection->add('some_item_route', new Route('/some/item/path/{id}', [
149-
'_api_resource_class' => 'AppBundle\Entity\User',
173+
'_api_resource_class' => User::class,
150174
'_api_item_operation_name' => 'some_item_op',
151175
]));
152176
$routeCollection->add('some_collection_route', new Route('/some/collection/path', [
153-
'_api_resource_class' => 'AppBundle\Entity\User',
177+
'_api_resource_class' => User::class,
154178
'_api_collection_operation_name' => 'some_collection_op',
155179
]));
156180

157181
$routerProphecy = $this->prophesize(RouterInterface::class);
158182
$routerProphecy->getRouteCollection()->willReturn($routeCollection);
159183

160184
$routeNameResolver = new RouteNameResolver($routerProphecy->reveal());
161-
$actual = $routeNameResolver->getRouteName('AppBundle\Entity\User', OperationType::COLLECTION);
185+
$actual = $routeNameResolver->getRouteName(User::class, OperationType::COLLECTION);
162186

163187
$this->assertSame('some_collection_route', $actual);
164188
}
@@ -167,25 +191,25 @@ public function testGetRouteNameForSubresourceRoute()
167191
{
168192
$routeCollection = new RouteCollection();
169193
$routeCollection->add('a_some_subresource_route', new Route('/a/some/item/path/{id}', [
170-
'_api_resource_class' => 'AppBundle\Entity\User',
194+
'_api_resource_class' => User::class,
171195
'_api_subresource_operation_name' => 'some_other_item_op',
172196
'_api_subresource_context' => ['identifiers' => [[1, 'bar']]],
173197
]));
174198
$routeCollection->add('b_some_subresource_route', new Route('/b/some/item/path/{id}', [
175-
'_api_resource_class' => 'AppBundle\Entity\User',
199+
'_api_resource_class' => User::class,
176200
'_api_subresource_operation_name' => 'some_item_op',
177201
'_api_subresource_context' => ['identifiers' => [[1, 'foo']]],
178202
]));
179203
$routeCollection->add('some_collection_route', new Route('/some/collection/path', [
180-
'_api_resource_class' => 'AppBundle\Entity\User',
204+
'_api_resource_class' => User::class,
181205
'_api_collection_operation_name' => 'some_collection_op',
182206
]));
183207

184208
$routerProphecy = $this->prophesize(RouterInterface::class);
185209
$routerProphecy->getRouteCollection()->willReturn($routeCollection);
186210

187211
$routeNameResolver = new RouteNameResolver($routerProphecy->reveal());
188-
$actual = $routeNameResolver->getRouteName('AppBundle\Entity\User', OperationType::SUBRESOURCE, ['subresource_resources' => ['foo' => 1]]);
212+
$actual = $routeNameResolver->getRouteName(User::class, OperationType::SUBRESOURCE, ['subresource_resources' => ['foo' => 1]]);
189213

190214
$this->assertSame('b_some_subresource_route', $actual);
191215
}

0 commit comments

Comments
 (0)