Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d8b3cc6

Browse filesBrowse files
committed
feature #58819 [Routing] Allow aliases in #[Route] attribute (damienfern)
This PR was squashed before being merged into the 7.3 branch. Discussion ---------- [Routing] Allow aliases in `#[Route]` attribute | Q | A | ------------- | --- | Branch? | 7.3 | Bug fix? | no | New feature? | yes <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | License | MIT While scrolling the [Routing documentation](https://symfony.com/doc/current/routing.html#route-aliasing), I noticed that we can't configure aliases with the `#[Route]` attribute. With this PR, we can. ```php #[Route('/path', name: 'action_with_alias', alias: ['alias', 'completely_different_name'])] public function action() { } ``` <!-- Replace this notice by a description of your feature/bugfix. This will help reviewers and should be a good start for the documentation. Additionally (see https://symfony.com/releases): - Always add tests and ensure they pass. - 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 latest branch. - For new features, provide some code snippets to help understand usage. - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry - Never break backward compatibility (see https://symfony.com/bc). --> Commits ------- d2ae097 [Routing] Allow aliases in `#[Route]` attribute
2 parents 4fdf3f7 + d2ae097 commit d8b3cc6
Copy full SHA for d8b3cc6

13 files changed

+368
-16
lines changed
+46Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Attribute;
13+
14+
/**
15+
* This class is meant to be used in {@see Route} to define an alias for a route.
16+
*/
17+
class DeprecatedAlias
18+
{
19+
public function __construct(
20+
private string $aliasName,
21+
private string $package,
22+
private string $version,
23+
private string $message = '',
24+
) {
25+
}
26+
27+
public function getMessage(): string
28+
{
29+
return $this->message;
30+
}
31+
32+
public function getAliasName(): string
33+
{
34+
return $this->aliasName;
35+
}
36+
37+
public function getPackage(): string
38+
{
39+
return $this->package;
40+
}
41+
42+
public function getVersion(): string
43+
{
44+
return $this->version;
45+
}
46+
}

‎src/Symfony/Component/Routing/Attribute/Route.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Attribute/Route.php
+38-15Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,28 @@ class Route
2222
private array $localizedPaths = [];
2323
private array $methods;
2424
private array $schemes;
25+
/**
26+
* @var (string|DeprecatedAlias)[]
27+
*/
28+
private array $aliases = [];
2529

2630
/**
27-
* @param string|array<string,string>|null $path The route path (i.e. "/user/login")
28-
* @param string|null $name The route name (i.e. "app_user_login")
29-
* @param array<string|\Stringable> $requirements Requirements for the route attributes, @see https://symfony.com/doc/current/routing.html#parameters-validation
30-
* @param array<string, mixed> $options Options for the route (i.e. ['prefix' => '/api'])
31-
* @param array<string, mixed> $defaults Default values for the route attributes and query parameters
32-
* @param string|null $host The host for which this route should be active (i.e. "localhost")
33-
* @param string|string[] $methods The list of HTTP methods allowed by this route
34-
* @param string|string[] $schemes The list of schemes allowed by this route (i.e. "https")
35-
* @param string|null $condition An expression that must evaluate to true for the route to be matched, @see https://symfony.com/doc/current/routing.html#matching-expressions
36-
* @param int|null $priority The priority of the route if multiple ones are defined for the same path
37-
* @param string|null $locale The locale accepted by the route
38-
* @param string|null $format The format returned by the route (i.e. "json", "xml")
39-
* @param bool|null $utf8 Whether the route accepts UTF-8 in its parameters
40-
* @param bool|null $stateless Whether the route is defined as stateless or stateful, @see https://symfony.com/doc/current/routing.html#stateless-routes
41-
* @param string|null $env The env in which the route is defined (i.e. "dev", "test", "prod")
31+
* @param string|array<string,string>|null $path The route path (i.e. "/user/login")
32+
* @param string|null $name The route name (i.e. "app_user_login")
33+
* @param array<string|\Stringable> $requirements Requirements for the route attributes, @see https://symfony.com/doc/current/routing.html#parameters-validation
34+
* @param array<string, mixed> $options Options for the route (i.e. ['prefix' => '/api'])
35+
* @param array<string, mixed> $defaults Default values for the route attributes and query parameters
36+
* @param string|null $host The host for which this route should be active (i.e. "localhost")
37+
* @param string|string[] $methods The list of HTTP methods allowed by this route
38+
* @param string|string[] $schemes The list of schemes allowed by this route (i.e. "https")
39+
* @param string|null $condition An expression that must evaluate to true for the route to be matched, @see https://symfony.com/doc/current/routing.html#matching-expressions
40+
* @param int|null $priority The priority of the route if multiple ones are defined for the same path
41+
* @param string|null $locale The locale accepted by the route
42+
* @param string|null $format The format returned by the route (i.e. "json", "xml")
43+
* @param bool|null $utf8 Whether the route accepts UTF-8 in its parameters
44+
* @param bool|null $stateless Whether the route is defined as stateless or stateful, @see https://symfony.com/doc/current/routing.html#stateless-routes
45+
* @param string|null $env The env in which the route is defined (i.e. "dev", "test", "prod")
46+
* @param string|DeprecatedAlias|(string|DeprecatedAlias)[] $alias The list of aliases for this route
4247
*/
4348
public function __construct(
4449
string|array|null $path = null,
@@ -56,6 +61,7 @@ public function __construct(
5661
?bool $utf8 = null,
5762
?bool $stateless = null,
5863
private ?string $env = null,
64+
string|DeprecatedAlias|array $alias = [],
5965
) {
6066
if (\is_array($path)) {
6167
$this->localizedPaths = $path;
@@ -64,6 +70,7 @@ public function __construct(
6470
}
6571
$this->setMethods($methods);
6672
$this->setSchemes($schemes);
73+
$this->setAliases($alias);
6774

6875
if (null !== $locale) {
6976
$this->defaults['_locale'] = $locale;
@@ -201,6 +208,22 @@ public function getEnv(): ?string
201208
{
202209
return $this->env;
203210
}
211+
212+
/**
213+
* @return (string|DeprecatedAlias)[]
214+
*/
215+
public function getAliases(): array
216+
{
217+
return $this->aliases;
218+
}
219+
220+
/**
221+
* @param string|DeprecatedAlias|(string|DeprecatedAlias)[] $aliases
222+
*/
223+
public function setAliases(string|DeprecatedAlias|array $aliases): void
224+
{
225+
$this->aliases = \is_array($aliases) ? $aliases : [$aliases];
226+
}
204227
}
205228

206229
if (!class_exists(\Symfony\Component\Routing\Annotation\Route::class, false)) {

‎src/Symfony/Component/Routing/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.3
5+
---
6+
7+
* Allow aliases and deprecations in `#[Route]` attribute
8+
49
7.2
510
---
611

‎src/Symfony/Component/Routing/Loader/AttributeClassLoader.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Loader/AttributeClassLoader.php
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
use Symfony\Component\Config\Loader\LoaderInterface;
1515
use Symfony\Component\Config\Loader\LoaderResolverInterface;
1616
use Symfony\Component\Config\Resource\FileResource;
17+
use Symfony\Component\Routing\Attribute\DeprecatedAlias;
1718
use Symfony\Component\Routing\Attribute\Route as RouteAttribute;
19+
use Symfony\Component\Routing\Exception\InvalidArgumentException;
1820
use Symfony\Component\Routing\Exception\LogicException;
1921
use Symfony\Component\Routing\Route;
2022
use Symfony\Component\Routing\RouteCollection;
@@ -107,6 +109,15 @@ public function load(mixed $class, ?string $type = null): RouteCollection
107109
return $collection;
108110
}
109111
$fqcnAlias = false;
112+
113+
if (!$class->hasMethod('__invoke')) {
114+
foreach ($this->getAttributes($class) as $attr) {
115+
if ($attr->getAliases()) {
116+
throw new InvalidArgumentException(\sprintf('Route aliases cannot be used on non-invokable class "%s".', $class->getName()));
117+
}
118+
}
119+
}
120+
110121
foreach ($class->getMethods() as $method) {
111122
$this->defaultRouteIndex = 0;
112123
$routeNamesBefore = array_keys($collection->all());
@@ -230,6 +241,19 @@ protected function addRoute(RouteCollection $collection, object $attr, array $gl
230241
} else {
231242
$collection->add($name, $route, $priority);
232243
}
244+
foreach ($attr->getAliases() as $aliasAttribute) {
245+
if ($aliasAttribute instanceof DeprecatedAlias) {
246+
$alias = $collection->addAlias($aliasAttribute->getAliasName(), $name);
247+
$alias->setDeprecated(
248+
$aliasAttribute->getPackage(),
249+
$aliasAttribute->getVersion(),
250+
$aliasAttribute->getMessage()
251+
);
252+
continue;
253+
}
254+
255+
$collection->addAlias($aliasAttribute, $name);
256+
}
233257
}
234258
}
235259

‎src/Symfony/Component/Routing/Tests/Attribute/RouteTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Attribute/RouteTest.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace Symfony\Component\Routing\Tests\Annotation;
12+
namespace Symfony\Component\Routing\Tests\Attribute;
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Routing\Attribute\Route;
@@ -40,6 +40,7 @@ public static function getValidParameters(): iterable
4040
['methods', 'getMethods', ['GET', 'POST']],
4141
['host', 'getHost', '{locale}.example.com'],
4242
['condition', 'getCondition', 'context.getMethod() == \'GET\''],
43+
['alias', 'getAliases', ['alias', 'completely_different_name']],
4344
];
4445
}
4546
}
+29Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures;
13+
14+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
15+
use Symfony\Component\Routing\Attribute\Route;
16+
17+
#[Route('/hello', alias: ['alias', 'completely_different_name'])]
18+
class AliasClassController
19+
{
20+
#[Route('/world')]
21+
public function actionWorld()
22+
{
23+
}
24+
25+
#[Route('/symfony')]
26+
public function actionSymfony()
27+
{
28+
}
29+
}
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures;
13+
14+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
15+
use Symfony\Component\Routing\Attribute\Route;
16+
17+
#[Route('/path', name:'invokable_path', alias: ['alias', 'completely_different_name'])]
18+
class AliasInvokableController
19+
{
20+
public function __invoke()
21+
{
22+
}
23+
}
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures;
13+
14+
use Symfony\Component\Routing\Attribute\Route;
15+
16+
class AliasRouteController
17+
{
18+
#[Route('/path', name: 'action_with_alias', alias: ['alias', 'completely_different_name'])]
19+
public function action()
20+
{
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures;
13+
14+
use Symfony\Component\Routing\Attribute\DeprecatedAlias;
15+
use Symfony\Component\Routing\Attribute\Route;
16+
17+
class DeprecatedAliasCustomMessageRouteController
18+
{
19+
20+
#[Route('/path', name: 'action_with_deprecated_alias', alias: new DeprecatedAlias('my_other_alias_deprecated', 'MyBundleFixture', '1.0', message: '%alias_id% alias is deprecated.'))]
21+
public function action()
22+
{
23+
}
24+
}
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures;
13+
14+
use Symfony\Component\Routing\Attribute\DeprecatedAlias;
15+
use Symfony\Component\Routing\Attribute\Route;
16+
17+
class DeprecatedAliasRouteController
18+
{
19+
#[Route('/path', name: 'action_with_deprecated_alias', alias: new DeprecatedAlias('my_other_alias_deprecated', 'MyBundleFixture', '1.0'))]
20+
public function action()
21+
{
22+
}
23+
}

‎src/Symfony/Component/Routing/Tests/Fixtures/AttributeFixtures/FooController.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Fixtures/AttributeFixtures/FooController.php
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,9 @@ public function host()
5555
public function condition()
5656
{
5757
}
58+
59+
#[Route(alias: ['alias', 'completely_different_name'])]
60+
public function alias()
61+
{
62+
}
5863
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures;
13+
14+
use Symfony\Component\Routing\Attribute\DeprecatedAlias;
15+
use Symfony\Component\Routing\Attribute\Route;
16+
17+
class MultipleDeprecatedAliasRouteController
18+
{
19+
#[Route('/path', name: 'action_with_multiple_deprecated_alias', alias: [
20+
new DeprecatedAlias('my_first_alias_deprecated', 'MyFirstBundleFixture', '1.0'),
21+
new DeprecatedAlias('my_second_alias_deprecated', 'MySecondBundleFixture', '2.0'),
22+
new DeprecatedAlias('my_third_alias_deprecated', 'SurprisedThirdBundleFixture', '3.0'),
23+
])]
24+
public function action()
25+
{
26+
}
27+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.