Skip to content

Commit 21e3738

Browse files
committed
bug #40767 [Routing] Fix localized paths (l-vo)
This PR was merged into the 5.3-dev branch. Discussion ---------- [Routing] Fix localized paths | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | | License | MIT | Doc PR | Related to #40266, localized paths does not work anymore. This PR aims to fix that and add a rework on the tests (using real annotations/attributes instead of guessing the parsing that may lead to errors). Commits ------- 9bf4a24 [Routing] Fix localized paths
2 parents 2ba1f89 + 9bf4a24 commit 21e3738

File tree

4 files changed

+208
-35
lines changed

4 files changed

+208
-35
lines changed

src/Symfony/Component/Routing/Annotation/Route.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,19 @@ public function __construct(
6969
} elseif (!\is_array($data)) {
7070
throw new \TypeError(sprintf('"%s": Argument $data is expected to be a string or array, got "%s".', __METHOD__, get_debug_type($data)));
7171
} elseif ([] !== $data) {
72-
trigger_deprecation('symfony/routing', '5.3', 'Passing an array as first argument to "%s" is deprecated. Use named arguments instead.', __METHOD__);
72+
$deprecation = false;
73+
foreach ($data as $key => $val) {
74+
if (\in_array($key, ['path', 'name', 'requirements', 'options', 'defaults', 'host', 'methods', 'schemes', 'condition', 'priority', 'locale', 'format', 'utf8', 'stateless', 'env', 'value'])) {
75+
$deprecation = true;
76+
}
77+
}
78+
79+
if ($deprecation) {
80+
trigger_deprecation('symfony/routing', '5.3', 'Passing an array as first argument to "%s" is deprecated. Use named arguments instead.', __METHOD__);
81+
} else {
82+
$localizedPaths = $data;
83+
$data = ['path' => $localizedPaths];
84+
}
7385
}
7486
if (null !== $path && !\is_string($path) && !\is_array($path)) {
7587
throw new \TypeError(sprintf('"%s": Argument $path is expected to be a string, array or null, got "%s".', __METHOD__, get_debug_type($path)));

src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php

+59-34
Original file line numberDiff line numberDiff line change
@@ -11,73 +11,98 @@
1111

1212
namespace Symfony\Component\Routing\Tests\Annotation;
1313

14+
use Doctrine\Common\Annotations\AnnotationReader;
1415
use PHPUnit\Framework\TestCase;
1516
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1617
use Symfony\Component\Routing\Annotation\Route;
18+
use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\FooController;
19+
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\FooController as FooAttributesController;
1720

1821
class RouteTest extends TestCase
1922
{
2023
use ExpectDeprecationTrait;
2124

22-
/**
23-
* @group legacy
24-
*/
25-
public function testInvalidRouteParameter()
25+
private function getMethodAnnotation(string $method, bool $attributes): Route
2626
{
27-
$this->expectException(\BadMethodCallException::class);
28-
new Route(['foo' => 'bar']);
27+
$class = $attributes ? FooAttributesController::class : FooController::class;
28+
$reflection = new \ReflectionMethod($class, $method);
29+
30+
if ($attributes) {
31+
$attributes = $reflection->getAttributes(Route::class);
32+
$route = $attributes[0]->newInstance();
33+
} else {
34+
$reader = new AnnotationReader();
35+
$route = $reader->getMethodAnnotation($reflection, Route::class);
36+
}
37+
38+
if (!$route instanceof Route) {
39+
throw new \Exception('Can\'t parse annotation');
40+
}
41+
42+
return $route;
43+
}
44+
45+
public function provideDeprecationArrayAsFirstArgument()
46+
{
47+
return [
48+
['requirements', ['locale' => 'en'], 'getRequirements'],
49+
['options', ['compiler_class' => 'RouteCompiler'], 'getOptions'],
50+
['name', 'blog_index', 'getName'],
51+
['defaults', ['_controller' => 'MyBlogBundle:Blog:index'], 'getDefaults'],
52+
['schemes', ['https'], 'getSchemes'],
53+
['methods', ['GET', 'POST'], 'getMethods'],
54+
['host', '{locale}.example.com', 'getHost'],
55+
['condition', 'context.getMethod() == "GET"', 'getCondition'],
56+
['value', '/Blog', 'getPath'],
57+
['value', ['nl' => '/hier', 'en' => '/here'], 'getLocalizedPaths'],
58+
];
2959
}
3060

3161
/**
3262
* @group legacy
63+
* @dataProvider provideDeprecationArrayAsFirstArgument
3364
*/
34-
public function testTryingToSetLocalesDirectly()
65+
public function testDeprecationArrayAsFirstArgument(string $parameter, $value, string $getter)
3566
{
36-
$this->expectException(\BadMethodCallException::class);
37-
new Route(['locales' => ['nl' => 'bar']]);
67+
$this->expectDeprecation('Since symfony/routing 5.3: Passing an array as first argument to "Symfony\Component\Routing\Annotation\Route::__construct" is deprecated. Use named arguments instead.');
68+
69+
$route = new Route([$parameter => $value]);
70+
$this->assertEquals($route->$getter(), $value);
3871
}
3972

4073
/**
4174
* @requires PHP 8
4275
* @dataProvider getValidParameters
4376
*/
44-
public function testRouteParameters(string $parameter, $value, string $getter)
77+
public function testRouteParameters(string $methodName, string $getter, $expectedReturn)
4578
{
46-
$route = new Route(...[$parameter => $value]);
47-
$this->assertEquals($route->$getter(), $value);
79+
$route = $this->getMethodAnnotation($methodName, true);
80+
$this->assertEquals($route->$getter(), $expectedReturn);
4881
}
4982

5083
/**
5184
* @group legacy
52-
* @dataProvider getLegacyValidParameters
85+
* @dataProvider getValidParameters
5386
*/
54-
public function testLegacyRouteParameters(string $parameter, $value, string $getter)
87+
public function testLegacyRouteParameters(string $methodName, string $getter, $expectedReturn)
5588
{
56-
$this->expectDeprecation('Since symfony/routing 5.3: Passing an array as first argument to "Symfony\Component\Routing\Annotation\Route::__construct" is deprecated. Use named arguments instead.');
57-
58-
$route = new Route([$parameter => $value]);
59-
$this->assertEquals($route->$getter(), $value);
89+
$route = $this->getMethodAnnotation($methodName, false);
90+
$this->assertEquals($route->$getter(), $expectedReturn);
6091
}
6192

6293
public function getValidParameters(): iterable
6394
{
6495
return [
65-
['requirements', ['locale' => 'en'], 'getRequirements'],
66-
['options', ['compiler_class' => 'RouteCompiler'], 'getOptions'],
67-
['name', 'blog_index', 'getName'],
68-
['defaults', ['_controller' => 'MyBlogBundle:Blog:index'], 'getDefaults'],
69-
['schemes', ['https'], 'getSchemes'],
70-
['methods', ['GET', 'POST'], 'getMethods'],
71-
['host', '{locale}.example.com', 'getHost'],
72-
['condition', 'context.getMethod() == "GET"', 'getCondition'],
96+
['simplePath', 'getPath', '/Blog'],
97+
['localized', 'getLocalizedPaths', ['nl' => '/hier', 'en' => '/here']],
98+
['requirements', 'getRequirements', ['locale' => 'en']],
99+
['options', 'getOptions', ['compiler_class' => 'RouteCompiler']],
100+
['name', 'getName', 'blog_index'],
101+
['defaults', 'getDefaults', ['_controller' => 'MyBlogBundle:Blog:index']],
102+
['schemes', 'getSchemes', ['https']],
103+
['methods', 'getMethods', ['GET', 'POST']],
104+
['host', 'getHost', '{locale}.example.com'],
105+
['condition', 'getCondition', 'context.getMethod() == \'GET\''],
73106
];
74107
}
75-
76-
public function getLegacyValidParameters(): iterable
77-
{
78-
yield from $this->getValidParameters();
79-
80-
yield ['value', '/Blog', 'getPath'];
81-
yield ['value', ['nl' => '/hier', 'en' => '/here'], 'getLocalizedPaths'];
82-
}
83108
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
namespace Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures;
4+
5+
use Symfony\Component\Routing\Annotation\Route;
6+
7+
class FooController
8+
{
9+
/**
10+
* @Route("/Blog")
11+
*/
12+
public function simplePath()
13+
{
14+
}
15+
16+
/**
17+
* @Route({"nl":"/hier","en":"/here"})
18+
*/
19+
public function localized()
20+
{
21+
}
22+
23+
/**
24+
* @Route(requirements={"locale":"en"})
25+
*/
26+
public function requirements()
27+
{
28+
}
29+
30+
/**
31+
* @Route(options={"compiler_class":"RouteCompiler"})
32+
*/
33+
public function options()
34+
{
35+
}
36+
37+
/**
38+
* @Route(name="blog_index")
39+
*/
40+
public function name()
41+
{
42+
}
43+
44+
/**
45+
* @Route(defaults={"_controller":"MyBlogBundle:Blog:index"})
46+
*/
47+
public function defaults()
48+
{
49+
}
50+
51+
/**
52+
* @Route(schemes={"https"})
53+
*/
54+
public function schemes()
55+
{
56+
}
57+
58+
/**
59+
* @Route(methods={"GET","POST"})
60+
*/
61+
public function methods()
62+
{
63+
}
64+
65+
/**
66+
* @Route(host="{locale}.example.com")
67+
*/
68+
public function host()
69+
{
70+
}
71+
72+
/**
73+
* @Route(condition="context.getMethod() == 'GET'")
74+
*/
75+
public function condition()
76+
{
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
namespace Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures;
4+
5+
use Symfony\Component\Routing\Annotation\Route;
6+
7+
class FooController
8+
{
9+
#[Route('/Blog')]
10+
public function simplePath()
11+
{
12+
}
13+
14+
#[Route(['nl' => '/hier', 'en' => '/here'])]
15+
public function localized()
16+
{
17+
}
18+
19+
#[Route(requirements: ['locale' => 'en'])]
20+
public function requirements()
21+
{
22+
}
23+
24+
#[Route(options: ['compiler_class' => 'RouteCompiler'])]
25+
public function options()
26+
{
27+
}
28+
29+
#[Route(name: 'blog_index')]
30+
public function name()
31+
{
32+
}
33+
34+
#[Route(defaults: ['_controller' => 'MyBlogBundle:Blog:index'])]
35+
public function defaults()
36+
{
37+
}
38+
39+
#[Route(schemes: ['https'])]
40+
public function schemes()
41+
{
42+
}
43+
44+
#[Route(methods: ['GET', 'POST'])]
45+
public function methods()
46+
{
47+
}
48+
49+
#[Route(host: '{locale}.example.com')]
50+
public function host()
51+
{
52+
}
53+
54+
#[Route(condition: 'context.getMethod() == \'GET\'')]
55+
public function condition()
56+
{
57+
}
58+
}

0 commit comments

Comments
 (0)