Skip to content

Commit bc611fc

Browse files
committed
added docs for PrependExtensionInterface
1 parent dccf123 commit bc611fc

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

components/dependency_injection/compilation.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,29 @@ but also load a secondary one only if a certain parameter is set::
248248

249249
.. _components-dependency-injection-compiler-passes:
250250

251+
Prepending configuration passed to the Extension
252+
------------------------------------------------
253+
254+
An Extension can prepend the configuration of any Bundle before the ``load()``
255+
method is called by implementing :class:`Symfony\\Component\\DependencyInjection\\Compiler\\PrependExtensionInterface`::
256+
257+
use Symfony\Component\DependencyInjection\Compiler\PrependExtensionInterface;
258+
// ...
259+
260+
class AcmeDemoExtension implements ExtensionInterface, PrependExtensionInterface
261+
{
262+
// ...
263+
264+
public function prepend()
265+
{
266+
// ...
267+
268+
$container->prependExtensionConfig($name, $config);
269+
270+
// ...
271+
}
272+
}
273+
251274
Creating a Compiler Pass
252275
------------------------
253276

cookbook/bundles/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ Bundles
88
inheritance
99
override
1010
extension
11+
prepend_extension
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
.. index::
2+
single: Configuration; Semantic
3+
single: Bundle; Extension configuration
4+
5+
How to simplify configuration of multiple Bundle
6+
================================================
7+
8+
Especially when building reusable and extensible applications developers are
9+
often faced with a choice, either create a single Bundle or create multiple
10+
Bundles. Creating a single Bundle has the draw back that its impossible for
11+
users to choose to remove functionality they are not using. Creating multiple
12+
Bundles has the draw back that configuration becomes more tedious and settings
13+
often need to be repeated for various Bundles.
14+
15+
Using the below approach it is possible to remove the disadvantage of the
16+
multiple Bundle approach, by enabling a single Extension to prepend the settings
17+
for any Bundle. It can use the settings defined in the ``app/config/config.yml``
18+
to prepend settings just as if they would have been written explicitly by the
19+
user in the application configuration.
20+
21+
For example, this could be used to configure the entity manager name to use in
22+
multiple Bundle. Or it can be used to enable an optional feature that depends
23+
on another Bundle being loaded as well.
24+
25+
In order for an Extension to be able to do this it needs to implement
26+
:class:`Symfony\\Component\\DependencyInjection\\Compiler\\PrependExtensionInterface`::
27+
28+
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
29+
namespace Acme\HelloBundle\DependencyInjection;
30+
31+
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
32+
use Symfony\Component\\DependencyInjection\PrependExtensionInterface;
33+
use Symfony\Component\DependencyInjection\ContainerBuilder;
34+
35+
class AcmeHelloExtension extends Extension implements PrependExtensionInterface
36+
{
37+
// ...
38+
39+
public function prepend(ContainerBuilder $container)
40+
{
41+
// ...
42+
}
43+
}
44+
45+
Inside the :method:`Symfony\\Component\\DependencyInjection\\Compiler\\PrependExtensionInterface::prepend()`
46+
method developers have full access to the :class:`Symfony\Component\DependencyInjection\ContainerBuilder`
47+
instance just before the :method:`Symfony\Component\HttpKernel\DependencyInjection\ExtensionInterface:load()`
48+
method is called on the registered Bundle Extensions. In order to prepend settings
49+
to a Bundle extension developers can use the
50+
:method:`Symfony\Component\DependencyInjection\ContainerBuilder:prependExtensionConfig()`
51+
method on the :class:`Symfony\Component\DependencyInjection\ContainerBuilder`
52+
instance. As this method only prepends settings, any other settings done explicitly
53+
inside the ``app/config/config.yml`` would override these prepended settings.
54+
55+
The following example illustrates how to prepend
56+
a configuration setting in multiple Bundles as well as disable a flag in multiple Bundles
57+
in case specific other Bundle is not registered::
58+
59+
public function prepend(ContainerBuilder $container)
60+
{
61+
// get all Bundles
62+
$bundles = $container->getParameter('kernel.bundles');
63+
// determine if AcmeGoodbyeBundle is registered
64+
if (!isset($bundles['AcmeGoodbyeBundle'])) {
65+
// disable AcmeGoodbyeBundle in Bundles
66+
$config = array('use_acme_goodbye' => false);
67+
foreach ($container->getExtensions() as $name => $extension) {
68+
switch ($name) {
69+
case 'acme_something':
70+
case 'acme_other':
71+
// set use_acme_goodbye to false in the config of acme_something and acme_other
72+
// note that if the user manually configured use_acme_goodbye to true in the
73+
// app/config/config.yml then the setting would in the end be true and not false
74+
$container->prependExtensionConfig($name, $config);
75+
break;
76+
}
77+
}
78+
}
79+
80+
// process the configuration of AcmeHelloExtension
81+
$configs = $container->getExtensionConfig($this->getAlias());
82+
// use the Configuration class to generate a config array with the settings ``acme_hello``
83+
$config = $this->processConfiguration(new Configuration(), $configs);
84+
85+
// check if entity_manager_name is set in the ``acme_hello`` configuration
86+
if (isset($config['entity_manager_name'])) {
87+
// prepend the acme_something settings with the entity_manager_name
88+
$config = array('entity_manager_name' => $config['entity_manager_name']);
89+
$container->prependExtensionConfig('acme_something', $config);
90+
}
91+
}
92+
93+
The above would be the equivalent of writing the following into the ``app/config/config.yml``
94+
in case ``AcmeGoodbyeBundle`` is not registered and the ``entity_manager_name`` setting
95+
for ``acme_hello`` is set to ``non_default``::
96+
97+
.. configuration-block::
98+
99+
.. code-block:: yaml
100+
101+
# app/config/config.yml
102+
103+
acme_something:
104+
# ...
105+
use_acme_goodbye: false
106+
entity_manager_name: non_default
107+
108+
acme_other:
109+
# ...
110+
use_acme_goodbye: false
111+
112+
.. code-block:: xml
113+
114+
<!-- app/config/config.xml -->
115+
116+
<acme-something:config use-acme-goodbye="false">
117+
<acme-something:entity-manager-name>non_default</acme-something:entity-manager-name>
118+
</acme-something:config>
119+
120+
<acme-other:config use-acme-goodbye="false" />
121+
122+
.. code-block:: php
123+
124+
// app/config/config.php
125+
126+
$container->loadFromExtension('acme_something', array(
127+
...,
128+
'use_acme_goodbye' => false,
129+
'entity_manager_name' => 'non_default',
130+
));
131+
$container->loadFromExtension('acme_other', array(
132+
...,
133+
'use_acme_goodbye' => false,
134+
));
135+

0 commit comments

Comments
 (0)