8000 [Routing] Deprecate ServiceRouterLoader and ObjectRouteLoader in favo… · symfony/symfony@2593241 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2593241

Browse files
committed
[Routing] Deprecate ServiceRouterLoader and ObjectRouteLoader in favor of ContainerLoader and ObjectLoader
1 parent 25f1804 commit 2593241

File tree

12 files changed

+391
-76
lines changed

12 files changed

+391
-76
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<argument type="service" id="file_locator" />
4141
</service>
4242

43-
<service id="routing.loader.service" class="Symfony\Component\Routing\Loader\DependencyInjection\ServiceRouterLoader">
43+
<service id="routing.loader.service" class="Symfony\Component\Routing\Loader\ContainerLoader">
4444
<tag name="routing.loader" />
4545
<argument type="service" id="service_container" />
4646
</service>

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"symfony/polyfill-mbstring": "~1.0",
2828
"symfony/filesystem": "^3.4|^4.0|^5.0",
2929
"symfony/finder": "^3.4|^4.0|^5.0",
30-
"symfony/routing": "^4.3|^5.0"
30+
"symfony/routing": "^4.4|^5.0"
3131
},
3232
"require-dev": {
3333
"doctrine/cache": "~1.0",

src/Symfony/Component/Routing/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
CHANGELOG
22
=========
33

4+
4.4.0
5+
-----
6+
7+
* deprecated `ServiceRouterLoader` in favor of `ContainerLoader`
8+
* deprecated `ObjectRouteLoader` in favor of `ObjectLoader`
9+
410
4.3.0
511
-----
612

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Loader;
13+
14+
use Psr\Container\ContainerInterface;
15+
16+
/**
17+
* A route loader that executes a service from a PSR-11 container to load the routes.
18+
*
19+
* @author Ryan Weaver <ryan@knpuniversity.com>
20+
*/
21+
class ContainerLoader extends ObjectLoader
22+
{
23+
private $container;
24+
25+
public function __construct(ContainerInterface $container)
26+
{
27+
$this->container = $container;
28+
}
29+
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
public function supports($resource, $type = null)
34+
{
35+
return 'service' === $type;
36+
}
37+
38+
/**
39+
* {@inheritdoc}
40+
*/
41+
protected function getObject(string $id)
42+
{
43+
return $this->container->get($id);
44+
}
45+
}

src/Symfony/Component/Routing/Loader/DependencyInjection/ServiceRouterLoader.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
namespace Symfony\Component\Routing\Loader\DependencyInjection;
1313

1414
use Psr\Container\ContainerInterface;
15+
use Symfony\Component\Routing\Loader\ContainerLoader;
1516
use Symfony\Component\Routing\Loader\ObjectRouteLoader;
1617

18+
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', ServiceRouterLoader::class, ContainerLoader::class), E_USER_DEPRECATED);
19+
1720
/**
18-
* A route loader that executes a service to load the routes.
19-
*
20-
* @author Ryan Weaver <ryan@knpuniversity.com>
21+
* @deprecated since Symfony 4.4, use Symfony\Component\Routing\Loader\ContainerLoader instead.
2122
*/
2223
class ServiceRouterLoader extends ObjectRouteLoader
2324
{
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Loader;
13+
14+
use Symfony\Component\Config\Loader\Loader;
15+
use Symfony\Component\Config\Resource\FileResource;
16+
use Symfony\Component\Routing\RouteCollection;
17+
18+
/**
19+
* A route loader that calls a method on an object to load the routes.
20+
*
21+
* @author Ryan Weaver <ryan@knpuniversity.com>
22+
*/
23+
abstract class ObjectLoader extends Loader
24+
{
25+
/**
26+
* Returns the object that the method will be called on to load routes.
27+
*
28+
* For example, if your application uses a service container,
29+
* the $id may be a service id.
30+
*
31+
* @return object
32+
*/
33+
abstract protected function getObject(string $id);
34+
35+
/**
36+
* Calls the object method that will load the routes.
37+
*
38+
* @param string $resource object_id::method
39+
* @param string|null $type The resource type
40+
*
41+
* @return RouteCollection
42+
*/
43+
public function load($resource, $type = null)
44+
{
45+
if (!preg_match('/^[^\:]+(?:::?(?:[^\:]+))?$/', $resource)) {
46+
throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the %s route loader: use the format "object_id::method" or "object_id" if your object class has an "__invoke" method.', $resource, \is_string($type) ? '"'.$type.'"' : 'object'));
47+
}
48+
49+
$parts = explode('::', $resource);
50+
$method = $parts[1] ?? '__invoke';
51+
52+
$loaderObject = $this->getObject($parts[0]);
53+
54+
if (!\is_object($loaderObject)) {
55+
throw new \LogicException(sprintf('%s:getObject() must return an object: %s returned', \get_class($this), \gettype($loaderObject)));
56+
}
57+
58+
if (!\is_callable([$loaderObject, $method])) {
59+
throw new \BadMethodCallException(sprintf('Method "%s" not found on "%s" when importing routing resource "%s"', $method, \get_class($loaderObject), $resource));
60+
}
61+
62+
$routeCollection = $loaderObject->$method($this);
63+
64+
if (!$routeCollection instanceof RouteCollection) {
65+
$type = \is_object($routeCollection) ? \get_class($routeCollection) : \gettype($routeCollection);
66+
67+
throw new \LogicException(sprintf('The %s::%s method must return a RouteCollection: %s returned', \get_class($loaderObject), $method, $type));
68+
}
69+
70+
// make the object file tracked so that if it changes, the cache rebuilds
71+
$this->addClassResource(new \ReflectionClass($loaderObject), $routeCollection);
72+
73+
return $routeCollection;
74+
}
75+
76+
private function addClassResource(\ReflectionClass $class, RouteCollection $collection)
77+
{
78+
do {
79+
if (is_file($class->getFileName())) {
80+
$collection->addResource(new FileResource($class->getFileName()));
81+
}
82+
} while ($class = $class->getParentClass());
83+
}
84+
}

src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php

Lines changed: 18 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,12 @@
1111

1212
namespace Symfony\Component\Routing\Loader;
1313

14-
use Symfony\Component\Config\Loader\Loader;
15-
use Symfony\Component\Config\Resource\FileResource;
16-
use Symfony\Component\Routing\RouteCollection;
14+
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', ObjectRouteLoader::class, ObjectLoader::class), E_USER_DEPRECATED);
1715

1816
/**
19-
* A route loader that calls a method on an object to load the routes.
20-
*
21-
* @author Ryan Weaver <ryan@knpuniversity.com>
17+
* @deprecated since Symfony 4.4, use ObjectLoader instead.
2218
*/
23-
abstract class ObjectRouteLoader extends Loader
19+
abstract class ObjectRouteLoader extends ObjectLoader
2420
{
2521
/**
2622
* Returns the object that the method will be called on to load routes.
@@ -35,50 +31,23 @@ abstract class ObjectRouteLoader extends Loader
3531
abstract protected function getServiceObject($id);
3632

3733
/**
38-
* Calls the service that will load the routes.
39-
*
40-
* @param string $resource Some value that will resolve to a callable
41-
* @param string|null $type The resource type
42-
*
43-
* @return RouteCollection
34+
* {@inheritdoc}
4435
*/
4536
public function load($resource, $type = null)
4637
{
47-
if (!preg_match('/^[^\:]+(?:::?(?:[^\:]+))?$/', $resource)) {
48-
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));
49-
}
50-
51-
if (1 === substr_count($resource, ':')) {
38+
if ($useSingleColon = (1 === substr_count($resource, ':'))) {
5239
$resource = str_replace(':', '::', $resource);
53-
@trigger_error(sprintf('Referencing service route loaders with a single colon is deprecated since Symfony 4.1. Use %s instead.', $resource), E_USER_DEPRECATED);
5440
}
5541

56-
$parts = explode('::', $resource);
57-
$serviceString = $parts[0];
58-
$method = $parts[1] ?? '__invoke';
59-
60-
$loaderObject = $this->getServiceObject($serviceString);
61-
62-
if (!\is_object($loaderObject)) {
63-
throw new \LogicException(sprintf('%s:getServiceObject() must return an object: %s returned', \get_class($this), \gettype($loaderObject)));
64-
}
65-
66-
if (!\is_callable([$loaderObject, $method])) {
67-
throw new \BadMethodCallException(sprintf('Method "%s" not found on "%s" when importing routing resource "%s"', $method, \get_class($loaderObject), $resource));
68-
}
69-
70-
$routeCollection = $loaderObject->$method($this);
71-
72-
if (!$routeCollection instanceof RouteCollection) {
73-
$type = \is_object($routeCollection) ? \get_class($routeCollection) : \gettype($routeCollection);
74-
75-
throw new \LogicException(sprintf('The %s::%s method must return a RouteCollection: %s returned', \get_class($loaderObject), $method, $type));
42+
try {
43+
return parent::load($resource, $type);
44+
} catch (\InvalidArgumentException $e) {
45+
throw $e;
46+
} finally {
47+
if ($useSingleColon && !isset($e)) {
48+
@trigger_error(sprintf('Referencing service route loaders with a single colon is deprecated since Symfony 4.1. Use %s instead.', $resource), E_USER_DEPRECATED);
49+
}
7650
}
77-
78-
// make the service file tracked so that if it changes, the cache rebuilds
79-
$this->addClassResource(new \ReflectionClass($loaderObject), $routeCollection);
80-
81-
return $routeCollection;
8251
}
8352

8453
/**
@@ -89,12 +58,11 @@ public function supports($resource, $type = null)
8958
return 'service' === $type;
9059
}
9160

92-
private function addClassResource(\ReflectionClass $class, RouteCollection $collection)
61+
/**
62+
* {@inheritdoc}
63+
*/
64+
protected function getObject(string $id)
9365
{
94-
do {
95-
if (is_file($class->getFileName())) {
96-
$collection->addResource(new FileResource($class->getFileName()));
97-
}
98-
} while ($class = $class->getParentClass());
66+
return $this->getServiceObject($id);
9967
}
10068
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Fixtures;
13+
14+
use Symfony\Component\Routing\Loader\ObjectRouteLoader;
15+
16+
class TestObjectRouteLoader extends ObjectRouteLoader
17+
{
18+
public $loaderMap = [];
19+
20+
protected function getServiceObject($id)
21+
{
22+
return isset($this->loaderMap[$id]) ? $this->loaderMap[$id] : null;
23+
}
24+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Loader;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\Container;
16+
use Symfony\Component\Routing\Loader\ContainerLoader;
17+
18+
class ContainerLoaderTest extends TestCase
19+
{
20+
/**
21+
* @dataProvider supportsProvider
22+
*/
23+
public function testSupports(bool $expected, string $type = null)
24+
{
25+
$this->assertSame($expected, (new ContainerLoader(new Container()))->supports('foo', $type));
26+
}
27+
28+
public function supportsProvider()
29+
{
30+
return [
31+
[true, 'service'],
32+
[false, 'bar'],
33+
[false, null],
34+
];
35+
}
36+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Loader;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\Container;
16+
use Symfony\Component\Routing\Loader\DependencyInjection\ServiceRouterLoader;
17+
18+
class ServiceRouterLoaderTest extends TestCase
19+
{
20+
/**
21+
* @group legacy
22+
* @expectedDeprecation The "Symfony\Component\Routing\Loader\DependencyInjection\ServiceRouterLoader" class is deprecated since Symfony 4.4, use "Symfony\Component\Routing\Loader\ContainerLoader" instead.
23+
*/
24+
public function testDeprecationWarning()
25+
{
26+
new ServiceRouterLoader(new Container());
27+
}
28+
}

0 commit comments

Comments
 (0)
0