Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commit0455a84

Browse files
committed
feature#57379 [DependencyInjection] Add#[WhenNot] attribute (alexandre-daubois)
This PR was merged into the 7.2 branch.Discussion----------[DependencyInjection] Add `#[WhenNot]` attribute| Q | A| ------------- | ---| Branch? | 7.2| Bug fix? | no| New feature? | yes| Deprecations? | no| Issues | -| License | MITWhen dealing with many environment and concrete+test implementations of many services, it can be tricky/verbose to repeat `#[When]` for each and every existing env. By using `#[NotWhen]`, it becomes handy to deal with different implementations of a service across different env:```php// ConcreteService.php#[WhenNot(env: 'test')]class ConcreteService implements MyServiceInterface{ public function call() { dump("I'm a concrete service!"); }}// TestService.php#[When(env: 'test')]class TestService implements MyServiceInterface{ public function call() { dump("I'm a test service!"); }}// MyCommand.phpclass MyCommand extends Command{ public function __construct(private MyServiceInterface $service) { parent::__construct(); } // ...}```It also eases the creation of a new env: no more need to go across all `#[When]` occurrences to update service definitions.You cannot use When and NotWhen at the same time:```php#[WhenNot(env: 'dev')]#[When(env: 'test')]class TestService implements MyServiceInterface{ public function call() { dump("I'm a test service!"); }}// Throws a LogicException: The "App\Service\TestService" class cannot have both #[When] and #[NotWhen] attributes.```Commits-------7349e3f [DependencyInjection] Add `#[WhenNot]` attribute
2 parents645f868 +7349e3f commit0455a84

21 files changed

