ValidateEnvPlaceholdersPass.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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\ConfigurationInterface;
  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 ? get_debug_type($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 || $extension instanceof ConfigurationInterface)
  62. || !$config = array_filter($container->getExtensionConfig($name))
  63. ) {
  64. // this extension has no semantic configuration or was not called
  65. continue;
  66. }
  67. $config = $resolvingBag->resolveValue($config);
  68. if ($extension instanceof ConfigurationInterface) {
  69. $configuration = $extension;
  70. } elseif (null === $configuration = $extension->getConfiguration($config, $container)) {
  71. continue;
  72. }
  73. $this->extensionConfig[$name] = $processor->processConfiguration($configuration, $config);
  74. }
  75. } finally {
  76. BaseNode::resetPlaceholders();
  77. }
  78. $resolvingBag->clearUnusedEnvPlaceholders();
  79. }
  80. /**
  81. * @internal
  82. */
  83. public function getExtensionConfig(): array
  84. {
  85. try {
  86. return $this->extensionConfig;
  87. } finally {
  88. $this->extensionConfig = [];
  89. }
  90. }
  91. }