annotate vendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\DependencyInjection\Compiler;
Chris@0 13
Chris@0 14 use Symfony\Component\DependencyInjection\ContainerBuilder;
Chris@14 15 use Symfony\Component\DependencyInjection\Exception\LogicException;
Chris@14 16 use Symfony\Component\DependencyInjection\Exception\RuntimeException;
Chris@0 17 use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
Chris@14 18 use Symfony\Component\DependencyInjection\Extension\Extension;
Chris@14 19 use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
Chris@0 20 use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
Chris@14 21 use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
Chris@14 22 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
Chris@0 23
Chris@0 24 /**
Chris@0 25 * Merges extension configs into the container builder.
Chris@0 26 *
Chris@0 27 * @author Fabien Potencier <fabien@symfony.com>
Chris@0 28 */
Chris@0 29 class MergeExtensionConfigurationPass implements CompilerPassInterface
Chris@0 30 {
Chris@0 31 /**
Chris@0 32 * {@inheritdoc}
Chris@0 33 */
Chris@0 34 public function process(ContainerBuilder $container)
Chris@0 35 {
Chris@0 36 $parameters = $container->getParameterBag()->all();
Chris@0 37 $definitions = $container->getDefinitions();
Chris@0 38 $aliases = $container->getAliases();
Chris@0 39 $exprLangProviders = $container->getExpressionLanguageProviders();
Chris@0 40
Chris@0 41 foreach ($container->getExtensions() as $extension) {
Chris@0 42 if ($extension instanceof PrependExtensionInterface) {
Chris@0 43 $extension->prepend($container);
Chris@0 44 }
Chris@0 45 }
Chris@0 46
Chris@0 47 foreach ($container->getExtensions() as $name => $extension) {
Chris@0 48 if (!$config = $container->getExtensionConfig($name)) {
Chris@0 49 // this extension was not called
Chris@0 50 continue;
Chris@0 51 }
Chris@14 52 $resolvingBag = $container->getParameterBag();
Chris@14 53 if ($resolvingBag instanceof EnvPlaceholderParameterBag && $extension instanceof Extension) {
Chris@14 54 // create a dedicated bag so that we can track env vars per-extension
Chris@14 55 $resolvingBag = new MergeExtensionConfigurationParameterBag($resolvingBag);
Chris@14 56 }
Chris@14 57 $config = $resolvingBag->resolveValue($config);
Chris@0 58
Chris@14 59 try {
Chris@14 60 $tmpContainer = new MergeExtensionConfigurationContainerBuilder($extension, $resolvingBag);
Chris@14 61 $tmpContainer->setResourceTracking($container->isTrackingResources());
Chris@14 62 $tmpContainer->addObjectResource($extension);
Chris@14 63 if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
Chris@14 64 $tmpContainer->addObjectResource($configuration);
Chris@14 65 }
Chris@14 66
Chris@14 67 foreach ($exprLangProviders as $provider) {
Chris@14 68 $tmpContainer->addExpressionLanguageProvider($provider);
Chris@14 69 }
Chris@14 70
Chris@14 71 $extension->load($config, $tmpContainer);
Chris@14 72 } catch (\Exception $e) {
Chris@14 73 if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) {
Chris@14 74 $container->getParameterBag()->mergeEnvPlaceholders($resolvingBag);
Chris@14 75 }
Chris@14 76
Chris@14 77 throw $e;
Chris@0 78 }
Chris@0 79
Chris@14 80 if ($resolvingBag instanceof MergeExtensionConfigurationParameterBag) {
Chris@14 81 // don't keep track of env vars that are *overridden* when configs are merged
Chris@14 82 $resolvingBag->freezeAfterProcessing($extension, $tmpContainer);
Chris@0 83 }
Chris@0 84
Chris@0 85 $container->merge($tmpContainer);
Chris@0 86 $container->getParameterBag()->add($parameters);
Chris@0 87 }
Chris@0 88
Chris@0 89 $container->addDefinitions($definitions);
Chris@0 90 $container->addAliases($aliases);
Chris@0 91 }
Chris@0 92 }
Chris@14 93
Chris@14 94 /**
Chris@14 95 * @internal
Chris@14 96 */
Chris@14 97 class MergeExtensionConfigurationParameterBag extends EnvPlaceholderParameterBag
Chris@14 98 {
Chris@14 99 private $processedEnvPlaceholders;
Chris@14 100
Chris@14 101 public function __construct(parent $parameterBag)
Chris@14 102 {
Chris@14 103 parent::__construct($parameterBag->all());
Chris@14 104 $this->mergeEnvPlaceholders($parameterBag);
Chris@14 105 }
Chris@14 106
Chris@14 107 public function freezeAfterProcessing(Extension $extension, ContainerBuilder $container)
Chris@14 108 {
Chris@14 109 if (!$config = $extension->getProcessedConfigs()) {
Chris@14 110 // Extension::processConfiguration() wasn't called, we cannot know how configs were merged
Chris@14 111 return;
Chris@14 112 }
Chris@17 113 $this->processedEnvPlaceholders = [];
Chris@14 114
Chris@14 115 // serialize config and container to catch env vars nested in object graphs
Chris@14 116 $config = serialize($config).serialize($container->getDefinitions()).serialize($container->getAliases()).serialize($container->getParameterBag()->all());
Chris@14 117
Chris@14 118 foreach (parent::getEnvPlaceholders() as $env => $placeholders) {
Chris@14 119 foreach ($placeholders as $placeholder) {
Chris@14 120 if (false !== stripos($config, $placeholder)) {
Chris@14 121 $this->processedEnvPlaceholders[$env] = $placeholders;
Chris@14 122 break;
Chris@14 123 }
Chris@14 124 }
Chris@14 125 }
Chris@14 126 }
Chris@14 127
Chris@14 128 /**
Chris@14 129 * {@inheritdoc}
Chris@14 130 */
Chris@14 131 public function getEnvPlaceholders()
Chris@14 132 {
Chris@14 133 return null !== $this->processedEnvPlaceholders ? $this->processedEnvPlaceholders : parent::getEnvPlaceholders();
Chris@14 134 }
Chris@14 135 }
Chris@14 136
Chris@14 137 /**
Chris@14 138 * A container builder preventing using methods that wouldn't have any effect from extensions.
Chris@14 139 *
Chris@14 140 * @internal
Chris@14 141 */
Chris@14 142 class MergeExtensionConfigurationContainerBuilder extends ContainerBuilder
Chris@14 143 {
Chris@14 144 private $extensionClass;
Chris@14 145
Chris@14 146 public function __construct(ExtensionInterface $extension, ParameterBagInterface $parameterBag = null)
Chris@14 147 {
Chris@14 148 parent::__construct($parameterBag);
Chris@14 149
Chris@17 150 $this->extensionClass = \get_class($extension);
Chris@14 151 }
Chris@14 152
Chris@14 153 /**
Chris@14 154 * {@inheritdoc}
Chris@14 155 */
Chris@14 156 public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/)
Chris@14 157 {
Chris@17 158 throw new LogicException(sprintf('You cannot add compiler pass "%s" from extension "%s". Compiler passes must be registered before the container is compiled.', \get_class($pass), $this->extensionClass));
Chris@14 159 }
Chris@14 160
Chris@14 161 /**
Chris@14 162 * {@inheritdoc}
Chris@14 163 */
Chris@14 164 public function registerExtension(ExtensionInterface $extension)
Chris@14 165 {
Chris@17 166 throw new LogicException(sprintf('You cannot register extension "%s" from "%s". Extensions must be registered before the container is compiled.', \get_class($extension), $this->extensionClass));
Chris@14 167 }
Chris@14 168
Chris@14 169 /**
Chris@14 170 * {@inheritdoc}
Chris@14 171 */
Chris@14 172 public function compile($resolveEnvPlaceholders = false)
Chris@14 173 {
Chris@14 174 throw new LogicException(sprintf('Cannot compile the container in extension "%s".', $this->extensionClass));
Chris@14 175 }
Chris@14 176
Chris@14 177 /**
Chris@14 178 * {@inheritdoc}
Chris@14 179 */
Chris@14 180 public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs = null)
Chris@14 181 {
Chris@14 182 if (true !== $format || !\is_string($value)) {
Chris@14 183 return parent::resolveEnvPlaceholders($value, $format, $usedEnvs);
Chris@14 184 }
Chris@14 185
Chris@14 186 $bag = $this->getParameterBag();
Chris@14 187 $value = $bag->resolveValue($value);
Chris@14 188
Chris@14 189 foreach ($bag->getEnvPlaceholders() as $env => $placeholders) {
Chris@14 190 if (false === strpos($env, ':')) {
Chris@14 191 continue;
Chris@14 192 }
Chris@14 193 foreach ($placeholders as $placeholder) {
Chris@14 194 if (false !== stripos($value, $placeholder)) {
Chris@14 195 throw new RuntimeException(sprintf('Using a cast in "env(%s)" is incompatible with resolution at compile time in "%s". The logic in the extension should be moved to a compiler pass, or an env parameter with no cast should be used instead.', $env, $this->extensionClass));
Chris@14 196 }
Chris@14 197 }
Chris@14 198 }
Chris@14 199
Chris@14 200 return parent::resolveEnvPlaceholders($value, $format, $usedEnvs);
Chris@14 201 }
Chris@14 202 }