+240
-15
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.2
5+
---
6+
7+
* Add`#[WhenNot]` attribute to prevent service from being registered in a specific environment
8+
49
7.1
510
---
611

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+
namespaceSymfony\Component\DependencyInjection\Attribute;
13+
14+
/**
15+
* An attribute to tell under which environment this class should NOT be registered as a service.
16+
*
17+
* @author Alexandre Daubois <alex.daubois@gmail.com>
18+
*/
19+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)]
20+
class WhenNot
21+
{
22+
publicfunction__construct(
23+
publicstring$env,
24+
) {
25+
}
26+
}

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
useSymfony\Component\DependencyInjection\Attribute\AsAlias;
2222
useSymfony\Component\DependencyInjection\Attribute\Exclude;
2323
useSymfony\Component\DependencyInjection\Attribute\When;
24+
useSymfony\Component\DependencyInjection\Attribute\WhenNot;
2425
useSymfony\Component\DependencyInjection\ChildDefinition;
2526
useSymfony\Component\DependencyInjection\Compiler\RegisterAutoconfigureAttributesPass;
2627
useSymfony\Component\DependencyInjection\ContainerBuilder;
@@ -154,14 +155,32 @@ public function registerClasses(Definition $prototype, string $namespace, string
154155
continue;
155156
}
156157
if ($this->env) {
157-
$attribute =null;
158-
foreach ($r->getAttributes(When::class, \ReflectionAttribute::IS_INSTANCEOF)as$attribute) {
158+
$excluded =true;
159+
$whenAttributes =$r->getAttributes(When::class, \ReflectionAttribute::IS_INSTANCEOF);
160+
$notWhenAttributes =$r->getAttributes(WhenNot::class, \ReflectionAttribute::IS_INSTANCEOF);
161+
162+
if ($whenAttributes &&$notWhenAttributes) {
163+
thrownewLogicException(sprintf('The "%s" class cannot have both #[When] and #[WhenNot] attributes.',$class));
164+
}
165+
166+
if (!$whenAttributes && !$notWhenAttributes) {
167+
$excluded =false;
168+
}
169+
170+
foreach ($whenAttributesas$attribute) {
159171
if ($this->env ===$attribute->newInstance()->env) {
160-
$attribute =null;
172+
$excluded =false;
161173
break;
162174
}
163175
}
164-
if (null !==$attribute) {
176+
177+
foreach ($notWhenAttributesas$attribute) {
178+
if ($excluded =$this->env ===$attribute->newInstance()->env) {
179+
break;
180+
}
181+
}
182+
183+
if ($excluded) {
165184
$this->addContainerExcludedTag($class,$source);
166185
continue;
167186
}

‎src/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php‎

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
useSymfony\Component\Config\Builder\ConfigBuilderInterface;
1717
useSymfony\Component\Config\FileLocatorInterface;
1818
useSymfony\Component\DependencyInjection\Attribute\When;
19+
useSymfony\Component\DependencyInjection\Attribute\WhenNot;
1920
useSymfony\Component\DependencyInjection\Container;
2021
useSymfony\Component\DependencyInjection\ContainerBuilder;
2122
useSymfony\Component\DependencyInjection\Exception\InvalidArgumentException;
23+
useSymfony\Component\DependencyInjection\Exception\LogicException;
2224
useSymfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
2325
useSymfony\Component\DependencyInjection\Extension\ExtensionInterface;
2426
useSymfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
@@ -97,14 +99,32 @@ private function executeCallback(callable $callback, ContainerConfigurator $cont
9799
$configBuilders = [];
98100
$r =new \ReflectionFunction($callback);
99101

100-
$attribute =null;
101-
foreach ($r->getAttributes(When::class, \ReflectionAttribute::IS_INSTANCEOF)as$attribute) {
102+
$excluded =true;
103+
$whenAttributes =$r->getAttributes(When::class, \ReflectionAttribute::IS_INSTANCEOF);
104+
$notWhenAttributes =$r->getAttributes(WhenNot::class, \ReflectionAttribute::IS_INSTANCEOF);
105+
106+
if ($whenAttributes &&$notWhenAttributes) {
107+
thrownewLogicException('Using both #[When] and #[WhenNot] attributes on the same target is not allowed.');
108+
}
109+
110+
if (!$whenAttributes && !$notWhenAttributes) {
111+
$excluded =false;
112+
}
113+
114+
foreach ($whenAttributesas$attribute) {
102115
if ($this->env ===$attribute->newInstance()->env) {
103-
$attribute =null;
116+
$excluded =false;
104117
break;
105118
}
106119
}
107-
if (null !==$attribute) {
120+
121+
foreach ($notWhenAttributesas$attribute) {
122+
if ($excluded =$this->env ===$attribute->newInstance()->env) {
123+
break;
124+
}
125+
}
126+
127+
if ($excluded) {
108128
return;
109129
}
110130

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespaceSymfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadAttributes;
4+
5+
useSymfony\Component\DependencyInjection\Attribute\WhenNot;
6+
useSymfony\Component\DependencyInjection\Attribute\When;
7+
8+
#[When(env:'dev')]
9+
#[WhenNot(env:'test')]
10+
class WhenNotWhenFoo
11+
{
12+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespaceSymfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
4+
5+
useSymfony\Component\DependencyInjection\Attribute\WhenNot;
6+
7+
#[NeverInProduction]
8+
#[WhenNot(env:'dev')]
9+
class NotFoo
10+
{
11+
publicfunction__construct($bar =null, ?iterable$foo =null, ?object$baz =null)
12+
{
13+
}
14+
15+
publicfunctionsetFoo(self$foo)
16+
{
17+
}
18+
}
19+
20+
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::TARGET_FUNCTION | \Attribute::IS_REPEATABLE)]
21+
class NeverInProductionextends WhenNot
22+
{
23+
publicfunction__construct()
24+
{
25+
parent::__construct('prod');
26+
}
27+
}

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/instanceof.expected.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ services:
1616

1717
shared:false
1818
configurator:c
19+
Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\NotFoo:
20+
class:Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\NotFoo
21+
public:true
1922
foo:
2023
class:App\FooService
2124
public:true
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
useSymfony\Component\DependencyInjection\Attribute\WhenNot;
4+
5+
return #[WhenNot(env:'prod')]function () {
6+
thrownewRuntimeException('This code should not be run.');
7+
};

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.expected.yml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ services:
1616
message:'%service_id%'
1717
arguments:[1]
1818
factory:f
19+
Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\NotFoo:
20+
class:Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\NotFoo
21+
public:true
22+
tags:
23+
-foo
24+
-baz
25+
deprecated:
26+
package:vendor/package
27+
version:'1.1'
28+
message:'%service_id%'
29+
lazy:true
30+
arguments:[1]
31+
factory:f
1932
Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar:
2033
class:Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar
2134
public:true

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
$di->load(Prototype::class.'\\','../Prototype')
1111
->public()
1212
->autoconfigure()
13-
->exclude('../Prototype/{OtherDir,BadClasses,SinglyImplementedInterface,StaticConstructor}')
13+
->exclude('../Prototype/{OtherDir,BadClasses,BadAttributes,SinglyImplementedInterface,StaticConstructor}')
1414
->factory('f')
1515
->deprecate('vendor/package','1.1','%service_id%')
1616
->args([0])

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp