ValidateEnvPlaceholdersPass.php 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\DependencyInjection\Compiler;
  11. use Symfony\Component\Config\Definition\BaseNode;
  12. use Symfony\Component\Config\Definition\Exception\TreeWithoutRootNodeException;
  13. use Symfony\Component\Config\Definition\Processor;
  14. use Symfony\Component\DependencyInjection\ContainerBuilder;
  15. use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
  16. use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
  17. use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
  18. /**
  19. * Validates environment variable placeholders used in extension configuration with dummy values.
  20. *
  21. * @author Roland Franssen <franssen.roland@gmail.com>
  22. */
  23. class ValidateEnvPlaceholdersPass implements CompilerPassInterface
  24. {
  25. private const TYPE_FIXTURES = ['array' => [], 'bool' => false, 'float' => 0.0, 'int' => 0, 'string' => ''];
  26. private $extensionConfig = [];
  27. /**
  28. * {@inheritdoc}
  29. */
  30. public function process(ContainerBuilder $container)
  31. {
  32. $this->extensionConfig = [];
  33. if (!class_exists(BaseNode::class) || !$extensions = $container->getExtensions()) {
  34. return;
  35. }
  36. $resolvingBag = $container->getParameterBag();
  37. if (!$resolvingBag instanceof EnvPlaceholderParameterBag) {
  38. return;
  39. }
  40. $defaultBag = new ParameterBag($resolvingBag->all());
  41. $envTypes = $resolvingBag->getProvidedTypes();
  42. try {
  43. foreach ($resolvingBag->getEnvPlaceholders() + $resolvingBag->getUnusedEnvPlaceholders() as $env => $placeholders) {
  44. $values = [];
  45. if (false === $i = strpos($env, ':')) {
  46. $default = $defaultBag->has("env($env)") ? $defaultBag->get("env($env)") : self::TYPE_FIXTURES['string'];
  47. $defaultType = null !== $default ? self::getType($default) : 'string';
  48. $values[$defaultType] = $default;
  49. } else {
  50. $prefix = substr($env, 0, $i);
  51. foreach ($envTypes[$prefix] ?? ['string'] as $type) {
  52. $values[$type] = self::TYPE_FIXTURES[$type] ?? null;
  53. }
  54. }
  55. foreach ($placeholders as $placeholder) {
  56. BaseNode::setPlaceholder($placeholder, $values);
  57. }
  58. }
  59. $processor = new Processor();
  60. foreach ($extensions as $name => $extension) {
  61. if (!$extension instanceof ConfigurationExtensionInterface || !$config = array_filter($container->getExtensionConfig($name))) {
  62. // this extension has no semantic configuration or was not called
  63. continue;
  64. }
  65. $config = $resolvingBag->resolveValue($config);
  66. if (null === $configuration = $extension->getConfiguration($config, $container)) {
  67. continue;
  68. }
  69. try {
  70. $this->extensionConfig[$name] = $processor->processConfiguration($configuration, $config);
  71. } catch (TreeWithoutRootNodeException $e) {
  72. }
  73. }
  74. } finally {
  75. BaseNode::resetPlaceholders();
  76. }
  77. $resolvingBag->clearUnusedEnvPlaceholders();
  78. }
  79. /**
  80. * @internal
  81. */
  82. public function getExtensionConfig(): array
  83. {
  84. try {
  85. return $this->extensionConfig;
  86. } finally {
  87. $this->extensionConfig = [];
  88. }
  89. }
  90. private static function getType($value): string
  91. {
  92. switch ($type = \gettype($value)) {
  93. case 'boolean':
  94. return 'bool';
  95. case 'double':
  96. return 'float';
  97. case 'integer':
  98. return 'int';
  99. }
  100. return $type;
  101. }
  102. }