diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 4362103f93..f7439903e0 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG * deprecated implementing `Serializable` for `Route` and `CompiledRoute`; if you serialize them, please ensure your unserialization logic can recover from a failure related to an updated serialization format * exposed `utf8` Route option, defaults "locale" and "format" in configuration loaders and configurators + * added support for invokable route loader services 4.2.0 ----- diff --git a/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php b/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php index 8370d576c5..8f0680f02a 100644 --- a/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php +++ b/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php @@ -37,25 +37,25 @@ abstract class ObjectRouteLoader extends Loader /** * Calls the service that will load the routes. * - * @param mixed $resource Some value that will resolve to a callable + * @param string $resource Some value that will resolve to a callable * @param string|null $type The resource type * * @return RouteCollection */ public function load($resource, $type = null) { + if (!preg_match('/^[^\:]+(?:::?(?:[^\:]+))?$/', $resource)) { + throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the "service" route loader: use the format "service::method" or "service" if your service has an "__invoke" method.', $resource)); + } + if (1 === substr_count($resource, ':')) { $resource = str_replace(':', '::', $resource); @trigger_error(sprintf('Referencing service route loaders with a single colon is deprecated since Symfony 4.1. Use %s instead.', $resource), E_USER_DEPRECATED); } $parts = explode('::', $resource); - if (2 != \count($parts)) { - throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the "service" route loader: use the format "service::method"', $resource)); - } - $serviceString = $parts[0]; - $method = $parts[1]; + $method = $parts[1] ?? '__invoke'; $loaderObject = $this->getServiceObject($serviceString); diff --git a/src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php index 0e9289bee4..62ec5261ab 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php @@ -70,7 +70,7 @@ class ObjectRouteLoaderTest extends TestCase * @expectedException \InvalidArgumentException * @dataProvider getBadResourceStrings */ - public function testExceptionWithoutSyntax($resourceString) + public function testExceptionWithoutSyntax(string $resourceString): void { $loader = new ObjectRouteLoaderForTest(); $loader->load($resourceString); @@ -79,8 +79,12 @@ class ObjectRouteLoaderTest extends TestCase public function getBadResourceStrings() { return [ - ['Foo'], ['Foo:Bar:baz'], + ['Foo::Bar::baz'], + ['Foo:'], + ['Foo::'], + [':Foo'], + ['::Foo'], ]; }