-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Adding more detail to the DI compilation page #1660
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
weaverryan
merged 4 commits into
symfony:2.0
from
richardmiller-zz:adding_to_di_compilation
Sep 9, 2012
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
7c69432
Adding more detail to the DI compilation page
richardmiller-zz 5702a9b
Updating to remove HTTPKernel specific method from di config processi…
richardmiller-zz 15e8e87
Adding a note that XSD validation of config files is optional
richardmiller-zz 9542954
Changing syntax used for missing code sections
richardmiller-zz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,220 @@ validity, further compiler passes are used to optimize the configuration | |
before it is cached. For example, private services and abstract services | ||
are removed, and aliases are resolved. | ||
|
||
Managing Configuration with Extensions | ||
-------------------------------------- | ||
|
||
As well as loading configuration directly into the container as shown in | ||
:doc:`/components/dependency_injection/introduction`, you can manage it by | ||
registering extensions with the container. The first step in the compilation | ||
process is to load configuration from any extension classes registered with | ||
the container. Unlike the configuration loaded directly they are only processed | ||
when the container is compiled. If your application is modular then extensions | ||
allow each module to register and manage their own service configuration. | ||
|
||
The extensions must implement :class:`Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface` | ||
and can be registered with the container with:: | ||
|
||
$container->registerExtension($extension); | ||
|
||
The main work of the extension is done in the ``load`` method. In the load method | ||
you can load configuration from one or more configuration files as well as | ||
manipulate the container definitions using the methods shown in :doc:`/components/dependency_injection/definitions`. | ||
|
||
The ``load`` method is passed a fresh container to set up, which is then | ||
merged afterwards into the container it is registered with. This allows you | ||
to have several extensions managing container definitions independently. | ||
The extensions do not add to the containers configuration when they are added | ||
but are processed when the container's ``compile`` method is called. | ||
|
||
A very simple extension may just load configuration files into the container:: | ||
|
||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; | ||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; | ||
use Symfony\Component\Config\FileLocator; | ||
|
||
class AcmeDemoExtension implements ExtensionInterface | ||
{ | ||
public function load(array $configs, ContainerBuilder $container) | ||
{ | ||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | ||
$loader->load('services.xml'); | ||
} | ||
|
||
//-- | ||
} | ||
|
||
This does not gain very much compared to loading the file directly into the | ||
overall container being built. It just allows the files to be split up amongst | ||
the modules/bundles. Being able to affect the configuration of a module from | ||
configuration files outside of the module/bundle is needed to make a complex | ||
application configurable. This can be done by specifying sections of config files | ||
loaded directly into the container as being for a particular extension. These | ||
sections on the config will not be processed directly by the container but by the | ||
relevant Extension. | ||
|
||
The Extension must specify a ``getAlias`` method to implement the interface:: | ||
|
||
//-- | ||
|
||
class AcmeDemoExtension implements ExtensionInterface | ||
{ | ||
//-- | ||
|
||
public function getAlias() | ||
{ | ||
return 'acme_demo'; | ||
} | ||
} | ||
|
||
For YAML configuration files specifying the alias for the Extension as a key | ||
will mean that those values are passed to the Extension's ``load`` method: | ||
|
||
.. code-block:: yaml | ||
#-- | ||
|
||
acme_demo: | ||
foo: fooValue | ||
bar: barValue | ||
|
||
If this file is loaded into the configuration then the values in it are only | ||
processed when the container is compiled at which point the Extensions are loaded:: | ||
|
||
use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
use Symfony\Component\Config\FileLocator; | ||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; | ||
|
||
$container = new ContainerBuilder(); | ||
$loader = new YamlFileLoader($container, new FileLocator(__DIR__)); | ||
$loader->load('config.yml'); | ||
|
||
$container->registerExtension(new AcmeDemoExtension); | ||
//-- | ||
$container->compile(); | ||
|
||
The values from those sections of the config files are passed into the first | ||
argument of the ``load`` method of the extension:: | ||
|
||
public function load(array $configs, ContainerBuilder $container) | ||
{ | ||
$foo = $configs[0]['foo']; //fooValue | ||
$bar = $configs[0]['bar']; //barValue | ||
} | ||
|
||
The ``$configs`` argument is an array containing each different config file | ||
that was loaded into the container. You are only loading a single config file | ||
in the above example but it will still be within an array. The array will look | ||
like this:: | ||
|
||
array( | ||
array( | ||
'foo' => 'fooValue', | ||
'bar' => 'barValue', | ||
) | ||
) | ||
|
||
Whilst you can manually manage merging the different files, it is much better | ||
to use :doc:`the Config Component</components/config/introduction>` to merge | ||
and validate the config values. Using the configuration processing you could | ||
access the config value this way:: | ||
|
||
use Symfony\Component\Config\Definition\Processor; | ||
//-- | ||
|
||
public function load(array $configs, ContainerBuilder $container) | ||
{ | ||
$configuration = new Configuration(); | ||
$processor = new Processor(); | ||
$config = $processor->processConfiguration($configuration, $configs); | ||
|
||
$foo = $config['foo']; //fooValue | ||
$bar = $config['bar']; //barValue | ||
|
||
//-- | ||
} | ||
|
||
There are a further two methods you must implement. One to return the XML | ||
namespace so that the relevant parts of an XML config file are passed to | ||
the extension. The other to specify the base path to XSD files to validate | ||
the XML configuration:: | ||
|
||
public function getXsdValidationBasePath() | ||
{ | ||
return __DIR__.'/../Resources/config/'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you should mention that the XSD validation is optional (returning There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok, I have added a note |
||
} | ||
|
||
public function getNamespace() | ||
{ | ||
return 'http://www.example.com/symfony/schema/'; | ||
} | ||
|
||
..note:: | ||
XSD validation is optional, returning ``false`` from the ``getXsdValidationBasePath`` | ||
method will disable it. | ||
|
||
The XML version of the config would then look like this: | ||
|
||
.. code-block:: xml | ||
<?xml version="1.0" ?> | ||
|
||
<container xmlns="http://symfony.com/schema/dic/services" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns:acme_demo="http://www.example.com/symfony/schema/" | ||
xsi:schemaLocation="http://www.example.com/symfony/schema/ http://www.example.com/symfony/schema/hello-1.0.xsd"> | ||
|
||
<acme_demo:config> | ||
<acme_demo:foo>fooValue</acme_hello:foo> | ||
<acme_demo:bar>barValue</acme_demo:bar> | ||
</acme_demo:config> | ||
|
||
</container> | ||
|
||
..note:: | ||
In the Symfony2 full stack framework there is a base Extension class which | ||
implements these methods as well as a short cut method for processing the | ||
configuration. See :doc:`/cookbook/bundles/extension` for more details. | ||
|
||
The processed config value can now be added as container parameters as if they were | ||
listed in a ``parameters`` section of the config file but with merging multiple files | ||
and validation of the configuration thrown in:: | ||
|
||
public function load(array $configs, ContainerBuilder $container) | ||
{ | ||
$configuration = new Configuration(); | ||
$processor = new Processor(); | ||
$config = $processor->processConfiguration($configuration, $configs); | ||
|
||
$container->setParameter('acme_demo.FOO', $config['foo']) | ||
|
||
//-- | ||
} | ||
|
||
More complex configuration requirements can be catered for in the Extension | ||
classes. For example, you may choose to load a main service configuration file | ||
but also load a secondary one only if a certain parameter is set:: | ||
|
||
public function load(array $configs, ContainerBuilder $container) | ||
{ | ||
$configuration = new Configuration(); | ||
$processor = new Processor(); | ||
$config = $processor->processConfiguration($configuration, $configs); | ||
|
||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); | ||
$loader->load('services.xml'); | ||
|
||
if ($config['advanced']) { | ||
$loader->load('advanced.xml'); | ||
} | ||
} | ||
|
||
.. note:: | ||
|
||
If you need to manipulate the configuration loaded by an extension then | ||
you cannot do it from another extension as it uses a fresh container. | ||
You should instead use a compiler pass which works with the full container | ||
after the extensions have been processed. | ||
|
||
Creating a Compiler Pass | ||
------------------------ | ||
|
||
|
@@ -85,34 +299,6 @@ For example, to run your custom pass after the default removal passes have been | |
$container = new ContainerBuilder(); | ||
$container->addCompilerPass(new CustomCompilerPass, PassConfig::TYPE_AFTER_REMOVING); | ||
|
||
|
||
Managing Configuration with Extensions | ||
-------------------------------------- | ||
|
||
As well as loading configuration directly into the container as shown in | ||
:doc:`/components/dependency_injection/introduction`, you can manage it by registering | ||
extensions with the container. The extensions must implement :class:`Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface` | ||
and can be registered with the container with:: | ||
|
||
$container->registerExtension($extension); | ||
|
||
The main work of the extension is done in the ``load`` method. In the load method | ||
you can load configuration from one or more configuration files as well as | ||
manipulate the container definitions using the methods shown in :doc:`/components/dependency_injection/definitions`. | ||
|
||
The ``load`` method is passed a fresh container to set up, which is then | ||
merged afterwards into the container it is registered with. This allows you | ||
to have several extensions managing container definitions independently. | ||
The extensions do not add to the containers configuration when they are added | ||
but are processed when the container's ``compile`` method is called. | ||
|
||
.. note:: | ||
|
||
If you need to manipulate the configuration loaded by an extension then | ||
you cannot do it from another extension as it uses a fresh container. | ||
You should instead use a compiler pass which works with the full container | ||
after the extensions have been processed. | ||
|
||
Dumping the Configuration for Performance | ||
----------------------------------------- | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be
// ...
(as wel as all the other// --
below). You can find these rules here: symfony.com/doc/master/contributing/documentation/overview.html#standards