8000 feature #40782 [DependencyInjection] Add `#[When(env: 'foo')]` to ski… · symfony/symfony@4cac9cf · GitHub
[go: up one dir, main page]

Skip to content

Commit 4cac9cf

Browse files
feature #40782 [DependencyInjection] Add #[When(env: 'foo')] to skip autoregistering a class when the env doesn't match (nicolas-grekas)
This PR was merged into the 5.3-dev branch. Discussion ---------- [DependencyInjection] Add `#[When(env: 'foo')]` to skip autoregistering a class when the env doesn't match | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - This is a follow up of #40214, in order to conditionally auto-register classes. By adding a `#[When(env: prod)]` annotation on a class, one can tell that a class should be skipped when the current env doesn't match the one declared in the attribute. This saves from writing similar conditional configuration by using the per-env `services_prod.yaml` convention (+corresponding exclusion from `services.yaml`), or some logic in the Kernel. Commits ------- 59c75ba [DI] add `#[When(env: 'foo')]` to skip autoregistering a class when the env doesn't match
2 parents 2edebff + 59c75ba commit 4cac9cf

File tree

7 files changed

+83
-3
lines changed

7 files changed

+83
-3
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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\DependencyInjection\Attribute;
13+
14+
/**
15+
* An attribute to tell under which environement this class should be registered as a service.
16+
*
17+
* @author Nicolas Grekas <p@tchwork.com>
18+
*/
19+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
20+
class When
21+
{
22+
public function __construct(
23+
public string $env,
24+
) {
25+
}
26+
}

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ CHANGELOG
1313
* Add support for per-env configuration in XML and Yaml loaders
1414
* Add `ContainerBuilder::willBeAvailable()` to help with conditional configuration
1515
* Add support an integer return value for default_index_method
16+
* Add `#[When(env: 'foo')]` to skip autoregistering a class when the env doesn't match
1617
* Add `env()` and `EnvConfigurator` in the PHP-DSL
1718
* Add support for `ConfigBuilder` in the `PhpFileLoader`
1819
* Add `ContainerConfigurator::env()` to get the current environment

src/Symfony/Component/DependencyInjection/Loader/FileLoader.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader;
1818
use Symfony\Component\Config\Loader\Loader;
1919
use Symfony\Component\Config\Resource\GlobResource;
20+
use Symfony\Component\DependencyInjection\Attribute\When;
2021
use Symfony\Component\DependencyInjection\ChildDefinition;
2122
use Symfony\Component\DependencyInjection\Compiler\RegisterAutoconfigureAttributesPass;
2223
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -98,11 +99,26 @@ public function registerClasses(Definition $prototype, string $namespace, string
9899
}
99100

100101
$autoconfigureAttributes = new RegisterAutoconfigureAttributesPass();
101-
$classes = $this->findClasses($namespace, $resource, (array) $exclude, $autoconfigureAttributes->accept($prototype) ? $autoconfigureAttributes : null);
102+
$autoconfigureAttributes = $autoconfigureAttributes->accept($prototype) ? $autoconfigureAttributes : null;
103+
$classes = $this->findClasses($namespace, $resource, (array) $exclude, $autoconfigureAttributes);
102104
// prepare for deep cloning
103105
$serializedPrototype = serialize($prototype);
104106

105107
foreach ($classes as $class => $errorMessage) {
108+
if ($autoconfigureAttributes && $this->env) {
109+
$r = $this->container->getReflectionClass($class);
110+
$attribute = null;
111+
foreach ($r->getAttributes(When::class) as $attribute) {
112+
if ($this->env === $attribute->newInstance()->env) {
113+
$attribute = null;
114+
break;
115+
}
116+
}
117+
if (null !== $attribute) {
118+
continue;
119+
}
120+
}
121+
106122
if (interface_exists($class, false)) {
107123
$this->interfaces[] = $class;
108124
} else {

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@ public function load($resource, string $type = null)
5050

5151
$this->container->fileExists($path);
5252

53-
$this->loadXml($xml, $path);
53+
$env = $this->env;
54+
$this->env = null;
55+
try {
56+
$this->loadXml($xml, $path);
57+
} finally {
58+
$this->env = $env;
59+
}
5460

5561
if ($this->env) {
5662
$xpath = new \DOMXPath($xml);

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,13 @@ public function load($resource, string $type = null)
129129
return;
130130
}
131131

132-
$this->loadContent($content, $path);
132+
$env = $this->env;
133+
$this->env = null;
134+
try {
135+
$this->loadContent($content, $path);
136+
} finally {
137+
$this->env = $env;
138+
}
133139

134140
// per-env configuration
135141
if ($this->env && isset($content['when@'.$this->env])) {

src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
44

5+
use Symfony\Component\DependencyInjection\Attribute\When;
6+
7+
#[When(env: 'prod')]
8+
#[When(env: 'dev')]
59
class Foo implements FooInterface, Sub\BarInterface
610
{
711
public function __construct($bar = null)

src/Symfony/Component/DependencyInjection/Tests/Loader/FileLoaderTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,27 @@ public function testRegisterClassesWithIncompatibleExclude()
243243
'yaml/*'
244244
);
245245
}
246+
247+
/**
248+
* @r CC25 equires PHP 8
249+
*
250+
* @testWith ["prod", true]
251+
* ["dev", true]
252+
* ["bar", false]
253+
* [null, true]
254+
*/
255+
public function testRegisterClassesWithWhenEnv(?string $env, bool $expected)
256+
{
257+
$container = new ContainerBuilder();
258+
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'), $env);
259+
$loader->registerClasses(
260+
(new Definition())->setAutoconfigured(true),
261+
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\',
262+
'Prototype/{Foo.php}'
263+
);
264+
265+
$this->assertSame($expected, $container->has(Foo::class));
266+
}
246267
}
247268

248269
class TestFileLoader extends FileLoader

0 commit comments

Comments
 (0)
0