Skip to content

Commit f8a609c

Browse files
Tobionfabpot
authored andcommitted
Deprecate bundle:controller:action and service:method notation
1 parent e0bdc0c commit f8a609c

40 files changed

+494
-450
lines changed

UPGRADE-4.1.md

+32
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,38 @@ EventDispatcher
1515
FrameworkBundle
1616
---------------
1717

18+
* Deprecated `bundle:controller:action` and `service:action` syntaxes to reference controllers. Use `serviceOrFqcn::method`
19+
instead where `serviceOrFqcn` is either the service ID when using controllers as services or the FQCN of the controller.
20+
21+
Before:
22+
23+
```yml
24+
bundle_controller:
25+
path: /
26+
defaults:
27+
_controller: FrameworkBundle:Redirect:redirect
28+
29+
service_controller:
30+
path: /
31+
defaults:
32+
_controller: app.my_controller:myAction
33+
```
34+
35+
After:
36+
37+
```yml
38+
bundle_controller:
39+
path: /
40+
defaults:
41+
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
42+
43+
service_controller:
44+
path: /
45+
defaults:
46+
_controller: app.my_controller::myAction
47+
```
48+
49+
* Deprecated `Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser`
1850
* A `RouterInterface` that does not implement the `WarmableInterface` is deprecated.
1951
* The `RequestDataCollector` class has been deprecated. Use the `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector` class instead.
2052

UPGRADE-5.0.md

+32
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,38 @@ EventDispatcher
1414
FrameworkBundle
1515
---------------
1616

17+
* Removed support for `bundle:controller:action` and `service:action` syntaxes to reference controllers. Use `serviceOrFqcn::method`
18+
instead where `serviceOrFqcn` is either the service ID when using controllers as services or the FQCN of the controller.
19+
20+
Before:
21+
22+
```yml
23+
bundle_controller:
24+
path: /
25+
defaults:
26+
_controller: FrameworkBundle:Redirect:redirect
27+
28+
service_controller:
29+
path: /
30+
defaults:
31+
_controller: app.my_controller:myAction
32+
```
33+
34+
After:
35+
36+
```yml
37+
bundle_controller:
38+
path: /
39+
defaults:
40+
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
41+
42+
service_controller:
43+
path: /
44+
defaults:
45+
_controller: app.my_controller::myAction
46+
```
47+
48+
* Removed `Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser`
1749
* Using a `RouterInterface` that does not implement the `WarmableInterface` is not supported anymore.
1850
* The `RequestDataCollector` class has been removed. Use the `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector` class instead.
1951

src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ CHANGELOG
1111
* Using a `RouterInterface` that does not implement the `WarmableInterface` is deprecated.
1212
* The `RequestDataCollector` class has been deprecated. Use the `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector` class instead.
1313
* The `RedirectController` class allows for 307/308 HTTP status codes
14+
* Deprecated `bundle:controller:action` syntax to reference controllers. Use `serviceOrFqcn::method` instead where `serviceOrFqcn`
15+
is either the service ID or the FQCN of the controller.
16+
* Deprecated `Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser`
1417

1518
4.0.0
1619
-----

src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php

-47
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,13 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Command;
1313

1414
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
15-
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
1615
use Symfony\Component\Console\Command\Command;
1716
use Symfony\Component\Console\Input\InputArgument;
1817
use Symfony\Component\Console\Input\InputInterface;
1918
use Symfony\Component\Console\Input\InputOption;
2019
use Symfony\Component\Console\Output\OutputInterface;
2120
use Symfony\Component\Console\Style\SymfonyStyle;
22-
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
2321
use Symfony\Component\Routing\RouterInterface;
24-
use Symfony\Component\Routing\Route;
2522

