Skip to content

Commit e21e9fa

Browse files
authored
fix: add back support for custom controller with class method (#5681)
* feat: allow defining controller as a class method * chore: cover undefined controller case in test suite
1 parent 0fe4f4d commit e21e9fa

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

src/Symfony/Routing/ApiLoader.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,11 @@ public function load(mixed $data, string $type = null): RouteCollection
8080
$path = str_replace('{._format}', '.{_format}', $path);
8181
}
8282

83-
if (($controller = $operation->getController()) && !$this->container->has($controller)) {
84-
throw new RuntimeException(sprintf('There is no builtin action for the "%s" operation. You need to define the controller yourself.', $operationName));
83+
if ($controller = $operation->getController()) {
84+
$controllerId = explode('::', $controller)[0];
85+
if (!$this->container->has($controllerId)) {
86+
throw new RuntimeException(sprintf('Operation "%s" is defining an unknown service as controller "%s". Make sure it is properly registered in the dependency injection container.', $operationName, $controllerId));
87+
}
8588
}
8689

8790
$route = new Route(

tests/Symfony/Routing/ApiLoaderTest.php

+32
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public function testApiLoader(): void
6464
'api_dummies_my_path_op_collection' => (new GetCollection())->withUriTemplate('some/custom/path'),
6565
// Custom path
6666
'api_dummies_my_stateless_op_collection' => (new GetCollection())->withUriTemplate('/dummies.{_format}')->withStateless(true),
67+
'api_dummies_my_controller_method_item' => (new Get())->withUriTemplate('/foo')->withController('Foo\\Bar\\MyController::method'),
6768
])),
6869
]);
6970

@@ -180,6 +181,21 @@ public function testApiLoader(): void
180181
),
181182
$routeCollection->get('api_dummies_my_stateless_op_collection')
182183
);
184+
185+
$this->assertEquals(
186+
$this->getRoute(
187+
'/foo',
188+
'Foo\\Bar\\MyController::method',
189+
null,
190+
RelatedDummyEntity::class,
191+
[],
192+
'api_dummies_my_controller_method_item',
193+
[],
194+
['GET'],
195+
[]
196+
),
197+
$routeCollection->get('api_dummies_my_controller_method_item')
198+
);
183199
}
184200

185201
public function testApiLoaderWithPrefix(): void
@@ -241,6 +257,20 @@ public function testApiLoaderWithPrefix(): void
241257
);
242258
}
243259

260+
public function testApiLoaderWithUndefinedControllerService(): void
261+
{
262+
$this->expectExceptionObject(new \RuntimeException('Operation "api_dummies_my_undefined_controller_method_item" is defining an unknown service as controller "Foo\\Bar\\MyUndefinedController". Make sure it is properly registered in the dependency injection container.'));
263+
264+
$resourceCollection = new ResourceMetadataCollection(Dummy::class, [
265+
(new ApiResource())->withShortName('dummy')->withOperations(new Operations([
266+
'api_dummies_my_undefined_controller_method_item' => (new Get())->withUriTemplate('/foo')->withController('Foo\\Bar\\MyUndefinedController::method'),
267+
])),
268+
]);
269+
270+
$routeCollection = $this->getApiLoaderWithResourceMetadataCollection($resourceCollection)->load(null);
271+
$routeCollection->get('api_dummies_my_undefined_controller_method_item');
272+
}
273+
244274
private function getApiLoaderWithResourceMetadataCollection(ResourceMetadataCollection $resourceCollection): ApiLoader
245275
{
246276
$routingConfig = __DIR__.'/../../../src/Symfony/Bundle/Resources/config/routing';
@@ -254,12 +284,14 @@ private function getApiLoaderWithResourceMetadataCollection(ResourceMetadataColl
254284
'api_platform.action.get_item',
255285
'api_platform.action.put_item',
256286
'api_platform.action.delete_item',
287+
'Foo\\Bar\\MyController',
257288
];
258289
$containerProphecy = $this->prophesize(ContainerInterface::class);
259290

260291
foreach ($possibleArguments as $possibleArgument) {
261292
$containerProphecy->has($possibleArgument)->willReturn(true);
262293
}
294+
$containerProphecy->has('Foo\\Bar\\MyUndefinedController')->willReturn(false);
263295

264296
$containerProphecy->has(Argument::type('string'))->willReturn(false);
265297

0 commit comments

Comments
 (0)