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
Fabien Potencier 51a359c079 Merge branch '4.2' into short-array-master
* 4.2:
  fixed CS
  fixed CS
  fixed tests
  fixed CS
  fixed CS
  fixed CS
  fixed short array CS in comments
  fixed CS in ExpressionLanguage fixtures
  fixed CS in generated files
  fixed CS on generated container files
  fixed CS on Form PHP templates
  fixed CS on YAML fixtures
  fixed fixtures
  switched array() to []
2019-01-16 22:53:39 +01:00

435 lines
15 KiB
PHP

<?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;
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()
{
$container = new ContainerBuilder();
$container->setParameter('env(NULLED)', null);
$container->setParameter('env(FLOATISH)', 3.2);
$container->registerExtension($ext = new EnvExtension());
$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)%',
]);
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testDefaultEnvWithoutPrefixIsValidatedInConfig()
{
$container = new ContainerBuilder();
$container->setParameter('env(FLOATISH)', 3.2);
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', $expected = [
'float_node' => '%env(FLOATISH)%',
'string_node' => '%env(UNDEFINED)%',
]);
$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());
$container->prependExtensionConfig('env_extension', $expected = [
'bool_node' => '%env(const:BAZ)%',
]);
$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());
$container->prependExtensionConfig('env_extension', [
'int_node' => '%env(json:FOO)%',
]);
$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());
$container->prependExtensionConfig('env_extension', [
'int_node' => '%env(NULLED)%',
]);
$this->doProcess($container);
}
public function testValidateEnvOnMerge()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', [
'int_node' => '%env(int:const:FOO)%',
'bool_node' => true,
]);
$container->prependExtensionConfig('env_extension', [
'int_node' => '%env(int:BAR)%',
'bool_node' => '%env(bool:int:BAZ)%',
'scalar_node' => '%env(BAZ)%',
]);
$this->doProcess($container);
$expected = [
'int_node' => '%env(int:const:FOO)%',
'bool_node' => true,
'scalar_node' => '%env(BAZ)%',
];
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testConcatenatedEnvInConfig()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', [
'scalar_node' => $expected = 'foo %env(BAR)% baz',
]);
$this->doProcess($container);
$this->assertSame(['scalar_node' => $expected], $container->resolveEnvPlaceholders($ext->getConfig()));
}
/**
* @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());
$container->prependExtensionConfig('env_extension', [
'enum_node' => '%env(FOO)%',
]);
$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());
$container->prependExtensionConfig('env_extension', [
'simple_array_node' => '%env(json:FOO)%',
]);
$this->doProcess($container);
}
public function testNormalizedEnvIsCompatibleWithArrayNode()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', [
'array_node' => $expected = '%env(CHILD)%',
]);
$this->doProcess($container);
$this->assertSame(['array_node' => ['child_node' => $expected]], $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testEnvIsNotUnset()
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', $expected = [
'array_node' => ['int_unset_at_zero' => '%env(int:CHILD)%'],
]);
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testEmptyEnvWhichCannotBeEmptyForScalarNode(): void
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', $expected = [
'scalar_node_not_empty' => '%env(SOME)%',
]);
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
/**
* NOT LEGACY (test exception in 5.0).
*
* @group legacy
* @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());
$container->prependExtensionConfig('env_extension', $expected = array(
'scalar_node_not_empty_validated' => '%env(SOME)%',
));
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testPartialEnvWhichCannotBeEmptyForScalarNode(): void
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', $expected = array(
'scalar_node_not_empty_validated' => 'foo %env(SOME)% bar',
));
$this->doProcess($container);
$this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig()));
}
public function testEnvWithVariableNode(): void
{
$container = new ContainerBuilder();
$container->registerExtension($ext = new EnvExtension());
$container->prependExtensionConfig('env_extension', $expected = [
'variable_node' => '%env(SOME)%',
]);
$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()));
$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());
$container->prependExtensionConfig('env_extension', [
'array_node' => ['bool_force_cast' => '%boolish%'],
]);
$container->compile(true);
$this->assertSame('1', $container->getParameter('boolish'));
}
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()
->children()
->scalarNode('scalar_node')->end()
->scalarNode('scalar_node_not_empty')->cannotBeEmpty()->end()
->scalarNode('scalar_node_not_empty_validated')
->cannotBeEmpty()
->validate()
->always(function ($value) {
return $value;
})
->end()
->end()
->integerNode('int_node')->end()
->floatNode('float_node')->end()
->booleanNode('bool_node')->end()
->arrayNode('array_node')
->beforeNormalization()
->ifTrue(function ($value) { return !\is_array($value); })
->then(function ($value) { return ['child_node' => $value]; })
->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()
->children()
->scalarNode('child_node')->end()
->booleanNode('bool_force_cast')->end()
->integerNode('int_unset_at_zero')
->validate()
->ifTrue(function ($value) { return 0 === $value; })
->thenUnset()
->end()
->end()
->end()
->end()
->arrayNode('simple_array_node')->end()
->enumNode('enum_node')->values(['a', 'b'])->end()
->variableNode('variable_node')->end()
->scalarNode('string_node')
->validate()
->ifTrue(function ($value) {
return !\is_string($value);
})
->thenInvalid('%s is not a string')
->end()
->end()
->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;
}
}
class EnvExtension extends Extension
{
private $configuration;
private $config;
public function __construct(ConfigurationInterface $configuration = null)
{
$this->configuration = $configuration ?? new EnvConfiguration();
}
public function getAlias()
{
return 'env_extension';
}
public function getConfiguration(array $config, ContainerBuilder $container)
{
return $this->configuration;
}
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;
}
}
public function getConfig()
{
return $this->config;
}
}