Skip to content

Commit

Permalink
feature #27879 [Routing] deprecate non string requirement names (xabbuh)
Browse files Browse the repository at this point in the history
This PR was merged into the 4.2-dev branch.

Discussion
----------

[Routing] deprecate non string requirement names

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

Basically, this will help catching wrong `@Route` annotation configurations like the following which can lead to hard to debug issues:

```php
@route("/{foo}", requirements={"foo", "bar"})
```

Commits
-------

8bb5266 deprecate non string requirement names
  • Loading branch information
fabpot committed Jul 11, 2018
2 parents df26fea + 8bb5266 commit c85134c
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 1 deletion.
16 changes: 15 additions & 1 deletion src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
Expand Up @@ -142,8 +142,16 @@ protected function addRoute(RouteCollection $collection, $annot, $globals, \Refl
}
$name = $globals['name'].$name;

$requirements = $annot->getRequirements();

foreach ($requirements as $placeholder => $requirement) {
if (is_int($placeholder)) {
@trigger_error(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s::%s()"?', $placeholder, $requirement, $name, $class->getName(), $method->getName()), E_USER_DEPRECATED);
}
}

$defaults = array_replace($globals['defaults'], $annot->getDefaults());
$requirements = array_replace($globals['requirements'], $annot->getRequirements());
$requirements = array_replace($globals['requirements'], $requirements);
$options = array_replace($globals['options'], $annot->getOptions());
$schemes = array_merge($globals['schemes'], $annot->getSchemes());
$methods = array_merge($globals['methods'], $annot->getMethods());
Expand Down Expand Up @@ -305,6 +313,12 @@ protected function getGlobals(\ReflectionClass $class)
if (null !== $annot->getCondition()) {
$globals['condition'] = $annot->getCondition();
}

foreach ($globals['requirements'] as $placeholder => $requirement) {
if (is_int($placeholder)) {
@trigger_error(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" in "%s"?', $placeholder, $requirement, $class->getName()), E_USER_DEPRECATED);
}
}
}

return $globals;
Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/Routing/Loader/YamlFileLoader.php
Expand Up @@ -116,6 +116,12 @@ protected function parseRoute(RouteCollection $collection, $name, array $config,
$methods = isset($config['methods']) ? $config['methods'] : array();
$condition = isset($config['condition']) ? $config['condition'] : null;

foreach ($requirements as $placeholder => $requirement) {
if (is_int($placeholder)) {
@trigger_error(sprintf('A placeholder name must be a string (%d given). Did you forget to specify the placeholder key for the requirement "%s" of route "%s" in "%s"?', $placeholder, $requirement, $name, $path), E_USER_DEPRECATED);
}
}

if (isset($config['controller'])) {
$defaults['_controller'] = $config['controller'];
}
Expand Down
@@ -0,0 +1,27 @@
<?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\Component\Routing\Tests\Fixtures\AnnotationFixtures;

use Symfony\Component\Routing\Annotation\Route;

/**
* @Route("/", requirements={"foo", "\d+"})
*/
class RequirementsWithoutPlaceholderNameController
{
/**
* @Route("/{foo}", name="foo", requirements={"foo", "\d+"})
*/
public function foo()
{
}
}
@@ -0,0 +1,4 @@
foo:
path: '/{foo}'
requirements:
- '\d+'
Expand Up @@ -33,6 +33,7 @@
use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\NothingButNameController;
use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\PrefixedActionLocalizedRouteController;
use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\PrefixedActionPathController;
use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\RequirementsWithoutPlaceholderNameController;
use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\RouteWithPrefixController;

class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
Expand Down Expand Up @@ -87,6 +88,18 @@ public function testSimplePathRoute()
$this->assertEquals('/path', $routes->get('action')->getPath());
}

/**
* @group legacy
* @expectedDeprecation A placeholder name must be a string (0 given). Did you forget to specify the placeholder key for the requirement "foo" in "Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\RequirementsWithoutPlaceholderNameController"?
* @expectedDeprecation A placeholder name must be a string (1 given). Did you forget to specify the placeholder key for the requirement "\d+" in "Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\RequirementsWithoutPlaceholderNameController"?
* @expectedDeprecation A placeholder name must be a string (0 given). Did you forget to specify the placeholder key for the requirement "foo" of route "foo" in "Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\RequirementsWithoutPlaceholderNameController::foo()"?
* @expectedDeprecation A placeholder name must be a string (1 given). Did you forget to specify the placeholder key for the requirement "\d+" of route "foo" in "Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\RequirementsWithoutPlaceholderNameController::foo()"?
*/
public function testRequirementsWithoutPlaceholderName()
{
$this->loader->load(RequirementsWithoutPlaceholderNameController::class);
}

public function testInvokableControllerLoader()
{
$routes = $this->loader->load(InvokableController::class);
Expand Down
10 changes: 10 additions & 0 deletions src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php
Expand Up @@ -304,4 +304,14 @@ public function testImportRouteWithNoTrailingSlash()
$this->assertEquals('/slash/', $routeCollection->get('a_app_homepage')->getPath());
$this->assertEquals('/no-slash', $routeCollection->get('b_app_homepage')->getPath());
}

/**
* @group legacy
* @expectedDeprecation A placeholder name must be a string (0 given). Did you forget to specify the placeholder key for the requirement "\d+" of route "foo" in "%srequirements_without_placeholder_name.yml"?
*/
public function testRequirementsWithoutPlaceholderName()
{
$loader = new YamlFileLoader(new FileLocator(array(__DIR__.'/../Fixtures')));
$loader->load('requirements_without_placeholder_name.yml');
}
}

0 comments on commit c85134c

Please sign in to comment.