diff --git a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php index f9e6024164c15..1ea77ad86c95e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php @@ -44,7 +44,7 @@ public function process(ContainerBuilder $container) } $config = $container->getParameterBag()->resolveValue($config); - $tmpContainer = new ContainerBuilder($container->getParameterBag()); + $tmpContainer = new ContainerBuilder($container->getParameterBag(), $container->getContext()); $tmpContainer->setResourceTracking($container->isTrackingResources()); $tmpContainer->addObjectResource($extension); diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index cb3789165891a..7199784588dc5 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -25,6 +25,7 @@ use Symfony\Component\Config\Resource\ResourceInterface; use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface; use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; @@ -33,7 +34,7 @@ * * @author Fabien Potencier */ -class ContainerBuilder extends Container implements TaggedContainerInterface +class ContainerBuilder extends Container implements TaggedContainerInterface, ContextualizedContainerBuilderInterface { /** * @var ExtensionInterface[] @@ -89,8 +90,21 @@ class ContainerBuilder extends Container implements TaggedContainerInterface */ private $usedTags = array(); + private $context; + private $compiled = false; + /** + * @param ParameterBagInterface|null $parameterBag A ParameterBagInterface instance + * @param Context|null $context A Context instance, or null + */ + public function __construct(ParameterBagInterface $parameterBag = null, Context $context = null) + { + parent::__construct($parameterBag); + + $this->context = $context ?: Context::create(); + } + /** * Sets the track resources flag. * @@ -1017,6 +1031,14 @@ public static function getServiceConditionals($value) return $services; } + /** + * {@inheritdoc} + */ + public function getContext() + { + return $this->context; + } + /** * Retrieves the currently set proxy instantiator or instantiates one. * diff --git a/src/Symfony/Component/DependencyInjection/Context.php b/src/Symfony/Component/DependencyInjection/Context.php new file mode 100644 index 0000000000000..9fad7793af441 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Context.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection; + +use Symfony\Component\DependencyInjection\Exception\ContextElementNotFoundException; + +/** + * @author Maxime Steinhausser + */ +final class Context +{ + private $elements; + + private function __construct(array $elements = array()) + { + $this->elements = $elements; + } + + /** + * Creates a new context allowing to share elements during the container building phase. + * + * Context elements is an array where the values are the elements to share + * and the keys are strings allowing to retrieve an element. + * + * For instance: + * + * Context::create(array('kernel' => new BootingKernel($kernel))); + * + * You can optionally pass an existing Context instance. Thus, original elements are reused, + * but new context elements replace any existing key. + * + * @param array $elements An array of elements indexed by a string. + * @param Context|null $previous An optional Context instance used as base. + * + * @return Context + */ + public static function create(array $elements = array(), Context $previous = null) + { + return new self($previous ? array_replace($previous->elements, $elements) : $elements); + } + + /** + * @param string $key + * + * @return bool + */ + public function has($key) + { + return isset($this->elements[$key]); + } + + /** + * @param string $key + * + * @return mixed + * + * @throws ContextElementNotFoundException When no element exists for this key. + */ + public function get($key) + { + if (!$this->has($key)) { + throw new ContextElementNotFoundException($key); + } + + return $this->elements[$key]; + } +} diff --git a/src/Symfony/Component/DependencyInjection/ContextualizedContainerBuilderInterface.php b/src/Symfony/Component/DependencyInjection/ContextualizedContainerBuilderInterface.php new file mode 100644 index 0000000000000..88976ec898aeb --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/ContextualizedContainerBuilderInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection; + +/** + * Implemented by a ContainerBuilder sharing a context during build time. + * + * @author Maxime Steinhausser + */ +interface ContextualizedContainerBuilderInterface extends ContainerInterface +{ + /** + * @return Context + */ + public function getContext(); +} diff --git a/src/Symfony/Component/DependencyInjection/Exception/ContextElementNotFoundException.php b/src/Symfony/Component/DependencyInjection/Exception/ContextElementNotFoundException.php new file mode 100644 index 0000000000000..704a77bafc21a --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Exception/ContextElementNotFoundException.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Exception; + +/** + * This exception is thrown when a non-existent context element is used. + * + * @author Maxime Steinhausser + */ +class ContextElementNotFoundException extends InvalidArgumentException +{ + private $key; + + /** + * @param string $key + */ + public function __construct($key) + { + $this->key = $key; + + parent::__construct(sprintf('Context element not found for "%s" key', $key)); + } + + /** + * @return string + */ + public function getKey() + { + return $this->key; + } +} diff --git a/src/Symfony/Component/HttpKernel/BootingKernel.php b/src/Symfony/Component/HttpKernel/BootingKernel.php new file mode 100644 index 0000000000000..e7d34b1c74740 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/BootingKernel.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Component\DependencyInjection\Exception\BadMethodCallException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Bundle\BootingBundle; +use Symfony\Component\HttpKernel\Bundle\BundleInterface; + +/** + * @author Maxime Steinhausser + */ +class BootingKernel implements KernelInterface +{ + private $innerKernel; + + public function __construct(KernelInterface $innerKernel) + { + $this->innerKernel = $innerKernel; + } + + /** + * {@inheritdoc} + */ + public function serialize() + { + return $this->innerKernel->serialize(); + } + + /** + * {@inheritdoc} + */ + public function unserialize($serialized) + { + $this->innerKernel->unserialize($serialized); + } + + /** + * {@inheritdoc} + */ + public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true) + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function registerBundles() + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function registerContainerConfiguration(LoaderInterface $loader) + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function boot() + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function shutdown() + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function getBundles() + { + return array_map(function (BundleInterface $bundle) { + return new BootingBundle($bundle); + }, $this->innerKernel->getBundles()); + } + + /** + * {@inheritdoc} + */ + public function getBundle($name, $first = true) + { + if (is_array($bundle = $this->innerKernel->getBundle($name, $first))) { + return array_map(function (BundleInterface $bundle) { + return new BootingBundle($bundle); + }, $bundle); + } + + return new BootingBundle($bundle); + } + + /** + * {@inheritdoc} + */ + public function locateResource($name, $dir = null, $first = true) + { + return $this->innerKernel->locateResource($name, $dir, $first); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->innerKernel->getName(); + } + + /** + * {@inheritdoc} + */ + public function getEnvironment() + { + return $this->innerKernel->getEnvironment(); + } + + /** + * {@inheritdoc} + */ + public function isDebug() + { + return $this->innerKernel->isDebug(); + } + + /** + * {@inheritdoc} + */ + public function getRootDir() + { + return $this->innerKernel->getRootDir(); + } + + /** + * {@inheritdoc} + */ + public function getContainer() + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function getStartTime() + { + return $this->innerKernel->getStartTime(); + } + + /** + * {@inheritdoc} + */ + public function getCacheDir() + { + return $this->innerKernel->getCacheDir(); + } + + /** + * {@inheritdoc} + */ + public function getLogDir() + { + return $this->innerKernel->getLogDir(); + } + + /** + * {@inheritdoc} + */ + public function getCharset() + { + return $this->innerKernel->getCharset(); + } +} diff --git a/src/Symfony/Component/HttpKernel/Bundle/BootingBundle.php b/src/Symfony/Component/HttpKernel/Bundle/BootingBundle.php new file mode 100644 index 0000000000000..c46cab5ef9a2b --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Bundle/BootingBundle.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Bundle; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\BadMethodCallException; + +/** + * @author Maxime Steinhausser + */ +class BootingBundle implements BundleInterface +{ + private $innerBundle; + + public function __construct(BundleInterface $innerBundle) + { + $this->innerBundle = $innerBundle; + } + + /** + * {@inheritdoc} + */ + public function boot() + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function shutdown() + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function build(ContainerBuilder $container) + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function getContainerExtension() + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return $this->innerBundle->getParent(); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->innerBundle->getName(); + } + + /** + * {@inheritdoc} + */ + public function getNamespace() + { + return $this->innerBundle->getNamespace(); + } + + /** + * {@inheritdoc} + */ + public function getPath() + { + return $this->innerBundle->getPath(); + } + + /** + * {@inheritdoc} + */ + public function setContainer(ContainerInterface $container = null) + { + throw new BadMethodCallException(sprintf('Calling "%s()" is not allowed.', __METHOD__)); + } +} diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 125da81d5ca4d..18edbb66a6fa3 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -15,6 +15,7 @@ use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Context; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; @@ -611,7 +612,7 @@ protected function prepareContainer(ContainerBuilder $container) */ protected function getContainerBuilder() { - $container = new ContainerBuilder(new ParameterBag($this->getKernelParameters())); + $container = new ContainerBuilder(new ParameterBag($this->getKernelParameters()), Context::create(array('kernel' => new BootingKernel($this)))); if (class_exists('ProxyManager\Configuration') && class_exists('Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator')) { $container->setProxyInstantiator(new RuntimeInstantiator()); diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index e583b43adc167..a417170c7b3fd 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -28,7 +28,7 @@ "symfony/config": "~2.8|~3.0", "symfony/console": "~2.8|~3.0", "symfony/css-selector": "~2.8|~3.0", - "symfony/dependency-injection": "~2.8|~3.0", + "symfony/dependency-injection": "3.2.x-dev", "symfony/dom-crawler": "~2.8|~3.0", "symfony/expression-language": "~2.8|~3.0", "symfony/finder": "~2.8|~3.0",