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
-------
59c75bad7b
[DI] add `#[When(env: 'foo')]` to skip autoregistering a class when the env doesn't match
This commit is contained in:
commit
4cac9cf829
26
src/Symfony/Component/DependencyInjection/Attribute/When.php
Normal file
26
src/Symfony/Component/DependencyInjection/Attribute/When.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Attribute;
|
||||
|
||||
/**
|
||||
* An attribute to tell under which environement this class should be registered as a service.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
|
||||
class When
|
||||
{
|
||||
public function __construct(
|
||||
public string $env,
|
||||
) {
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ CHANGELOG
|
||||
* Add support for per-env configuration in XML and Yaml loaders
|
||||
* Add `ContainerBuilder::willBeAvailable()` to help with conditional configuration
|
||||
* Add support an integer return value for default_index_method
|
||||
* Add `#[When(env: 'foo')]` to skip autoregistering a class when the env doesn't match
|
||||
* Add `env()` and `EnvConfigurator` in the PHP-DSL
|
||||
* Add support for `ConfigBuilder` in the `PhpFileLoader`
|
||||
* Add `ContainerConfigurator::env()` to get the current environment
|
||||
|
@ -17,6 +17,7 @@ use Symfony\Component\Config\FileLocatorInterface;
|
||||
use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader;
|
||||
use Symfony\Component\Config\Loader\Loader;
|
||||
use Symfony\Component\Config\Resource\GlobResource;
|
||||
use Symfony\Component\DependencyInjection\Attribute\When;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\RegisterAutoconfigureAttributesPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
@ -98,11 +99,26 @@ abstract class FileLoader extends BaseFileLoader
|
||||
}
|
||||
|
||||
$autoconfigureAttributes = new RegisterAutoconfigureAttributesPass();
|
||||
$classes = $this->findClasses($namespace, $resource, (array) $exclude, $autoconfigureAttributes->accept($prototype) ? $autoconfigureAttributes : null);
|
||||
$autoconfigureAttributes = $autoconfigureAttributes->accept($prototype) ? $autoconfigureAttributes : null;
|
||||
$classes = $this->findClasses($namespace, $resource, (array) $exclude, $autoconfigureAttributes);
|
||||
// prepare for deep cloning
|
||||
$serializedPrototype = serialize($prototype);
|
||||
|
||||
foreach ($classes as $class => $errorMessage) {
|
||||
if ($autoconfigureAttributes && $this->env) {
|
||||
$r = $this->container->getReflectionClass($class);
|
||||
$attribute = null;
|
||||
foreach ($r->getAttributes(When::class) as $attribute) {
|
||||
if ($this->env === $attribute->newInstance()->env) {
|
||||
$attribute = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (null !== $attribute) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (interface_exists($class, false)) {
|
||||
$this->interfaces[] = $class;
|
||||
} else {
|
||||
|
@ -50,7 +50,13 @@ class XmlFileLoader extends FileLoader
|
||||
|
||||
$this->container->fileExists($path);
|
||||
|
||||
$env = $this->env;
|
||||
$this->env = null;
|
||||
try {
|
||||
$this->loadXml($xml, $path);
|
||||
} finally {
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
if ($this->env) {
|
||||
$xpath = new \DOMXPath($xml);
|
||||
|
@ -129,7 +129,13 @@ class YamlFileLoader extends FileLoader
|
||||
return;
|
||||
}
|
||||
|
||||
$env = $this->env;
|
||||
$this->env = null;
|
||||
try {
|
||||
$this->loadContent($content, $path);
|
||||
} finally {
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
// per-env configuration
|
||||
if ($this->env && isset($content['when@'.$this->env])) {
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\When;
|
||||
|
||||
#[When(env: 'prod')]
|
||||
#[When(env: 'dev')]
|
||||
class Foo implements FooInterface, Sub\BarInterface
|
||||
{
|
||||
public function __construct($bar = null)
|
||||
|
@ -243,6 +243,27 @@ class FileLoaderTest extends TestCase
|
||||
'yaml/*'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 8
|
||||
*
|
||||
* @testWith ["prod", true]
|
||||
* ["dev", true]
|
||||
* ["bar", false]
|
||||
* [null, true]
|
||||
*/
|
||||
public function testRegisterClassesWithWhenEnv(?string $env, bool $expected)
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures'), $env);
|
||||
$loader->registerClasses(
|
||||
(new Definition())->setAutoconfigured(true),
|
||||
'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\',
|
||||
'Prototype/{Foo.php}'
|
||||
);
|
||||
|
||||
$this->assertSame($expected, $container->has(Foo::class));
|
||||
}
|
||||
}
|
||||
|
||||
class TestFileLoader extends FileLoader
|
||||
|
Reference in New Issue
Block a user