Skip to content

Commit a1ef1ee

Browse files
committed
[Routing] allow setting multiple envs in #[Route] attribute
1 parent fe8a2de commit a1ef1ee

File tree

5 files changed

+81
-6
lines changed

5 files changed

+81
-6
lines changed

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

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Routing\Attribute;
1313

14+
use Symfony\Component\Routing\Exception\LogicException;
15+
1416
/**
1517
* @author Fabien Potencier <fabien@symfony.com>
1618
* @author Alexander M. Turek <me@derrabus.de>
@@ -21,6 +23,8 @@ class Route
2123
private ?string $path = null;
2224
private array $localizedPaths = [];
2325
private array $methods;
26+
/** @var string[] */
27+
private array $env;
2428
private array $schemes;
2529
/**
2630
* @var (string|DeprecatedAlias)[]
@@ -42,7 +46,7 @@ class Route
4246
* @param string|null $format The format returned by the route (i.e. "json", "xml")
4347
* @param bool|null $utf8 Whether the route accepts UTF-8 in its parameters
4448
* @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")
49+
* @param string|string[]|null $env The env(s) in which the route is defined (i.e. "dev", "test", "prod", ["dev", "test"])
4650
* @param string|DeprecatedAlias|(string|DeprecatedAlias)[] $alias The list of aliases for this route
4751
*/
4852
public function __construct(
@@ -60,7 +64,7 @@ public function __construct(
6064
?string $format = null,
6165
?bool $utf8 = null,
6266
?bool $stateless = null,
63-
private ?string $env = null,
67+
string|array|null $env = null,
6468
string|DeprecatedAlias|array $alias = [],
6569
) {
6670
if (\is_array($path)) {
@@ -71,6 +75,7 @@ public function __construct(
7175
$this->setMethods($methods);
7276
$this->setSchemes($schemes);
7377
$this->setAliases($alias);
78+
$this->setEnvs((array) $env);
7479

7580
if (null !== $locale) {
7681
$this->defaults['_locale'] = $locale;
@@ -199,12 +204,37 @@ public function getPriority(): ?int
199204
return $this->priority;
200205
}
201206

207+
/**
208+
* @deprecated since Symfony 7.4, use the {@see setEnvs()} method instead
209+
*/
202210
public function setEnv(?string $env): void
203211
{
204-
$this->env = $env;
212+
trigger_deprecation('symfony/routing', '7.4', 'The "%s()" method is deprecated, use "setEnvs()" instead.', __METHOD__);
213+
$this->env = (array) $env;
205214
}
206215

216+
/**
217+
* @deprecated since Symfony 7.4, use {@see getEnvs()} method instead
218+
*/
207219
public function getEnv(): ?string
220+
{
221+
trigger_deprecation('symfony/routing', '7.4', 'The "%s()" method is deprecated, use "getEnvs()" instead.', __METHOD__);
222+
if (!$this->env) {
223+
return null;
224+
}
225+
if (\count($this->env) > 1) {
226+
throw new LogicException(\sprintf('The "env" property has %d environments. Use "getEnvs()" to get all of them.', \count($this->env)));
227+
}
228+
229+
return $this->env[0];
230+
}
231+
232+
public function setEnvs(array $env): void
233+
{
234+
$this->env = $env;
235+
}
236+
237+
public function getEnvs(): array
208238
{
209239
return $this->env;
210240
}

src/Symfony/Component/Routing/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Allow query-specific parameters in `UrlGenerator` using `_query`
8+
* Allow multiple environments in `#[Route]` attribute
89

910
7.3
1011
---

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public function load(mixed $class, ?string $type = null): RouteCollection
105105
$globals = $this->getGlobals($class);
106106
$collection = new RouteCollection();
107107
$collection->addResource(new FileResource($class->getFileName()));
108-
if ($globals['env'] && $this->env !== $globals['env']) {
108+
if ($globals['env'] && !\in_array($this->env, $globals['env'])) {
109109
return $collection;
110110
}
111111
$fqcnAlias = false;
@@ -161,7 +161,7 @@ public function load(mixed $class, ?string $type = null): RouteCollection
161161
*/
162162
protected function addRoute(RouteCollection $collection, object $attr, array $globals, \ReflectionClass $class, \ReflectionMethod $method): void
163163
{
164-
if ($attr->getEnv() && $attr->getEnv() !== $this->env) {
164+
if ($attr->getEnvs() && !\in_array($this->env, $attr->getEnvs())) {
165165
return;
166166
}
167167

@@ -338,7 +338,7 @@ protected function getGlobals(\ReflectionClass $class): array
338338
}
339339

340340
$globals['priority'] = $attr->getPriority() ?? 0;
341-
$globals['env'] = $attr->getEnv();
341+
$globals['env'] = $attr->getEnvs();
342342

343343
foreach ($globals['requirements'] as $placeholder => $requirement) {
344344
if (\is_int($placeholder)) {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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 RouteWithMultipleEnvs
17+
{
18+
#[Route(path: '/path', name: 'first_action', env: 'first-env')]
19+
public function firstAction()
20+
{
21+
}
22+
23+
#[Route(path: '/path2', name: 'second_action', env: ['first-env', 'second-env'])]
24+
public function secondAction()
25+
{
26+
}
27+
28+
#[Route(path: '/path3', name: 'third_action', env: ['first-env', 'third-env'])]
29+
public function thirdAction()
30+
{
31+
}
32+
}

src/Symfony/Component/Routing/Tests/Loader/AttributeClassLoaderTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\PrefixedActionPathController;
4848
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\RequirementsWithoutPlaceholderNameController;
4949
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\RouteWithEnv;
50+
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\RouteWithMultipleEnvs;
5051
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\RouteWithPrefixController;
5152
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\Utf8ActionControllers;
5253
use Symfony\Component\Routing\Tests\Fixtures\TraceableAttributeClassLoader;
@@ -334,6 +335,17 @@ public function testWhenEnv()
334335
$this->assertSame('/path', $routes->get('action')->getPath());
335336
}
336337

338+
public function testWhenMultipleEnvs()
339+
{
340+
$routes = $this->loader->load(RouteWithMultipleEnvs::class);
341+
$this->assertCount(0, $routes);
342+
343+
$this->setUp('second-env');
344+
$routes = $this->loader->load(RouteWithMultipleEnvs::class);
345+
$this->assertCount(1, $routes);
346+
$this->assertSame('/path2', $routes->get('second_action')->getPath());
347+
}
348+
337349
public function testMethodsAndSchemes()
338350
{
339351
$routes = $this->loader->load(MethodsAndSchemes::class);

0 commit comments

Comments
 (0)