Skip to content

Updated the bundle configuration articles to Symfony 4 #8620

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 21 additions & 34 deletions bundles/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
How to Create Friendly Configuration for a Bundle
=================================================

If you open your application configuration file (usually ``app/config/config.yml``),
you'll see a number of different configuration sections, such as ``framework``,
``twig`` and ``doctrine``. Each of these configures a specific bundle, allowing
you to define options at a high level and then let the bundle make all the
low-level, complex changes based on your settings.
If you open your main application configuration directory (usually
``config/packages/``), you'll see a number of different files, such as
``framework.yaml``, ``twig.yaml`` and ``doctrine.yaml``. Each of these
configures a specific bundle, allowing you to define options at a high level and
then let the bundle make all the low-level, complex changes based on your
settings.

For example, the following configuration tells the FrameworkBundle to enable the
form integration, which involves the definition of quite a few services as well
Expand Down Expand Up @@ -43,17 +44,6 @@ as integration of other related components:
'form' => true,
));

.. sidebar:: Using Parameters to Configure your Bundle

If you don't have plans to share your bundle between projects, it doesn't
make sense to use this more advanced way of configuration. Since you use
the bundle only in one project, you can just change the service
configuration each time.

If you *do* want to be able to configure something from within
``config.yml``, you can always create a parameter there and use that
parameter somewhere else.

Using the Bundle Extension
--------------------------

Expand All @@ -71,15 +61,15 @@ bundle configuration would look like:

.. code-block:: yaml

# app/config/config.yml
# config/packages/acme_social.yaml
acme_social:
twitter:
client_id: 123
client_secret: your_secret

.. code-block:: xml

<!-- app/config/config.xml -->
<!-- config/packages/acme_social.xml -->
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Expand All @@ -96,7 +86,7 @@ bundle configuration would look like:

.. code-block:: php

