minor #31702 [FrameworkBundle] Remove support for the bundle:controller:action notation (Simperfit)
This PR was merged into the 5.0-dev branch.
Discussion
----------
[FrameworkBundle] Remove support for the bundle:controller:action notation
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | no <!-- please update src/**/CHANGELOG.md files -->
| BC breaks? | no <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass? | yes <!-- please add some, will be required by reviewers -->
| Fixed tickets | none <!-- #-prefixed issue number(s), if any -->
| License | MIT
| Doc PR |none no mention in the docs <!-- required for new features -->
<!--
Replace this notice by a short README for your feature/bugfix. This will help people
understand your PR and can be used as a start for the documentation.
Additionally (see https://symfony.com/roadmap):
- Bug fixes must be submitted against the lowest maintained branch where they apply
(lowest branches are regularly merged to upper ones so they get the fixes too).
- Features and deprecations must be submitted against the master branch.
-->
This remove the ResolveControllerNameSubscriber since it is deprecated, it ease the cleaning of HttpKernel see https://github.com/symfony/symfony/pull/31672#discussion_r288479461
Commits
-------
29e3c2f2aa
[FrameworkBundle] remove deprecater controller a🅱️c notation
This commit is contained in:
commit
35cdf613d8
@ -220,6 +220,7 @@ FrameworkBundle
|
||||
* Support for the legacy directory structure in `translation:update` and `debug:translation` commands has been removed.
|
||||
* Removed the "Psr\SimpleCache\CacheInterface" / "cache.app.simple" service, use "Symfony\Contracts\Cache\CacheInterface" / "cache.app" instead.
|
||||
* Removed support for `templating` engine in `TemplateController`, use Twig instead
|
||||
* Removed `ResolveControllerNameSubscriber`.
|
||||
|
||||
HttpClient
|
||||
----------
|
||||
|
@ -5,6 +5,9 @@ CHANGELOG
|
||||
-----
|
||||
|
||||
* Removed support to load translation resources from the legacy directories `src/Resources/translations/` and `src/Resources/<BundleName>/translations/`
|
||||
* Removed `ControllerNameParser`.
|
||||
* Removed `ResolveControllerNameSubscriber`
|
||||
* Removed support for `bundle:controller:action` to reference controllers. Use `serviceOrFqcn::method` instead
|
||||
* Removed support for PHP templating, use Twig instead
|
||||
|
||||
4.4.0
|
||||
|
@ -1,146 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Controller;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* ControllerNameParser converts controller from the short notation a:b:c
|
||||
* (BlogBundle:Post:index) to a fully-qualified class::method string
|
||||
* (Bundle\BlogBundle\Controller\PostController::indexAction).
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @deprecated since Symfony 4.1
|
||||
*/
|
||||
class ControllerNameParser
|
||||
{
|
||||
protected $kernel;
|
||||
|
||||
public function __construct(KernelInterface $kernel, bool $triggerDeprecation = true)
|
||||
{
|
||||
$this->kernel = $kernel;
|
||||
|
||||
if ($triggerDeprecation) {
|
||||
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.1.', __CLASS__), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a short notation a:b:c to a class::method.
|
||||
*
|
||||
* @param string $controller A short notation controller (a:b:c)
|
||||
*
|
||||
* @return string A string in the class::method notation
|
||||
*
|
||||
* @throws \InvalidArgumentException when the specified bundle is not enabled
|
||||
* or the controller cannot be found
|
||||
*/
|
||||
public function parse($controller)
|
||||
{
|
||||
if (2 > \func_num_args() || func_get_arg(1)) {
|
||||
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.1.', __CLASS__), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
$parts = explode(':', $controller);
|
||||
if (3 !== \count($parts) || \in_array('', $parts, true)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "a:b:c" controller string.', $controller));
|
||||
}
|
||||
|
||||
$originalController = $controller;
|
||||
list($bundleName, $controller, $action) = $parts;
|
||||
$controller = str_replace('/', '\\', $controller);
|
||||
|
||||
try {
|
||||
// this throws an exception if there is no such bundle
|
||||
$bundle = $this->kernel->getBundle($bundleName);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$message = sprintf(
|
||||
'The "%s" (from the _controller value "%s") does not exist or is not enabled in your kernel!',
|
||||
$bundleName,
|
||||
$originalController
|
||||
);
|
||||
|
||||
if ($alternative = $this->findAlternative($bundleName)) {
|
||||
$message .= sprintf(' Did you mean "%s:%s:%s"?', $alternative, $controller, $action);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException($message, 0, $e);
|
||||
}
|
||||
|
||||
$try = $bundle->getNamespace().'\\Controller\\'.$controller.'Controller';
|
||||
if (class_exists($try)) {
|
||||
return $try.'::'.$action.'Action';
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('The _controller value "%s:%s:%s" maps to a "%s" class, but this class was not found. Create this class or check the spelling of the class and its namespace.', $bundleName, $controller, $action, $try));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a class::method notation to a short one (a:b:c).
|
||||
*
|
||||
* @param string $controller A string in the class::method notation
|
||||
*
|
||||
* @return string A short notation controller (a:b:c)
|
||||
*
|
||||
* @throws \InvalidArgumentException when the controller is not valid or cannot be found in any bundle
|
||||
*/
|
||||
public function build($controller)
|
||||
{
|
||||
@trigger_error(sprintf('The %s class is deprecated since Symfony 4.1.', __CLASS__), E_USER_DEPRECATED);
|
||||
|
||||
if (0 === preg_match('#^(.*?\\\\Controller\\\\(.+)Controller)::(.+)Action$#', $controller, $match)) {
|
||||
throw new \InvalidArgumentException(sprintf('The "%s" controller is not a valid "class::method" string.', $controller));
|
||||
}
|
||||
|
||||
$className = $match[1];
|
||||
$controllerName = $match[2];
|
||||
$actionName = $match[3];
|
||||
foreach ($this->kernel->getBundles() as $name => $bundle) {
|
||||
if (0 !== strpos($className, $bundle->getNamespace())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return sprintf('%s:%s:%s', $name, $controllerName, $actionName);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Unable to find a bundle that defines controller "%s".', $controller));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find a bundle that is *similar* to the given bundle name.
|
||||
*/
|
||||
private function findAlternative(string $nonExistentBundleName): ?string
|
||||
{
|
||||
$bundleNames = array_map(function (BundleInterface $b) {
|
||||
return $b->getName();
|
||||
}, $this->kernel->getBundles());
|
||||
|
||||
$alternative = null;
|
||||
$shortest = null;
|
||||
foreach ($bundleNames as $bundleName) {
|
||||
// if there's a partial match, return it immediately
|
||||
if (false !== strpos($bundleName, $nonExistentBundleName)) {
|
||||
return $bundleName;
|
||||
}
|
||||
|
||||
$lev = levenshtein($nonExistentBundleName, $bundleName);
|
||||
if ($lev <= \strlen($nonExistentBundleName) / 3 && (null === $alternative || $lev < $shortest)) {
|
||||
$alternative = $bundleName;
|
||||
$shortest = $lev;
|
||||
}
|
||||
}
|
||||
|
||||
return $alternative;
|
||||
}
|
||||
}
|
@ -11,9 +11,7 @@
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Controller;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver;
|
||||
|
||||
/**
|
||||
@ -23,45 +21,6 @@ use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver;
|
||||
*/
|
||||
class ControllerResolver extends ContainerControllerResolver
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 4.4
|
||||
*/
|
||||
protected $parser;
|
||||
|
||||
/**
|
||||
* @param LoggerInterface|null $logger
|
||||
*/
|
||||
public function __construct(ContainerInterface $container, $logger = null)
|
||||
{
|
||||
if ($logger instanceof ControllerNameParser) {
|
||||
@trigger_error(sprintf('Passing a "%s" instance as 2nd argument to "%s()" is deprecated since Symfony 4.4, pass a "%s" instance or null instead.', ControllerNameParser::class, __METHOD__, LoggerInterface::class), E_USER_DEPRECATED);
|
||||
$this->parser = $logger;
|
||||
$logger = 2 < \func_num_args() ? func_get_arg(2) : null;
|
||||
} elseif (2 < \func_num_args() && func_get_arg(2) instanceof ControllerNameParser) {
|
||||
$this->parser = func_get_arg(2);
|
||||
} elseif ($logger && !$logger instanceof LoggerInterface) {
|
||||
throw new \TypeError(sprintf('Argument 2 of "%s()" must be an instance of "%s" or null, "%s" given.', __METHOD__, LoggerInterface::class, \is_object($logger) ? \get_class($logger) : \gettype($logger)), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
parent::__construct($container, $logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function createController($controller)
|
||||
{
|
||||
if ($this->parser && false === strpos($controller, '::') && 2 === substr_count($controller, ':')) {
|
||||
// controller in the a:b:c notation then
|
||||
$deprecatedNotation = $controller;
|
||||
$controller = $this->parser->parse($deprecatedNotation, false);
|
||||
|
||||
@trigger_error(sprintf('Referencing controllers with %s is deprecated since Symfony 4.1. Use %s instead.', $deprecatedNotation, $controller), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
return parent::createController($controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@ -77,9 +36,7 @@ class ControllerResolver extends ContainerControllerResolver
|
||||
}
|
||||
if ($controller instanceof AbstractController) {
|
||||
if (null === $previousContainer = $controller->setContainer($this->container)) {
|
||||
@trigger_error(sprintf('Auto-injection of the container for "%s" is deprecated since Symfony 4.2. Configure it as a service instead.', $class), E_USER_DEPRECATED);
|
||||
// To be uncommented on Symfony 5:
|
||||
//throw new \LogicException(sprintf('"%s" has no container set, did you forget to define it as a service subscriber?', $class));
|
||||
throw new \LogicException(sprintf('"%s" has no container set, did you forget to define it as a service subscriber?', $class));
|
||||
} else {
|
||||
$controller->setContainer($previousContainer);
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\EventListener;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Guarantees that the _controller key is parsed into its final format.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
*
|
||||
* @deprecated since Symfony 4.1
|
||||
*/
|
||||
class ResolveControllerNameSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
private $parser;
|
||||
|
||||
public function __construct(ControllerNameParser $parser, bool $triggerDeprecation = true)
|
||||
{
|
||||
if ($triggerDeprecation) {
|
||||
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.1.', __CLASS__), E_USER_DEPRECATED);
|
||||
}
|
||||
|
||||
$this->parser = $parser;
|
||||
}
|
||||
|
||||
public function onKernelRequest(GetResponseEvent $event)
|
||||
{
|
||||
$controller = $event->getRequest()->attributes->get('_controller');
|
||||
if (\is_string($controller) && false === strpos($controller, '::') && 2 === substr_count($controller, ':')) {
|
||||
// controller in the a:b:c notation then
|
||||
$event->getRequest()->attributes->set('_controller', $parsedNotation = $this->parser->parse($controller, false));
|
||||
|
||||
@trigger_error(sprintf('Referencing controllers with %s is deprecated since Symfony 4.1, use "%s" instead.', $controller, $parsedNotation), E_USER_DEPRECATED);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
KernelEvents::REQUEST => ['onKernelRequest', 24],
|
||||
];
|
||||
}
|
||||
}
|
@ -48,7 +48,6 @@
|
||||
<service id="routing.loader" class="Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader" public="true">
|
||||
<argument type="service" id="routing.resolver" />
|
||||
<argument type="collection" />
|
||||
<argument type="service" id=".legacy_controller_name_converter" /> <!-- deprecated since Symfony 4.4 -->
|
||||
</service>
|
||||
|
||||
<service id="router.default" class="Symfony\Bundle\FrameworkBundle\Routing\Router">
|
||||
|
@ -7,21 +7,10 @@
|
||||
<services>
|
||||
<defaults public="false" />
|
||||
|
||||
<service id=".legacy_controller_name_converter" class="Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser">
|
||||
<tag name="monolog.logger" channel="request" />
|
||||
<argument type="service" id="kernel" />
|
||||
<argument>false</argument>
|
||||
</service>
|
||||
|
||||
<service id="controller_name_converter" alias=".legacy_controller_name_converter">
|
||||
<deprecated>The "%alias_id%" service is deprecated since Symfony 4.3.</deprecated>
|
||||
</service>
|
||||
|
||||
<service id="controller_resolver" class="Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver">
|
||||
<tag name="monolog.logger" channel="request" />
|
||||
<argument type="service" id="service_container" />
|
||||
<argument type="service" id="logger" on-invalid="ignore" />
|
||||
<argument type="service" id=".legacy_controller_name_converter" />
|
||||
</service>
|
||||
|
||||
<service id="argument_metadata_factory" class="Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory" />
|
||||
@ -86,15 +75,6 @@
|
||||
<tag name="kernel.event_subscriber" />
|
||||
</service>
|
||||
|
||||
<service id=".legacy_resolve_controller_name_subscriber" class="Symfony\Bundle\FrameworkBundle\EventListener\ResolveControllerNameSubscriber">
|
||||
<argument type="service" id=".legacy_controller_name_converter" />
|
||||
<argument>false</argument>
|
||||
<tag name="kernel.event_subscriber" />
|
||||
</service>
|
||||
<service id="resolve_controller_name_subscriber" alias=".legacy_resolve_controller_name_subscriber">
|
||||
<deprecated>The "%alias_id%" service is deprecated since Symfony 4.3.</deprecated>
|
||||
</service>
|
||||
|
||||
<service id="disallow_search_engine_index_response_listener" class="Symfony\Component\HttpKernel\EventListener\DisallowRobotsIndexingListener">
|
||||
<tag name="kernel.event_subscriber" />
|
||||
</service>
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Routing;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
||||
use Symfony\Component\Config\Exception\LoaderLoadException;
|
||||
use Symfony\Component\Config\Loader\DelegatingLoader as BaseDelegatingLoader;
|
||||
use Symfony\Component\Config\Loader\LoaderResolverInterface;
|
||||
@ -28,28 +27,11 @@ use Symfony\Component\Config\Loader\LoaderResolverInterface;
|
||||
*/
|
||||
class DelegatingLoader extends BaseDelegatingLoader
|
||||
{
|
||||
/**
|
||||
* @deprecated since Symfony 4.4
|
||||
*/
|
||||
protected $parser;
|
||||
private $loading = false;
|
||||
private $defaultOptions;
|
||||
|
||||
/**
|
||||
* @param LoaderResolverInterface $resolver
|
||||
* @param array $defaultOptions
|
||||
*/
|
||||
public function __construct($resolver, $defaultOptions = [])
|
||||
public function __construct(LoaderResolverInterface $resolver, array $defaultOptions = [])
|
||||
{
|
||||
if ($resolver instanceof ControllerNameParser) {
|
||||
@trigger_error(sprintf('Passing a "%s" instance as first argument to "%s()" is deprecated since Symfony 4.4, pass a "%s" instance instead.', ControllerNameParser::class, __METHOD__, LoaderResolverInterface::class), E_USER_DEPRECATED);
|
||||
$this->parser = $resolver;
|
||||
$resolver = $defaultOptions;
|
||||
$defaultOptions = 2 < \func_num_args() ? func_get_arg(2) : [];
|
||||
} elseif (2 < \func_num_args() && func_get_arg(2) instanceof ControllerNameParser) {
|
||||
$this->parser = func_get_arg(2);
|
||||
}
|
||||
|
||||
$this->defaultOptions = $defaultOptions;
|
||||
|
||||
parent::__construct($resolver);
|
||||
@ -99,18 +81,6 @@ class DelegatingLoader extends BaseDelegatingLoader
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->parser && 2 === substr_count($controller, ':')) {
|
||||
$deprecatedNotation = $controller;
|
||||
|
||||
try {
|
||||
$controller = $this->parser->parse($controller, false);
|
||||
|
||||
@trigger_error(sprintf('Referencing controllers with %s is deprecated since Symfony 4.1, use "%s" instead.', $deprecatedNotation, $controller), E_USER_DEPRECATED);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// unable to optimize unknown notation
|
||||
}
|
||||
}
|
||||
|
||||
if (1 === substr_count($controller, ':')) {
|
||||
$nonDeprecatedNotation = str_replace(':', '::', $controller);
|
||||
// TODO deprecate this in 5.1
|
||||
|
@ -1,183 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Tests\Controller;
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
||||
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
class ControllerNameParserTest extends TestCase
|
||||
{
|
||||
protected $loader;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->loader = new ClassLoader();
|
||||
$this->loader->add('TestBundle', __DIR__.'/../Fixtures');
|
||||
$this->loader->add('TestApplication', __DIR__.'/../Fixtures');
|
||||
$this->loader->register();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$this->loader->unregister();
|
||||
$this->loader = null;
|
||||
}
|
||||
|
||||
public function testParse()
|
||||
{
|
||||
$parser = $this->createParser();
|
||||
|
||||
$this->assertEquals('TestBundle\FooBundle\Controller\DefaultController::indexAction', $parser->parse('FooBundle:Default:index'), '->parse() converts a short a:b:c notation string to a class::method string');
|
||||
$this->assertEquals('TestBundle\FooBundle\Controller\Sub\DefaultController::indexAction', $parser->parse('FooBundle:Sub\Default:index'), '->parse() converts a short a:b:c notation string to a class::method string');
|
||||
$this->assertEquals('TestBundle\Sensio\Cms\FooBundle\Controller\DefaultController::indexAction', $parser->parse('SensioCmsFooBundle:Default:index'), '->parse() converts a short a:b:c notation string to a class::method string');
|
||||
$this->assertEquals('TestBundle\FooBundle\Controller\Test\DefaultController::indexAction', $parser->parse('FooBundle:Test\\Default:index'), '->parse() converts a short a:b:c notation string to a class::method string');
|
||||
$this->assertEquals('TestBundle\FooBundle\Controller\Test\DefaultController::indexAction', $parser->parse('FooBundle:Test/Default:index'), '->parse() converts a short a:b:c notation string to a class::method string');
|
||||
|
||||
try {
|
||||
$parser->parse('foo:');
|
||||
$this->fail('->parse() throws an \InvalidArgumentException if the controller is not an a:b:c string');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws an \InvalidArgumentException if the controller is not an a:b:c string');
|
||||
}
|
||||
}
|
||||
|
||||
public function testBuild()
|
||||
{
|
||||
$parser = $this->createParser();
|
||||
|
||||
$this->assertEquals('FoooooBundle:Default:index', $parser->build('TestBundle\FooBundle\Controller\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
|
||||
$this->assertEquals('FoooooBundle:Sub\Default:index', $parser->build('TestBundle\FooBundle\Controller\Sub\DefaultController::indexAction'), '->parse() converts a class::method string to a short a:b:c notation string');
|
||||
|
||||
try {
|
||||
$parser->build('TestBundle\FooBundle\Controller\DefaultController::index');
|
||||
$this->fail('->parse() throws an \InvalidArgumentException if the controller is not an aController::cAction string');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws an \InvalidArgumentException if the controller is not an aController::cAction string');
|
||||
}
|
||||
|
||||
try {
|
||||
$parser->build('TestBundle\FooBundle\Controller\Default::indexAction');
|
||||
$this->fail('->parse() throws an \InvalidArgumentException if the controller is not an aController::cAction string');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws an \InvalidArgumentException if the controller is not an aController::cAction string');
|
||||
}
|
||||
|
||||
try {
|
||||
$parser->build('Foo\Controller\DefaultController::indexAction');
|
||||
$this->fail('->parse() throws an \InvalidArgumentException if the controller is not an aController::cAction string');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws an \InvalidArgumentException if the controller is not an aController::cAction string');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getMissingControllersTest
|
||||
*/
|
||||
public function testMissingControllers($name)
|
||||
{
|
||||
$parser = $this->createParser();
|
||||
|
||||
try {
|
||||
$parser->parse($name);
|
||||
$this->fail('->parse() throws a \InvalidArgumentException if the class is found but does not exist');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws a \InvalidArgumentException if the class is found but does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
public function getMissingControllersTest()
|
||||
{
|
||||
// a normal bundle
|
||||
$bundles = [
|
||||
['FooBundle:Fake:index'],
|
||||
];
|
||||
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getInvalidBundleNameTests
|
||||
*/
|
||||
public function testInvalidBundleName($bundleName, $suggestedBundleName)
|
||||
{
|
||||
$parser = $this->createParser();
|
||||
|
||||
try {
|
||||
$parser->parse($bundleName);
|
||||
$this->fail('->parse() throws a \InvalidArgumentException if the bundle does not exist');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->parse() throws a \InvalidArgumentException if the bundle does not exist');
|
||||
|
||||
if (false === $suggestedBundleName) {
|
||||
// make sure we don't have a suggestion
|
||||
$this->assertNotContains('Did you mean', $e->getMessage());
|
||||
} else {
|
||||
$this->assertContains(sprintf('Did you mean "%s"', $suggestedBundleName), $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getInvalidBundleNameTests()
|
||||
{
|
||||
return [
|
||||
'Alternative will be found using levenshtein' => ['FoodBundle:Default:index', 'FooBundle:Default:index'],
|
||||
'Bundle does not exist at all' => ['CrazyBundle:Default:index', false],
|
||||
];
|
||||
}
|
||||
|
||||
private function createParser()
|
||||
{
|
||||
$bundles = [
|
||||
'SensioCmsFooBundle' => $this->getBundle('TestBundle\Sensio\Cms\FooBundle', 'SensioCmsFooBundle'),
|
||||
'FooBundle' => $this->getBundle('TestBundle\FooBundle', 'FooBundle'),
|
||||
];
|
||||
|
||||
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock();
|
||||
$kernel
|
||||
->expects($this->any())
|
||||
->method('getBundle')
|
||||
->willReturnCallback(function ($bundle) use ($bundles) {
|
||||
if (!isset($bundles[$bundle])) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid bundle name "%s"', $bundle));
|
||||
}
|
||||
|
||||
return $bundles[$bundle];
|
||||
})
|
||||
;
|
||||
|
||||
$bundles = [
|
||||
'SensioCmsFooBundle' => $this->getBundle('TestBundle\Sensio\Cms\FooBundle', 'SensioCmsFooBundle'),
|
||||
'FoooooBundle' => $this->getBundle('TestBundle\FooBundle', 'FoooooBundle'),
|
||||
'FooBundle' => $this->getBundle('TestBundle\FooBundle', 'FooBundle'),
|
||||
];
|
||||
$kernel
|
||||
->expects($this->any())
|
||||
->method('getBundles')
|
||||
->willReturn($bundles)
|
||||
;
|
||||
|
||||
return new ControllerNameParser($kernel);
|
||||
}
|
||||
|
||||
private function getBundle($namespace, $name)
|
||||
{
|
||||
$bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\BundleInterface')->getMock();
|
||||
$bundle->expects($this->any())->method('getName')->willReturn($name);
|
||||
$bundle->expects($this->any())->method('getNamespace')->willReturn($namespace);
|
||||
|
||||
return $bundle;
|
||||
}
|
||||
}
|
@ -14,7 +14,6 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Controller;
|
||||
use Psr\Container\ContainerInterface as Psr11ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||
@ -49,31 +48,6 @@ class ControllerResolverTest extends ContainerControllerResolverTest
|
||||
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerInterface', $controller->getContainer());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Referencing controllers with FooBundle:Default:test is deprecated since Symfony 4.1. Use Symfony\Bundle\FrameworkBundle\Tests\Controller\ContainerAwareController::testAction instead.
|
||||
*/
|
||||
public function testGetControllerWithBundleNotation()
|
||||
{
|
||||
$shortName = 'FooBundle:Default:test';
|
||||
$parser = $this->createMockParser();
|
||||
$parser->expects($this->once())
|
||||
->method('parse')
|
||||
->with($shortName)
|
||||
->willReturn('Symfony\Bundle\FrameworkBundle\Tests\Controller\ContainerAwareController::testAction')
|
||||
;
|
||||
|
||||
$resolver = $this->createLegacyControllerResolver(null, null, $parser);
|
||||
$request = Request::create('/');
|
||||
$request->attributes->set('_controller', $shortName);
|
||||
|
||||
$controller = $resolver->getController($request);
|
||||
|
||||
$this->assertInstanceOf('Symfony\Bundle\FrameworkBundle\Tests\Controller\ContainerAwareController', $controller[0]);
|
||||
$this->assertInstanceOf('Symfony\Component\DependencyInjection\ContainerInterface', $controller[0]->getContainer());
|
||||
$this->assertSame('testAction', $controller[1]);
|
||||
}
|
||||
|
||||
public function testContainerAwareControllerGetsContainerWhenNotSet()
|
||||
{
|
||||
class_exists(AbstractControllerTest::class);
|
||||
@ -93,8 +67,8 @@ class ControllerResolverTest extends ContainerControllerResolverTest
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Auto-injection of the container for "Symfony\Bundle\FrameworkBundle\Tests\Controller\TestAbstractController" is deprecated since Symfony 4.2. Configure it as a service instead.
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage "Symfony\Bundle\FrameworkBundle\Tests\Controller\TestAbstractController" has no container set, did you forget to define it as a service subscriber?
|
||||
*/
|
||||
public function testAbstractControllerGetsContainerWhenNotSet()
|
||||
{
|
||||
@ -105,7 +79,7 @@ class ControllerResolverTest extends ContainerControllerResolverTest
|
||||
$container = new Container();
|
||||
$container->set(TestAbstractController::class, $controller);
|
||||
|
||||
$resolver = $this->createLegacyControllerResolver(null, $container);
|
||||
$resolver = $this->createControllerResolver(null, $container);
|
||||
|
||||
$request = Request::create('/');
|
||||
$request->attributes->set('_controller', TestAbstractController::class.'::fooAction');
|
||||
@ -115,10 +89,10 @@ class ControllerResolverTest extends ContainerControllerResolverTest
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Auto-injection of the container for "Symfony\Bundle\FrameworkBundle\Tests\Controller\DummyController" is deprecated since Symfony 4.2. Configure it as a service instead.
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage "Symfony\Bundle\FrameworkBundle\Tests\Controller\DummyController" has no container set, did you forget to define it as a service subscriber?
|
||||
*/
|
||||
public function testAbstractControllerServiceWithFcqnIdGetsContainerWhenNotSet()
|
||||
public function testAbstractControllerServiceWithFqcnIdGetsContainerWhenNotSet()
|
||||
{
|
||||
class_exists(AbstractControllerTest::class);
|
||||
|
||||
@ -127,7 +101,7 @@ class ControllerResolverTest extends ContainerControllerResolverTest
|
||||
$container = new Container();
|
||||
$container->set(DummyController::class, $controller);
|
||||
|
||||
$resolver = $this->createLegacyControllerResolver(null, $container);
|
||||
$resolver = $this->createControllerResolver(null, $container);
|
||||
|
||||
$request = Request::create('/');
|
||||
$request->attributes->set('_controller', DummyController::class.'::fooAction');
|
||||
@ -176,19 +150,6 @@ class ControllerResolverTest extends ContainerControllerResolverTest
|
||||
$this->assertSame($controllerContainer, $controller->getContainer());
|
||||
}
|
||||
|
||||
protected function createLegacyControllerResolver(LoggerInterface $logger = null, Psr11ContainerInterface $container = null, ControllerNameParser $parser = null)
|
||||
{
|
||||
if (!$parser) {
|
||||
$parser = $this->createMockParser();
|
||||
}
|
||||
|
||||
if (!$container) {
|
||||
$container = $this->createMockContainer();
|
||||
}
|
||||
|
||||
return new ControllerResolver($container, $parser, $logger);
|
||||
}
|
||||
|
||||
protected function createControllerResolver(LoggerInterface $logger = null, Psr11ContainerInterface $container = null)
|
||||
{
|
||||
if (!$container) {
|
||||
|
@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Tests\EventListener;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
||||
use Symfony\Bundle\FrameworkBundle\EventListener\ResolveControllerNameSubscriber;
|
||||
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\RequestEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
class ResolveControllerNameSubscriberTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testReplacesControllerAttribute()
|
||||
{
|
||||
$parser = $this->getMockBuilder(ControllerNameParser::class)->disableOriginalConstructor()->getMock();
|
||||
$parser->expects($this->any())
|
||||
->method('parse')
|
||||
->with('AppBundle:Starting:format')
|
||||
->willReturn('App\\Final\\Format::methodName');
|
||||
$httpKernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
|
||||
|
||||
$request = new Request();
|
||||
$request->attributes->set('_controller', 'AppBundle:Starting:format');
|
||||
|
||||
$subscriber = new ResolveControllerNameSubscriber($parser);
|
||||
$subscriber->onKernelRequest(new RequestEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
|
||||
$this->assertEquals('App\\Final\\Format::methodName', $request->attributes->get('_controller'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideSkippedControllers
|
||||
*/
|
||||
public function testSkipsOtherControllerFormats($controller)
|
||||
{
|
||||
$parser = $this->getMockBuilder(ControllerNameParser::class)->disableOriginalConstructor()->getMock();
|
||||
$parser->expects($this->never())
|
||||
->method('parse');
|
||||
$httpKernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
|
||||
|
||||
$request = new Request();
|
||||
$request->attributes->set('_controller', $controller);
|
||||
|
||||
$subscriber = new ResolveControllerNameSubscriber($parser);
|
||||
$subscriber->onKernelRequest(new RequestEvent($httpKernel, $request, HttpKernelInterface::MASTER_REQUEST));
|
||||
$this->assertEquals($controller, $request->attributes->get('_controller'));
|
||||
}
|
||||
|
||||
public function provideSkippedControllers()
|
||||
{
|
||||
yield ['Other:format'];
|
||||
yield [function () {}];
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
namespace Symfony\Bundle\FrameworkBundle\Tests\Routing;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser;
|
||||
use Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader;
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\Config\Loader\LoaderResolver;
|
||||
@ -13,17 +12,10 @@ use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
class DelegatingLoaderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Passing a "Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser" instance as first argument to "Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader::__construct()" is deprecated since Symfony 4.4, pass a "Symfony\Component\Config\Loader\LoaderResolverInterface" instance instead.
|
||||
*/
|
||||
public function testConstructorApi()
|
||||
{
|
||||
$controllerNameParser = $this->getMockBuilder(ControllerNameParser::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
new DelegatingLoader($controllerNameParser, new LoaderResolver());
|
||||
$this->assertTrue(true, '__construct() takes a ControllerNameParser and LoaderResolverInterface respectively as its first and second argument.');
|
||||
new DelegatingLoader(new LoaderResolver());
|
||||
$this->assertTrue(true, '__construct() takeS a LoaderResolverInterface as its first argument.');
|
||||
}
|
||||
|
||||
public function testLoadDefaultOptions()
|
||||
@ -64,47 +56,4 @@ class DelegatingLoaderTest extends TestCase
|
||||
];
|
||||
$this->assertSame($expected, $routeCollection->get('bar')->getOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Referencing controllers with foo:bar:baz is deprecated since Symfony 4.1, use "some_parsed::controller" instead.
|
||||
*/
|
||||
public function testLoad()
|
||||
{
|
||||
$controllerNameParser = $this->getMockBuilder(ControllerNameParser::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$controllerNameParser->expects($this->once())
|
||||
->method('parse')
|
||||
->with('foo:bar:baz')
|
||||
->willReturn('some_parsed::controller');
|
||||
|
||||
$loaderResolver = $this->getMockBuilder(LoaderResolverInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$loader = $this->getMockBuilder(LoaderInterface::class)->getMock();
|
||||
|
||||
$loaderResolver->expects($this->once())
|
||||
->method('resolve')
|
||||
->willReturn($loader);
|
||||
|
||||
$routeCollection = new RouteCollection();
|
||||
$routeCollection->add('foo', new Route('/', ['_controller' => 'foo:bar:baz']));
|
||||
$routeCollection->add('bar', new Route('/', ['_controller' => 'foo::baz']));
|
||||
$routeCollection->add('baz', new Route('/', ['_controller' => 'foo:baz']));
|
||||
|
||||
$loader->expects($this->once())
|
||||
->method('load')
|
||||
->willReturn($routeCollection);
|
||||
|
||||
$delegatingLoader = new DelegatingLoader($controllerNameParser, $loaderResolver);
|
||||
|
||||
$loadedRouteCollection = $delegatingLoader->load('foo');
|
||||
$this->assertCount(3, $loadedRouteCollection);
|
||||
$this->assertSame('some_parsed::controller', $routeCollection->get('foo')->getDefault('_controller'));
|
||||
$this->assertSame('foo::baz', $routeCollection->get('bar')->getDefault('_controller'));
|
||||
$this->assertSame('foo:baz', $routeCollection->get('baz')->getDefault('_controller'));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user