From bc611fc554091bd4b808b67af6f20de69c1a28d4 Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Fri, 7 Dec 2012 13:15:53 +0100 Subject: [PATCH] added docs for PrependExtensionInterface --- .../dependency_injection/compilation.rst | 23 +++ cookbook/bundles/index.rst | 1 + cookbook/bundles/prepend_extension.rst | 135 ++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 cookbook/bundles/prepend_extension.rst diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index b7c54d19484..c244ff457a1 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -248,6 +248,29 @@ but also load a secondary one only if a certain parameter is set:: .. _components-dependency-injection-compiler-passes: +Prepending configuration passed to the Extension +------------------------------------------------ + +An Extension can prepend the configuration of any Bundle before the ``load()`` +method is called by implementing :class:`Symfony\\Component\\DependencyInjection\\Compiler\\PrependExtensionInterface`:: + + use Symfony\Component\DependencyInjection\Compiler\PrependExtensionInterface; + // ... + + class AcmeDemoExtension implements ExtensionInterface, PrependExtensionInterface + { + // ... + + public function prepend() + { + // ... + + $container->prependExtensionConfig($name, $config); + + // ... + } + } + Creating a Compiler Pass ------------------------ diff --git a/cookbook/bundles/index.rst b/cookbook/bundles/index.rst index c9a4b97ae27..aeeb5ec5fe7 100644 --- a/cookbook/bundles/index.rst +++ b/cookbook/bundles/index.rst @@ -8,3 +8,4 @@ Bundles inheritance override extension + prepend_extension diff --git a/cookbook/bundles/prepend_extension.rst b/cookbook/bundles/prepend_extension.rst new file mode 100644 index 00000000000..eb3f4c5ef18 --- /dev/null +++ b/cookbook/bundles/prepend_extension.rst @@ -0,0 +1,135 @@ +.. index:: + single: Configuration; Semantic + single: Bundle; Extension configuration + +How to simplify configuration of multiple Bundle +================================================ + +Especially when building reusable and extensible applications developers are +often faced with a choice, either create a single Bundle or create multiple +Bundles. Creating a single Bundle has the draw back that its impossible for +users to choose to remove functionality they are not using. Creating multiple +Bundles has the draw back that configuration becomes more tedious and settings +often need to be repeated for various Bundles. + +Using the below approach it is possible to remove the disadvantage of the +multiple Bundle approach, by enabling a single Extension to prepend the settings +for any Bundle. It can use the settings defined in the ``app/config/config.yml`` +to prepend settings just as if they would have been written explicitly by the +user in the application configuration. + +For example, this could be used to configure the entity manager name to use in +multiple Bundle. Or it can be used to enable an optional feature that depends +on another Bundle being loaded as well. + +In order for an Extension to be able to do this it needs to implement +:class:`Symfony\\Component\\DependencyInjection\\Compiler\\PrependExtensionInterface`:: + + // src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php + namespace Acme\HelloBundle\DependencyInjection; + + use Symfony\Component\HttpKernel\DependencyInjection\Extension; + use Symfony\Component\\DependencyInjection\PrependExtensionInterface; + use Symfony\Component\DependencyInjection\ContainerBuilder; + + class AcmeHelloExtension extends Extension implements PrependExtensionInterface + { + // ... + + public function prepend(ContainerBuilder $container) + { + // ... + } + } + +Inside the :method:`Symfony\\Component\\DependencyInjection\\Compiler\\PrependExtensionInterface::prepend()` +method developers have full access to the :class:`Symfony\Component\DependencyInjection\ContainerBuilder` +instance just before the :method:`Symfony\Component\HttpKernel\DependencyInjection\ExtensionInterface:load()` +method is called on the registered Bundle Extensions. In order to prepend settings +to a Bundle extension developers can use the +:method:`Symfony\Component\DependencyInjection\ContainerBuilder:prependExtensionConfig()` +method on the :class:`Symfony\Component\DependencyInjection\ContainerBuilder` +instance. As this method only prepends settings, any other settings done explicitly +inside the ``app/config/config.yml`` would override these prepended settings. + +The following example illustrates how to prepend +a configuration setting in multiple Bundles as well as disable a flag in multiple Bundles +in case specific other Bundle is not registered:: + + public function prepend(ContainerBuilder $container) + { + // get all Bundles + $bundles = $container->getParameter('kernel.bundles'); + // determine if AcmeGoodbyeBundle is registered + if (!isset($bundles['AcmeGoodbyeBundle'])) { + // disable AcmeGoodbyeBundle in Bundles + $config = array('use_acme_goodbye' => false); + foreach ($container->getExtensions() as $name => $extension) { + switch ($name) { + case 'acme_something': + case 'acme_other': + // set use_acme_goodbye to false in the config of acme_something and acme_other + // note that if the user manually configured use_acme_goodbye to true in the + // app/config/config.yml then the setting would in the end be true and not false + $container->prependExtensionConfig($name, $config); + break; + } + } + } + + // process the configuration of AcmeHelloExtension + $configs = $container->getExtensionConfig($this->getAlias()); + // use the Configuration class to generate a config array with the settings ``acme_hello`` + $config = $this->processConfiguration(new Configuration(), $configs); + + // check if entity_manager_name is set in the ``acme_hello`` configuration + if (isset($config['entity_manager_name'])) { + // prepend the acme_something settings with the entity_manager_name + $config = array('entity_manager_name' => $config['entity_manager_name']); + $container->prependExtensionConfig('acme_something', $config); + } + } + +The above would be the equivalent of writing the following into the ``app/config/config.yml`` +in case ``AcmeGoodbyeBundle`` is not registered and the ``entity_manager_name`` setting +for ``acme_hello`` is set to ``non_default``:: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + + acme_something: + # ... + use_acme_goodbye: false + entity_manager_name: non_default + + acme_other: + # ... + use_acme_goodbye: false + + .. code-block:: xml + + + + + non_default + + + + + .. code-block:: php + + // app/config/config.php + + $container->loadFromExtension('acme_something', array( + ..., + 'use_acme_goodbye' => false, + 'entity_manager_name' => 'non_default', + )); + $container->loadFromExtension('acme_other', array( + ..., + 'use_acme_goodbye' => false, + )); +