// app/config/config.php
// config/packages/acme_social.php
$container->loadFromExtension('acme_social', array(
'client_id' => 123,
'client_secret' => 'your_secret',
Expand Down Expand Up @@ -145,20 +135,20 @@ For the configuration example in the previous section, the array passed to your
)

Notice that this is an *array of arrays*, not just a single flat array of the
configuration values. This is intentional, as it allows Symfony to parse
several configuration resources. For example, if ``acme_social`` appears in
another configuration file - say ``config_dev.yml`` - with different values
beneath it, the incoming array might look like this::
configuration values. This is intentional, as it allows Symfony to parse several
configuration resources. For example, if ``acme_social`` appears in another
configuration file - say ``config/packages/dev/acme_social.yaml`` - with
different values beneath it, the incoming array might look like this::

array(
// values from config.yml
// values from config/packages/acme_social.yaml
array(
'twitter' => array(
'client_id' => 123,
'client_secret' => 'your_secret',
),
),
// values from config_dev.yml
// values from config/packages/dev/acme_social.yaml
array(
'twitter' => array(
'client_id' => 456,
Expand Down Expand Up @@ -219,7 +209,6 @@ force validation (e.g. if an additional option was passed, an exception will be
thrown)::

// src/Acme/SocialBundle/DependencyInjection/AcmeSocialExtension.php

public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
Expand Down Expand Up @@ -324,12 +313,10 @@ In your extension, you can load this and dynamically set its arguments::
Modifying the Configuration of Another Bundle
---------------------------------------------

If you have multiple bundles that depend on each other, it may be useful
to allow one ``Extension`` class to modify the configuration passed to another
bundle's ``Extension`` class, as if the end-developer has actually placed that
configuration in their ``app/config/config.yml`` file. This can be achieved
using a prepend extension. For more details, see
:doc:`/bundles/prepend_extension`.
If you have multiple bundles that depend on each other, it may be useful to
allow one ``Extension`` class to modify the configuration passed to another
bundle's ``Extension`` class. This can be achieved using a prepend extension.
For more details, see :doc:`/bundles/prepend_extension`.

Dump the Configuration
----------------------
Expand Down Expand Up @@ -401,7 +388,7 @@ namespace is then replaced with the XSD validation base path returned from
method. This namespace is then followed by the rest of the path from the base
path to the file itself.

By convention, the XSD file lives in the ``Resources/config/schema``, but you
By convention, the XSD file lives in the ``Resources/config/schema/``, but you
can place it anywhere you like. You should return this path as the base path::

// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
Expand All @@ -422,7 +409,7 @@ Assuming the XSD file is called ``hello-1.0.xsd``, the schema location will be

.. code-block:: xml

<!-- app/config/config.xml -->
<!-- config/packages/acme_hello.xml -->
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Expand Down
101 changes: 29 additions & 72 deletions bundles/extension.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,29 @@
How to Load Service Configuration inside a Bundle
=================================================

In Symfony, you'll find yourself using many services. These services can be
registered in the ``app/config/`` directory of your application. But when you
want to decouple the bundle for use in other projects, you want to include the
service configuration in the bundle itself. This article will teach you how to
do that.
Services created by bundles are not defined in the main ``config/services.yaml``
file used by the application but in the bundles themselves. This article
explains how to create and load those bundle services files.

Creating an Extension Class
---------------------------

In order to load service configuration, you have to create a Dependency
Injection (DI) Extension for your bundle. This class has some conventions in order
to be detected automatically. But you'll later see how you can change it to
your own preferences. By default, the Extension has to comply with the
following conventions:
Injection (DI) Extension for your bundle. By default, the Extension class must
follow these conventions (but later you'll learn how to skip them if needed):

* It has to live in the ``DependencyInjection`` namespace of the bundle;

* It has to implement the :class:`Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface`,
which is usually achieve by extending the
:class:`Symfony\\Component\\DependencyInjection\\Extension\\Extension` class;

* The name is equal to the bundle name with the ``Bundle`` suffix replaced by
``Extension`` (e.g. the Extension class of the AppBundle would be called
``AppExtension`` and the one for AcmeHelloBundle would be called
``Extension`` (e.g. the Extension class of the AcmeBundle would be called
``AcmeExtension`` and the one for AcmeHelloBundle would be called
``AcmeHelloExtension``).

The Extension class should implement the
:class:`Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface`,
but usually you would simply extend the
:class:`Symfony\\Component\\DependencyInjection\\Extension\\Extension` class::
This is how the extension of an AcmeHelloBundle should look like::

// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;
Expand Down Expand Up @@ -65,11 +62,11 @@ method to return the instance of the extension::
}
}

Since the new Extension class name doesn't follow the naming conventions, you
should also override
In addition, when the new Extension class name doesn't follow the naming
conventions, you must also override the
:method:`Extension::getAlias() <Symfony\\Component\\DependencyInjection\\Extension\\Extension::getAlias>`
to return the correct DI alias. The DI alias is the name used to refer to the
bundle in the container (e.g. in the ``app/config/config.yml`` file). By
method to return the correct DI alias. The DI alias is the name used to refer to
the bundle in the container (e.g. in the ``config/packages/`` files). By
default, this is done by removing the ``Extension`` suffix and converting the
class name to underscores (e.g. ``AcmeHelloExtension``'s DI alias is
``acme_hello``).
Expand All @@ -86,11 +83,10 @@ container.

In the ``load()`` method, you can use PHP code to register service definitions,
but it is more common if you put these definitions in a configuration file
(using the Yaml, XML or PHP format). Luckily, you can use the file loaders in
the extension!
(using the YAML, XML or PHP format).

For instance, assume you have a file called ``services.xml`` in the
``Resources/config`` directory of your bundle, your ``load()`` method looks like::
``Resources/config/`` directory of your bundle, your ``load()`` method looks like::

use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\Config\FileLocator;
Expand All @@ -105,39 +101,22 @@ For instance, assume you have a file called ``services.xml`` in the
$loader->load('services.xml');
}

Other available loaders are the ``YamlFileLoader``, ``PhpFileLoader`` and
``IniFileLoader``.

.. note::

The ``IniFileLoader`` can only be used to load parameters and it can only
load them as strings.

.. caution::

If you removed the default file with service definitions (i.e.
``config/services.yaml``), make sure to also remove it from the
``imports`` key in ``app/config/config.yml``.
The other available loaders are ``YamlFileLoader`` and ``PhpFileLoader``.

Using Configuration to Change the Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Extension is also the class that handles the configuration for that
particular bundle (e.g. the configuration in ``app/config/config.yml``). To
read more about it, see the ":doc:`/bundles/configuration`" article.
particular bundle (e.g. the configuration in ``config/packages/<bundle_alias>.yaml``).
To read more about it, see the ":doc:`/bundles/configuration`" article.

Adding Classes to Compile
-------------------------

Symfony creates a big ``classes.php`` file in the cache directory to aggregate
the contents of the PHP classes that are used in every request. This reduces the
I/O operations and increases the application performance.

Your bundles can also add their own classes into this file thanks to the
``addClassesToCompile()`` and ``addAnnotatedClassesToCompile()`` methods (both
work in the same way, but the second one is for classes that contain PHP
annotations). Define the classes to compile as an array of their fully qualified
class names::
Bundles can hint Symfony about which of their classes contain annotations so
they are compiled when generating the application cache to improve the overall
performance. Define the list of annotated classes to compile in the
``addAnnotatedClassesToCompile()`` method::

use App\Manager\UserManager;
use App\Utils\Slugger;
Expand All @@ -147,16 +126,12 @@ class names::
{
// ...

// this method can't compile classes that contain PHP annotations
$this->addClassesToCompile(array(
UserManager::class,
Slugger::class,
// ...
));

// add here only classes that contain PHP annotations
$this->addAnnotatedClassesToCompile(array(
// you can define the fully qualified class names...
'App\\Controller\\DefaultController',
// ... but glob patterns are also supported:
'**Bundle\\Controller\\',

// ...
));
}
Expand All @@ -166,24 +141,6 @@ class names::
If some class extends from other classes, all its parents are automatically
included in the list of classes to compile.

The classes to compile can also be added using file path patterns::

// ...
public function load(array $configs, ContainerBuilder $container)
{
// ...

$this->addClassesToCompile(array(
'**Bundle\\Manager\\',
// ...
));

$this->addAnnotatedClassesToCompile(array(
'**Bundle\\Controller\\',
// ...
));
}

Patterns are transformed into the actual class namespaces using the classmap
generated by Composer. Therefore, before using these patterns, you must generate
the full classmap executing the ``dump-autoload`` command of Composer.
Expand Down