This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
symfony/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php

455 lines
16 KiB
PHP
Raw Normal View History

2018-03-03 10:07:55 +00:00
<?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\Tests\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Exception\TreeWithoutRootNodeException;
2018-03-03 10:07:55 +00:00
use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass;
use Symfony\Component\DependencyInjection\Compiler\RegisterEnvVarProcessorsPass;
use Symfony\Component\DependencyInjection\Compiler\ValidateEnvPlaceholdersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
class ValidateEnvPlaceholdersPassTest extends TestCase
{
public function testEnvsAreValidatedInConfig()
2018-03-03 10:07:55 +00:00
{
$container = new ContainerBuilder();
$container->setParameter('env(NULLED)', null);
2018-07-02 19:21:13 +01:00
$container->setParameter('env(FLOATISH)', '3.2');
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', $expected = [
'scalar_node' => '%env(NULLED)%',
'scalar_node_not_empty' => '%env(FLOATISH)%',
'int_node' => '%env(int:FOO)%',
'float_node' => '%env(float:BAR)%',
2018-07-02 19:21:13 +01:00
'string_node' => '%env(UNDEFINED)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
2018-03-03 10:07:55 +00:00
}
2018-07-02 19:21:13 +01:00
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
* @expectedExceptionMessage Invalid configuration for path "env_extension.string_node": "fail" is not a valid string
*/
public function testDefaultEnvIsValidatedInConfig()
{
$container = new ContainerBuilder();
$container->setParameter('env(STRING)', 'fail');
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', $expected = [
'string_node' => '%env(STRING)%',
]);
$this->doProcess($container);
}
/**
* @group legacy
* @expectedDeprecation A non-string default value of an env() parameter is deprecated since 4.3, cast "env(FLOATISH)" to string instead.
*/
public function testDefaultEnvWithoutPrefixIsValidatedInConfig()
2018-03-03 10:07:55 +00:00
{
$container = new ContainerBuilder();
$container->setParameter('env(FLOATISH)', 3.2);
2018-03-03 10:07:55 +00:00
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', $expected = [
'float_node' => '%env(FLOATISH)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
* @expectedExceptionMessage Invalid type for path "env_extension.bool_node". Expected "bool", but got one of "bool", "int", "float", "string", "array".
*/
public function testEnvsAreValidatedInConfigWithInvalidPlaceholder()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', $expected = [
2018-03-03 10:07:55 +00:00
'bool_node' => '%env(const:BAZ)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
* @expectedExceptionMessage Invalid type for path "env_extension.int_node". Expected "int", but got "array".
*/
public function testInvalidEnvInConfig()
{
$container = new ContainerBuilder();
$container->registerExtension(new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', [
2018-03-03 10:07:55 +00:00
'int_node' => '%env(json:FOO)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidTypeException
* @expectedExceptionMessage Invalid type for path "env_extension.int_node". Expected int, but got NULL.
*/
public function testNulledEnvInConfig()
{
$container = new ContainerBuilder();
$container->setParameter('env(NULLED)', null);
$container->registerExtension(new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', [
2018-03-03 10:07:55 +00:00
'int_node' => '%env(NULLED)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
}
public function testValidateEnvOnMerge()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', [
2018-03-03 10:07:55 +00:00
'int_node' => '%env(int:const:FOO)%',
'bool_node' => true,
2019-01-16 18:24:45 +00:00
]);
$container->prependExtensionConfig('env_extension', [
2018-03-03 10:07:55 +00:00
'int_node' => '%env(int:BAR)%',
'bool_node' => '%env(bool:int:BAZ)%',
'scalar_node' => '%env(BAZ)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
2019-01-16 18:24:45 +00:00
$expected = [
2018-03-03 10:07:55 +00:00
'int_node' => '%env(int:const:FOO)%',
'bool_node' => true,
'scalar_node' => '%env(BAZ)%',
2019-01-16 18:24:45 +00:00
];
2018-03-03 10:07:55 +00:00
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testConcatenatedEnvInConfig()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', [
2018-03-03 10:07:55 +00:00
'scalar_node' => $expected = 'foo %env(BAR)% baz',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
2019-01-16 18:24:45 +00:00
$this->assertSame(['scalar_node' => $expected], $container->resolveEnvPlaceholders($ext->getConfig()));
2018-03-03 10:07:55 +00:00
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
* @expectedExceptionMessage A dynamic value is not compatible with a "Symfony\Component\Config\Definition\EnumNode" node type at path "env_extension.enum_node".
*/
public function testEnvIsIncompatibleWithEnumNode()
{
$container = new ContainerBuilder();
$container->registerExtension(new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', [
2018-03-03 10:07:55 +00:00
'enum_node' => '%env(FOO)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
}
/**
* @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
* @expectedExceptionMessage A dynamic value is not compatible with a "Symfony\Component\Config\Definition\ArrayNode" node type at path "env_extension.simple_array_node".
*/
public function testEnvIsIncompatibleWithArrayNode()
{
$container = new ContainerBuilder();
$container->registerExtension(new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', [
2018-03-03 10:07:55 +00:00
'simple_array_node' => '%env(json:FOO)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
}
public function testNormalizedEnvIsCompatibleWithArrayNode()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', [
2018-03-03 10:07:55 +00:00
'array_node' => $expected = '%env(CHILD)%',
2019-01-16 18:24:45 +00:00
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
2019-01-16 18:24:45 +00:00
$this->assertSame(['array_node' => ['child_node' => $expected]], $container->resolveEnvPlaceholders($ext->getConfig()));
2018-03-03 10:07:55 +00:00
}
public function testEnvIsNotUnset()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', $expected = [
'array_node' => ['int_unset_at_zero' => '%env(int:CHILD)%'],
]);
2018-03-03 10:07:55 +00:00
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
2018-04-06 06:34:50 +01:00
public function testEmptyEnvWhichCannotBeEmptyForScalarNode(): void
2018-04-04 17:31:13 +01:00
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', $expected = [
2018-04-04 17:31:13 +01:00
'scalar_node_not_empty' => '%env(SOME)%',
2019-01-16 18:24:45 +00:00
]);
2018-04-04 17:31:13 +01:00
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
/**
* NOT LEGACY (test exception in 5.0).
*
* @group legacy
2018-12-01 09:28:10 +00:00
* @expectedDeprecation Setting path "env_extension.scalar_node_not_empty_validated" to an environment variable is deprecated since Symfony 4.3. Remove "cannotBeEmpty()", "validate()" or include a prefix/suffix value instead.
*/
public function testEmptyEnvWhichCannotBeEmptyForScalarNodeWithValidation(): void
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 21:53:45 +00:00
$container->prependExtensionConfig('env_extension', $expected = [
'scalar_node_not_empty_validated' => '%env(SOME)%',
2019-01-16 21:53:45 +00:00
]);
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testPartialEnvWhichCannotBeEmptyForScalarNode(): void
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 21:53:45 +00:00
$container->prependExtensionConfig('env_extension', $expected = [
'scalar_node_not_empty_validated' => 'foo %env(SOME)% bar',
2019-01-16 21:53:45 +00:00
]);
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testEnvWithVariableNode(): void
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', $expected = [
'variable_node' => '%env(SOME)%',
2019-01-16 18:24:45 +00:00
]);
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
/**
* @group legacy
*/
public function testConfigurationWithoutRootNode(): void
{
$container = new ContainerBuilder();
$container->registerExtension(new EnvExtension(new EnvConfigurationWithoutRootNode()));
$container->loadFromExtension('env_extension');
$this->doProcess($container);
$this->addToAssertionCount(1);
}
public function testEmptyConfigFromMoreThanOneSource()
{
$container = new ContainerBuilder();
$container->registerExtension(new EnvExtension(new ConfigurationWithArrayNodeRequiringOneElement()));
2019-01-16 18:24:45 +00:00
$container->loadFromExtension('env_extension', []);
$container->loadFromExtension('env_extension', []);
$this->doProcess($container);
$this->addToAssertionCount(1);
}
public function testDiscardedEnvInConfig(): void
{
$container = new ContainerBuilder();
$container->setParameter('env(BOOLISH)', '1');
$container->setParameter('boolish', '%env(BOOLISH)%');
$container->registerExtension(new EnvExtension());
2019-01-16 18:24:45 +00:00
$container->prependExtensionConfig('env_extension', [
'array_node' => ['bool_force_cast' => '%boolish%'],
]);
$container->compile(true);
$this->assertSame('1', $container->getParameter('boolish'));
}
2018-03-03 10:07:55 +00:00
private function doProcess(ContainerBuilder $container): void
{
(new MergeExtensionConfigurationPass())->process($container);
(new RegisterEnvVarProcessorsPass())->process($container);
(new ValidateEnvPlaceholdersPass())->process($container);
}
}
class EnvConfiguration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('env_extension');
$treeBuilder->getRootNode()
2018-03-03 10:07:55 +00:00
->children()
->scalarNode('scalar_node')->end()
2018-04-04 17:31:13 +01:00
->scalarNode('scalar_node_not_empty')->cannotBeEmpty()->end()
->scalarNode('scalar_node_not_empty_validated')
->cannotBeEmpty()
->validate()
->always(function ($value) {
return $value;
})
->end()
->end()
2018-03-03 10:07:55 +00:00
->integerNode('int_node')->end()
->floatNode('float_node')->end()
->booleanNode('bool_node')->end()
->arrayNode('array_node')
->beforeNormalization()
->ifTrue(function ($value) { return !\is_array($value); })
2019-01-16 18:24:45 +00:00
->then(function ($value) { return ['child_node' => $value]; })
2018-03-03 10:07:55 +00:00
->end()
->beforeNormalization()
->ifArray()
->then(function (array $v) {
if (isset($v['bool_force_cast'])) {
$v['bool_force_cast'] = (bool) $v['bool_force_cast'];
}
return $v;
})
->end()
2018-03-03 10:07:55 +00:00
->children()
->scalarNode('child_node')->end()
->booleanNode('bool_force_cast')->end()
2018-03-03 10:07:55 +00:00
->integerNode('int_unset_at_zero')
->validate()
->ifTrue(function ($value) { return 0 === $value; })
->thenUnset()
->end()
->end()
->end()
->end()
->arrayNode('simple_array_node')->end()
2019-01-16 18:24:45 +00:00
->enumNode('enum_node')->values(['a', 'b'])->end()
->variableNode('variable_node')->end()
->scalarNode('string_node')
->validate()
->ifTrue(function ($value) {
2018-07-02 19:21:13 +01:00
return !\is_string($value) || 'fail' === $value;
})
2018-07-02 19:21:13 +01:00
->thenInvalid('%s is not a valid string')
->end()
->end()
2018-03-03 10:07:55 +00:00
->end();
return $treeBuilder;
}
}
class EnvConfigurationWithoutRootNode implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
return new TreeBuilder();
}
}
class ConfigurationWithArrayNodeRequiringOneElement implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$treeBuilder->root('env_extension')
->children()
->arrayNode('nodes')
->isRequired()
->requiresAtLeastOneElement()
->scalarPrototype()->end()
->end()
->end();
return $treeBuilder;
}
}
2018-03-03 10:07:55 +00:00
class EnvExtension extends Extension
{
private $configuration;
2018-03-03 10:07:55 +00:00
private $config;
public function __construct(ConfigurationInterface $configuration = null)
{
$this->configuration = $configuration ?? new EnvConfiguration();
}
2018-03-03 10:07:55 +00:00
public function getAlias()
{
return 'env_extension';
}
public function getConfiguration(array $config, ContainerBuilder $container)
{
return $this->configuration;
2018-03-03 10:07:55 +00:00
}
public function load(array $configs, ContainerBuilder $container)
{
if (!array_filter($configs)) {
return;
}
try {
$this->config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs);
} catch (TreeWithoutRootNodeException $e) {
$this->config = null;
}
2018-03-03 10:07:55 +00:00
}
public function getConfig()
{
return $this->config;
}
}