[DependencyInjection] inject $env in the scope of PHP-DSL files

This commit is contained in:
Nicolas Grekas 2021-05-12 08:03:11 +02:00
parent 31bd00e6d7
commit 29173a91d1
7 changed files with 46 additions and 8 deletions

View File

@ -16,7 +16,7 @@ namespace Symfony\Component\DependencyInjection\Attribute;
*
* @author Nicolas Grekas <p@tchwork.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
class When
{
public function __construct(

View File

@ -15,6 +15,7 @@ use Symfony\Component\Config\Builder\ConfigBuilderGenerator;
use Symfony\Component\Config\Builder\ConfigBuilderGeneratorInterface;
use Symfony\Component\Config\Builder\ConfigBuilderInterface;
use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\DependencyInjection\Attribute\When;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
@ -55,12 +56,12 @@ class PhpFileLoader extends FileLoader
$this->container->fileExists($path);
// the closure forbids access to the private scope in the included file
$load = \Closure::bind(function ($path) use ($container, $loader, $resource, $type) {
$load = \Closure::bind(function ($path, $env) use ($container, $loader, $resource, $type) {
return include $path;
}, $this, ProtectedPhpFileLoader::class);
try {
$callback = $load($path);
$callback = $load($path, $this->env);
if (\is_object($callback) && \is_callable($callback)) {
$this->executeCallback($callback, new ContainerConfigurator($this->container, $this, $this->instanceof, $path, $resource, $this->env), $path);
@ -98,8 +99,22 @@ class PhpFileLoader extends FileLoader
$arguments = [];
$configBuilders = [];
$parameters = (new \ReflectionFunction($callback))->getParameters();
foreach ($parameters as $parameter) {
$r = new \ReflectionFunction($callback);
if (\PHP_VERSION_ID >= 80000) {
$attribute = null;
foreach ($r->getAttributes(When::class) as $attribute) {
if ($this->env === $attribute->newInstance()->env) {
$attribute = null;
break;
}
}
if (null !== $attribute) {
return;
}
}
foreach ($r->getParameters() as $parameter) {
$reflectionType = $parameter->getType();
if (!$reflectionType instanceof \ReflectionNamedType) {
throw new \InvalidArgumentException(sprintf('Could not resolve argument "$%s" for "%s". You must typehint it (for example with "%s" or "%s").', $parameter->getName(), $path, ContainerConfigurator::class, ContainerBuilder::class));

View File

@ -2,6 +2,10 @@
use Symfony\Component\DependencyInjection\Tests\Fixtures\AcmeConfig;
return static function (AcmeConfig $config) {
if ('prod' !== $env) {
return;
}
return function (AcmeConfig $config) {
$config->color('blue');
};

View File

@ -2,7 +2,7 @@
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
return static function (ContainerConfigurator $configurator): void {
return function (ContainerConfigurator $configurator): void {
$services = $configurator->services();
$services

View File

@ -2,6 +2,6 @@
use Symfony\Config\AcmeConfig\NestedConfig;
return static function (NestedConfig $config) {
return function (NestedConfig $config) {
throw new RuntimeException('This code should not be run.');
};

View File

@ -0,0 +1,7 @@
<?php
use Symfony\Component\DependencyInjection\Attribute\When;
return #[When(env: 'prod')] function () {
throw new RuntimeException('This code should not be run.');
};

View File

@ -176,4 +176,16 @@ class PhpFileLoaderTest extends TestCase
$loader->load($fixtures.'/config/nested_bundle_config.php');
}
/**
* @requires PHP 8
*/
public function testWhenEnv()
{
$fixtures = realpath(__DIR__.'/../Fixtures');
$container = new ContainerBuilder();
$loader = new PhpFileLoader($container, new FileLocator(), 'dev', new ConfigBuilderGenerator(sys_get_temp_dir()));
$loader->load($fixtures.'/config/when_env.php');
}
}