diff --git a/UPGRADE-4.4.md b/UPGRADE-4.4.md index c3b9ad8688..def83c0867 100644 --- a/UPGRADE-4.4.md +++ b/UPGRADE-4.4.md @@ -94,6 +94,7 @@ FrameworkBundle * The `ControllerResolver` and `DelegatingLoader` classes have been marked as `final`. * The `controller_name_converter` and `resolve_controller_name_subscriber` services have been deprecated. * Deprecated `routing.loader.service`, use `routing.loader.container` instead. + * Not tagging service route loaders with `routing.route_loader` has been deprecated. HttpClient ---------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 284e942c9a..461c90e51c 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -373,6 +373,7 @@ Routing Instead of overwriting them, use `__serialize` and `__unserialize` as extension points which are forward compatible with the new serialization methods in PHP 7.4. * Removed `ServiceRouterLoader` and `ObjectRouteLoader`. + * Service route loaders must be tagged with `routing.route_loader`. Security -------- diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 607766850a..f2c575a56e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG * Added support for configuring chained cache pools * Deprecated booting the kernel before running `WebTestCase::createClient()` * Deprecated `routing.loader.service`, use `routing.loader.container` instead. + * Not tagging service route loaders with `routing.route_loader` has been deprecated. 4.3.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php index efeafad5f0..00fc826cf2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php @@ -49,6 +49,7 @@ class UnusedTagsPass implements CompilerPassInterface 'proxy', 'routing.expression_language_provider', 'routing.loader', + 'routing.route_loader', 'security.expression_language_provider', 'security.remember_me_aware', 'security.voter', diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index cb9eaeaf3d..8d3555f441 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -24,6 +24,7 @@ use Symfony\Bridge\Twig\Extension\CsrfExtension; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Routing\AnnotatedRouteControllerLoader; use Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher; +use Symfony\Bundle\FrameworkBundle\Routing\RouteLoaderInterface; use Symfony\Bundle\FullStack; use Symfony\Component\Asset\PackageInterface; use Symfony\Component\BrowserKit\AbstractBrowser; @@ -446,6 +447,9 @@ class FrameworkExtension extends Extension if (!$config['disallow_search_engine_index'] ?? false) { $container->removeDefinition('disallow_search_engine_index_response_listener'); } + + $container->registerForAutoconfiguration(RouteLoaderInterface::class) + ->addTag('routing.route_loader'); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php b/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php index 3919737e44..c228734725 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php @@ -69,14 +69,20 @@ trait MicroKernelTrait ], ]); - if ($this instanceof EventSubscriberInterface) { + if (!$container->hasDefinition('kernel')) { $container->register('kernel', static::class) ->setSynthetic(true) ->setPublic(true) - ->addTag('kernel.event_subscriber') ; } + $kernelDefinition = $container->getDefinition('kernel'); + $kernelDefinition->addTag('routing.route_loader'); + + if ($this instanceof EventSubscriberInterface) { + $kernelDefinition->addTag('kernel.event_subscriber'); + } + $this->configureContainer($container, $loader); $container->addObjectResource($this); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml index 21530280d3..b85e9fa71d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml @@ -47,7 +47,12 @@ - + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/LegacyRouteLoaderContainer.php b/src/Symfony/Bundle/FrameworkBundle/Routing/LegacyRouteLoaderContainer.php new file mode 100644 index 0000000000..fa110ddb5d --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/LegacyRouteLoaderContainer.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Routing; + +use Psr\Container\ContainerInterface; + +/** + * @internal to be removed in Symfony 5.0 + */ +class LegacyRouteLoaderContainer implements ContainerInterface +{ + private $container; + private $serviceLocator; + + public function __construct(ContainerInterface $container, ContainerInterface $serviceLocator) + { + $this->container = $container; + $this->serviceLocator = $serviceLocator; + } + + /** + * {@inheritdoc} + */ + public function get($id) + { + if ($this->serviceLocator->has($id)) { + return $this->serviceLocator->get($id); + } + + @trigger_error(sprintf('Registering the service route loader "%s" without tagging it with the "routing.route_loader" tag is deprecated since Symfony 4.4 and will be required in Symfony 5.0.', $id), E_USER_DEPRECATED); + + return $this->container->get($id); + } + + /** + * {@inheritdoc} + */ + public function has($id) + { + return $this->serviceLocator->has($id) || $this->container->has($id); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/RouteLoaderInterface.php b/src/Symfony/Bundle/FrameworkBundle/Routing/RouteLoaderInterface.php new file mode 100644 index 0000000000..d1cb55a7af --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/RouteLoaderInterface.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Routing; + +/** + * Marker interface for service route loaders. + */ +interface RouteLoaderInterface +{ +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php index 539306fcea..dd909ea6fc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php @@ -12,6 +12,9 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Kernel; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; +use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\HttpFoundation\Request; class MicroKernelTraitTest extends TestCase @@ -39,4 +42,18 @@ class MicroKernelTraitTest extends TestCase $this->assertSame('It\'s dangerous to go alone. Take this ⚔', $response->getContent()); } + + public function testRoutingRouteLoaderTagIsAdded() + { + $frameworkExtension = $this->createMock(ExtensionInterface::class); + $frameworkExtension + ->expects($this->atLeastOnce()) + ->method('getAlias') + ->willReturn('framework'); + $container = new ContainerBuilder(); + $container->registerExtension($frameworkExtension); + $kernel = new ConcreteMicroKernel('test', false); + $kernel->registerContainerConfiguration(new ClosureLoader($container)); + $this->assertTrue($container->getDefinition('kernel')->hasTag('routing.route_loader')); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/LegacyRouteLoaderContainerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/LegacyRouteLoaderContainerTest.php new file mode 100644 index 0000000000..cd002453ba --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/LegacyRouteLoaderContainerTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Routing; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Bundle\FrameworkBundle\Routing\LegacyRouteLoaderContainer; +use Symfony\Component\DependencyInjection\Container; + +/** + * @group legacy + */ +class LegacyRouteLoaderContainerTest extends TestCase +{ + /** + * @var ContainerInterface + */ + private $container; + + /** + * @var ContainerInterface + */ + private $serviceLocator; + + /** + * @var LegacyRouteLoaderContainer + */ + private $legacyRouteLoaderContainer; + + /** + * {@inheritdoc} + */ + protected function setUp() + { + $this->container = new Container(); + $this->container->set('foo', new \stdClass()); + + $this->serviceLocator = new Container(); + $this->serviceLocator->set('bar', new \stdClass()); + + $this->legacyRouteLoaderContainer = new LegacyRouteLoaderContainer($this->container, $this->serviceLocator); + } + + /** + * @expectedDeprecation Registering the service route loader "foo" without tagging it with the "routing.route_loader" tag is deprecated since Symfony 4.4 and will be required in Symfony 5.0. + */ + public function testGet() + { + $this->assertSame($this->container->get('foo'), $this->legacyRouteLoaderContainer->get('foo')); + $this->assertSame($this->serviceLocator->get('bar'), $this->legacyRouteLoaderContainer->get('bar')); + } + + public function testHas() + { + $this->assertTrue($this->legacyRouteLoaderContainer->has('foo')); + $this->assertTrue($this->legacyRouteLoaderContainer->has('bar')); + $this->assertFalse($this->legacyRouteLoaderContainer->has('ccc')); + } +}