2623
/**
2724
* A console command for retrieving information about routes.
@@ -83,20 +80,13 @@ protected function execute(InputInterface $input, OutputInterface $output)
8380
throw new \InvalidArgumentException(sprintf('The route "%s" does not exist.', $name));
8481
}
8582

86-
$callable = $this->extractCallable($route);
87-
8883
$helper->describe($io, $route, array(
8984
'format' => $input->getOption('format'),
9085
'raw_text' => $input->getOption('raw'),
9186
'name' => $name,
9287
'output' => $io,
93-
'callable' => $callable,
9488
));
9589
} else {
96-
foreach ($routes as $route) {
97-
$this->convertController($route);
98-
}
99-
10090
$helper->describe($io, $routes, array(
10191
'format' => $input->getOption('format'),
10292
'raw_text' => $input->getOption('raw'),
@@ -105,41 +95,4 @@ protected function execute(InputInterface $input, OutputInterface $output)
10595
));
10696
}
10797
}
108-
109-
private function convertController(Route $route)
110-
{
111-
if ($route->hasDefault('_controller')) {
112-
$nameParser = new ControllerNameParser($this->getApplication()->getKernel());
113-
try {
114-
$route->setDefault('_controller', $nameParser->build($route->getDefault('_controller')));
115-
} catch (\InvalidArgumentException $e) {
116-
}
117-
}
118-
}
119-
120-
private function extractCallable(Route $route)
121-
{
122-
if (!$route->hasDefault('_controller')) {
123-
return;
124-
}
125-
126-
$controller = $route->getDefault('_controller');
127-
128-
if (1 === substr_count($controller, ':')) {
129-
list($service, $method) = explode(':', $controller);
130-
try {
131-
return sprintf('%s::%s', get_class($this->getApplication()->getKernel()->getContainer()->get($service)), $method);
132-
} catch (ServiceNotFoundException $e) {
133-
}
134-
}
135-
136-
$nameParser = new ControllerNameParser($this->getApplication()->getKernel());
137-
try {
138-
$shortNotation = $nameParser->build($controller);
139-
$route->setDefault('_controller', $shortNotation);
140-
141-
return $controller;
142-
} catch (\InvalidArgumentException $e) {
143-
}
144-
}
14598
}

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php

-3
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,6 @@ protected function describeRoute(Route $route, array $options = array())
9595
array('Defaults', $this->formatRouterConfig($route->getDefaults())),
9696
array('Options', $this->formatRouterConfig($route->getOptions())),
9797
);
98-
if (isset($options['callable'])) {
99-
$tableRows[] = array('Callable', $options['callable']);
100-
}
10198

10299
$table = new Table($this->getOutput());
103100
$table->setHeaders($tableHeaders)->setRows($tableRows);

src/Symfony/Bundle/FrameworkBundle/Controller/ControllerNameParser.php

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
* (Bundle\BlogBundle\Controller\PostController::indexAction).
2020
*
2121
* @author Fabien Potencier <fabien@symfony.com>
22+
*
23+
* @deprecated since Symfony 4.1
2224
*/
2325
class ControllerNameParser
2426
{
@@ -41,6 +43,10 @@ public function __construct(KernelInterface $kernel)
4143
*/
4244
public function parse($controller)
4345
{
46+
if (2 > func_num_args() || func_get_arg(1)) {
47+
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.1.', __CLASS__), E_USER_DEPRECATED);
48+
}
49+
4450
$parts = explode(':', $controller);
4551
if (3 !== count($parts) || in_array('', $parts, true)) {
4652
throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "a:b:c" controller string.', $controller));
@@ -86,6 +92,8 @@ public function parse($controller)
8692
*/
8793
public function build($controller)
8894
{
95+
@trigger_error(sprintf('The %s class is deprecated since Symfony 4.1.', __CLASS__), E_USER_DEPRECATED);
96+
8997
if (0 === preg_match('#^(.*?\\\\Controller\\\\(.+)Controller)::(.+)Action$#', $controller, $match)) {
9098
throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "class::method" string.', $controller));
9199
}

src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php

+4-7
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,13 @@ protected function createController($controller)
3737
{
3838
if (false === strpos($controller, '::') && 2 === substr_count($controller, ':')) {
3939
// controller in the a:b:c notation then
40-
$controller = $this->parser->parse($controller);
41-
}
42-
43-
$resolvedController = parent::createController($controller);
40+
$deprecatedNotation = $controller;
41+
$controller = $this->parser->parse($deprecatedNotation, false);
4442

45-
if (1 === substr_count($controller, ':') && is_array($resolvedController)) {
46-
$resolvedController[0] = $this->configureController($resolvedController[0]);
43+
@trigger_error(sprintf('Referencing controllers with %s is deprecated since Symfony 4.1. Use %s instead.', $deprecatedNotation, $controller), E_USER_DEPRECATED);
4744
}
4845

49-
return $resolvedController;
46+
return parent::createController($controller);
5047
}
5148

5249
/**

src/Symfony/Bundle/FrameworkBundle/EventListener/ResolveControllerNameSubscriber.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
* Guarantees that the _controller key is parsed into its final format.
2121
*
2222
* @author Ryan Weaver <ryan@knpuniversity.com>
23+
*
24+
* @deprecated since Symfony 4.1
2325
*/
2426
class ResolveControllerNameSubscriber implements EventSubscriberInterface
2527
{
@@ -35,7 +37,7 @@ public function onKernelRequest(GetResponseEvent $event)
3537
$controller = $event->getRequest()->attributes->get('_controller');
3638
if (is_string($controller) && false === strpos($controller, '::') && 2 === substr_count($controller, ':')) {
3739
// controller in the a:b:c notation then
38-
$event->getRequest()->attributes->set('_controller', $this->parser->parse($controller));
40+
$event->getRequest()->attributes->set('_controller', $this->parser->parse($controller, false));
3941
}
4042
}
4143

src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function registerContainerConfiguration(LoaderInterface $loader)
6464
$loader->load(function (ContainerBuilder $container) use ($loader) {
6565
$container->loadFromExtension('framework', array(
6666
'router' => array(
67-
'resource' => 'kernel:loadRoutes',
67+
'resource' => 'kernel::loadRoutes',
6868
'type' => 'service',
6969
),
7070
));

src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php

+20-5
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,29 @@ public function load($resource, $type = null)
7373
}
7474

7575
foreach ($collection->all() as $route) {
76-
if (!is_string($controller = $route->getDefault('_controller')) || !$controller) {
76+
if (!is_string($controller = $route->getDefault('_controller'))) {
7777
continue;
7878
}
7979

80-
try {
81-
$controller = $this->parser->parse($controller);
82-
} catch (\InvalidArgumentException $e) {
83-
// unable to optimize unknown notation
80+
if (false !== strpos($controller, '::')) {
81+
continue;
82+
}
83+
84+
if (2 === substr_count($controller, ':')) {
85+
$deprecatedNotation = $controller;
86+
87+
try {
88+
$controller = $this->parser->parse($controller, false);
89+
90+
@trigger_error(sprintf('Referencing controllers with %s is deprecated since Symfony 4.1. Use %s instead.', $deprecatedNotation, $controller), E_USER_DEPRECATED);
91+
} catch (\InvalidArgumentException $e) {
92+
// unable to optimize unknown notation
93+
}
94+
}
95+
96+
if (1 === substr_count($controller, ':')) {
97+
$controller = str_replace(':', '::', $controller);
98+
@trigger_error(sprintf('Referencing controllers with a single colon is deprecated since Symfony 4.1. Use %s instead.', $controller), E_USER_DEPRECATED);
8499
}
85100

86101
$route->setDefault('_controller', $controller);

src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerNameParserTest.php

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
1717
use Symfony\Component\HttpKernel\Kernel;
1818

19+
/**
20+
* @group legacy
21+
*/
1922
class ControllerNameParserTest extends TestCase
2023
{
2124
protected $loader;

src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerResolverTest.php

+10-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
2121
use Symfony\Component\DependencyInjection\ContainerInterface;
2222
use Symfony\Component\HttpFoundation\Request;
23+
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
2324
use Symfony\Component\HttpKernel\Tests\Controller\ContainerControllerResolverTest;
2425

2526
class ControllerResolverTest extends ContainerControllerResolverTest
@@ -32,6 +33,7 @@ public function testGetControllerOnContainerAware()
3233

3334
$controller = $resolver->getController($request);
3435

36+
$this->assertInstanceOf('Symfony\Bundle\FrameworkBundle\Tests\Controller\ContainerAwareController', $controller[0]);
3537
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerInterface', $controller[0]->getContainer());
3638
$this->assertSame('testAction', $controller[1]);
3739
}
@@ -48,6 +50,10 @@ public function testGetControllerOnContainerAwareInvokable()
4850
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerInterface', $controller->getContainer());
4951
}
5052

53+
/**
54+
* @group legacy
55+
* @expectedDeprecation Referencing controllers with FooBundle:Default:test is deprecated since Symfony 4.1. Use Symfony\Bundle\FrameworkBundle\Tests\Controller\ContainerAwareController::testAction instead.
56+
*/
5157
public function testGetControllerWithBundleNotation()
5258
{
5359
$shortName = 'FooBundle:Default:test';
@@ -81,7 +87,7 @@ class_exists(AbstractControllerTest::class);
8187
$resolver = $this->createControllerResolver(null, $container);
8288

8389
$request = Request::create('/');
84-
$request->attributes->set('_controller', TestAbstractController::class.':testAction');
90+
$request->attributes->set('_controller', TestAbstractController::class.'::testAction');
8591

8692
$this->assertSame(array($controller, 'testAction'), $resolver->getController($request));
8793
$this->assertSame($container, $controller->getContainer());
@@ -117,7 +123,7 @@ class_exists(AbstractControllerTest::class);
117123
$resolver = $this->createControllerResolver(null, $container);
118124

119125
$request = Request::create('/');
120-
$request->attributes->set('_controller', DummyController::class.':fooAction');
126+
$request->attributes->set('_controller', DummyController::class.'::fooAction');
121127

122128
$this->assertSame(array($controller, 'fooAction'), $resolver->getController($request));
123129
$this->assertSame($container, $controller->getContainer());
@@ -157,13 +163,13 @@ class_exists(AbstractControllerTest::class);
157163
$resolver = $this->createControllerResolver(null, $container);
158164

159165
$request = Request::create('/');
160-
$request->attributes->set('_controller', DummyController::class.':fooAction');
166+
$request->attributes->set('_controller', DummyController::class.'::fooAction');
161167

162168
$this->assertSame(array($controller, 'fooAction'), $resolver->getController($request));
163169
$this->assertSame($controllerContainer, $controller->getContainer());
164170
}
165171

166-
protected function createControllerResolver(LoggerInterface $logger = null, Psr11ContainerInterface $container = null, ControllerNameParser $parser = null)
172+
protected function createControllerResolver(LoggerInterface $logger = null, Psr11ContainerInterface $container = null, ControllerNameParser $parser = null): ControllerResolverInterface
167173
{
168174
if (!$parser) {
169175
$parser = $this->createMockParser();

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SubRequestController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function indexAction($handler)
3333
// ...to check that the FragmentListener still references the right Request
3434
// when rendering another fragment after the error occurred
3535
// should render en/html instead of fr/json
36-
$content .= $handler->render(new ControllerReference('TestBundle:SubRequest:fragment'));
36+
$content .= $handler->render(new ControllerReference(self::class.'::fragmentAction'));
3737

3838
// forces the LocaleListener to set fr for the locale...
3939
// should render fr/json

src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SubRequestServiceResolutionController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class SubRequestServiceResolutionController implements ContainerAwareInterface
2424
public function indexAction()
2525
{
2626
$request = $this->container->get('request_stack')->getCurrentRequest();
27-
$path['_controller'] = 'TestBundle:SubRequestServiceResolution:fragment';
27+
$path['_controller'] = self::class.'::fragmentAction';
2828
$subRequest = $request->duplicate(array(), null, $path);
2929

3030
return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);

0 commit comments

Comments
 (0)