8000 [DI] Documenting Abstract Bundle and Extension by yceruto · Pull Request #16801 · symfony/symfony-docs · GitHub
[go: up one dir, main page]

Skip to content

[DI] Documenting Abstract Bundle and Extension #16801

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
merged 9 commits into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Documenting Abstract Bundle and Extension
  • Loading branch information
yceruto committed May 21, 2022
commit 426e289ec2fb34315c231acea98ea2450ab7bd79
53 changes: 35 additions & 18 deletions bundles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,33 +48,52 @@ The new bundle is called AcmeTestBundle, where the ``Acme`` portion is an exampl
name that should be replaced by some "vendor" name that represents you or your
organization (e.g. ABCTestBundle for some company named ``ABC``).

Start by creating a ``src/Acme/TestBundle/`` directory and adding a new file
Start by creating a ``Acme/TestBundle/src/`` directory and adding a new file
called ``AcmeTestBundle.php``::

// src/Acme/TestBundle/AcmeTestBundle.php
namespace App\Acme\TestBundle;
// Acme/TestBundle/src/AcmeTestBundle.php
namespace Acme\TestBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class AcmeTestBundle extends Bundle
class AcmeTestBundle extends AbstractBundle
{
}

.. versionadded:: 6.1

The ``AbstractBundle`` was introduced in Symfony 6.1. If your bundle must be compatible
with previous Symfony versions you have to extend from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\Bundle`
instead.

.. tip::

The name AcmeTestBundle follows the standard
:ref:`Bundle naming conventions <bundles-naming-conventions>`. You could
also choose to shorten the name of the bundle to simply TestBundle by naming
this class TestBundle (and naming the file ``TestBundle.php``).

This empty class is the only piece you need to create the new bundle. Though
It's recommended to place your bundle class in the ``src/`` directory and keep out all the
configuration files, templates, translations, etc. By default, Symfony determines the bundle path from the
directory where the bundle class is placed, so you have to define the :method:`Symfony\\Component\\HttpKernel\\Bundle\\Bundle::getPath`
method to tell Symfony what is the root directory of your bundle path::

class AcmeTestBundle extends AbstractBundle
{
public function getPath(): string
{
return \dirname(__DIR__);
}
}

This almost empty class is the only piece you need to create the new bundle. Though
commonly empty, this class is powerful and can be used to customize the behavior
of the bundle. Now that you've created the bundle, enable it::

// config/bundles.php
return [
// ...
App\Acme\TestBundle\AcmeTestBundle::class => ['all' => true],
Acme\TestBundle\AcmeTestBundle::class => ['all' => true],
];

And while it doesn't do anything yet, AcmeTestBundle is now ready to be used.
Expand All @@ -86,26 +105,24 @@ The directory structure of a bundle is meant to help to keep code consistent
between all Symfony bundles. It follows a set of conventions, but is flexible
to be adjusted if needed:

``Controller/``
``src/Controller/``
Contains the controllers of the bundle (e.g. ``RandomController.php``).

``DependencyInjection/``
Holds certain Dependency Injection Extension classes, which may import service
configuration, register compiler passes or more (this directory is not
necessary).

``Resources/config/``
``config/``
Houses configuration, including routing configuration (e.g. ``routing.yaml``).

``Resources/views/``
Holds templates organized by controller name (e.g. ``Random/index.html.twig``).
``templates/``
Holds templates organized by controller name (e.g. ``random/index.html.twig``).

``translations/``
Holds translations organized by domain and locale (e.g. ``AcmeTestBundle.en.xlf``).

``Resources/public/``
``public/``
Contains web assets (images, stylesheets, etc) and is copied or symbolically
linked into the project ``public/`` directory via the ``assets:install`` console
command.

``Tests/``
``tests/``
Holds all tests for the bundle.

A bundle can be as small or large as the feature it implements. It contains
Expand Down
51 changes: 51 additions & 0 deletions bundles/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,57 @@ Assuming the XSD file is called ``hello-1.0.xsd``, the schema location will be
<!-- ... -->
</container>

Defining Configuration directly in your Bundle class
----------------------------------------------------

.. versionadded:: 6.1

The ``AbstractBundle`` class is introduced in Symfony 6.1.

As another option, you can define the extension configuration directly in your Bundle
class by implementing :class:`Symfony\\Component\\Config\\Definition\\ConfigurableInterface`,
which is already supported when your bundle extend from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`::

use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;

class AcmeFooBundle extends AbstractBundle
{
public function configure(DefinitionConfigurator $definition): void
{
// loads config definition from a file
$definition->import('../config/definition.php');

// loads config definition from multiple files (when it's too long you can split it)
$definition->import('../config/definition/*.php');

// if the configuration is short, consider adding it in this class
$definition->rootNode()
->children()
->scalarNode('foo')->defaultValue('bar')->end()
->end()
;
}
}

This method is a shortcut of the previous "Extension", "Configuration" and "TreeBuilder" convention,
where you also have the possibility to import configuration definition from an external file::

// Acme/FooBundle/config/definition.php
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;

return static function (DefinitionConfigurator $definition) {
$definition->rootNode()
->children()
->scalarNode('foo')->defaultValue('bar')->end()
->end()
;
};

.. note::

The "configure()" method is called only at compiler time.

.. _`FrameworkBundle Configuration`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
.. _`TwigBundle Configuration`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
.. _`XML namespace`: https://en.wikipedia.org/wiki/XML_namespace
Expand Down
41 changes: 41 additions & 0 deletions bundles/extension.rst
9E88
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,44 @@ the full classmap executing the ``dump-autoload`` command of Composer.
This technique can't be used when the classes to compile use the ``__DIR__``
or ``__FILE__`` constants, because their values will change when loading
these classes from the ``classes.php`` file.

Loading Services directly in your Bundle class
----------------------------------------------

.. versionadded:: 6.1

The ``AbstractBundle`` class is introduced in Symfony 6.1.

Alternatively, you can define and load services configuration directly in a bundle class
by extending from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
and defining the :method:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle::loadExtension` method::

use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

class AcmeFooBundle extends AbstractBundle
{
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
{
$container->parameters()
->set('foo', $config['foo']);

$container->import('../config/services.php');

if ('bar' === $config['foo']) {
$container->services()
->set(Parser::class);
}
}
}

This method is a shortcut of the previous "load()" method, but with more options
to define and import the service configuration with less effort. The ``$config``
argument is the previous ``$configs`` array but already merged and processed. And
through the ``$container`` configurator you can import the services configuration
from an external file in any supported format (php, yaml, xml) or simply define
them in place using the fluent interfaces.

.. note::

The "loadExtension()" like "load()" method is called only at compiler time.
18 changes: 9 additions & 9 deletions bundles/override.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ features of a bundle.

The bundle overriding mechanism means that you cannot use physical paths to
refer to bundle's resources (e.g. ``__DIR__/config/services.xml``). Always
use logical paths in your bundles (e.g. ``@FooBundle/Resources/config/services.xml``)
use logical paths in your bundles (e.g. ``@FooBundle/config/services.xml``)
and call the :ref:`locateResource() method <http-kernel-resource-locator>`
to turn them into physical paths when needed.

Expand All @@ -23,12 +23,12 @@ Templates

Third-party bundle templates can be overridden in the
``<your-project>/templates/bundles/<bundle-name>/`` directory. The new templates
must use the same name and path (relative to ``<bundle>/Resources/views/``) as
must use the same name and path (relative to ``<bundle>/templates/``) as
the original templates.

For example, to override the ``Resources/views/Registration/confirmed.html.twig``
template from the FOSUserBundle, create this template:
``<your-project>/templates/bundles/FOSUserBundle/Registration/confirmed.html.twig``
For example, to override the ``templates/registration/confirmed.html.twig``
template from the AcmeUserBundle, create this template:
``<your-project>/templates/bundles/AcmeUserBundle/registration/confirmed.html.twig``

.. caution::

Expand All @@ -43,9 +43,9 @@ extend from the original template, not from the overridden one:

.. code-block:: twig

{# templates/bundles/FOSUserBundle/Registration/confirmed.html.twig #}
{# templates/bundles/AcmeUserBundle/registration/confirmed.html.twig #}
{# the special '!' prefix avoids errors when extending from an overridden template #}
{% extends "@!FOSUser/Registration/confirmed.html.twig" %}
{% extends "@!AcmeUser/registration/confirmed.html.twig" %}

{% block some_block %}
...
Expand Down Expand Up @@ -173,7 +173,7 @@ For this reason, you can override any bundle translation file from the main
``translations/`` directory, as long as the new file uses the same domain.

For example, to override the translations defined in the
``Resources/translations/FOSUserBundle.es.yml`` file of the FOSUserBundle,
create a ``<your-project>/translations/FOSUserBundle.es.yml`` file.
``translations/AcmeUserBundle.es.yaml`` file of the AcmeUserBundle,
create a ``<your-project>/translations/AcmeUserBundle.es.yaml`` file.

.. _`the Doctrine documentation`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/inheritance-mapping.html#overrides
41 changes: 41 additions & 0 deletions bundles/prepend_extension.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,44 @@ More than one Bundle using PrependExtensionInterface
If there is more than one bundle that prepends the same extension and defines
the same key, the bundle that is registered **first** will take priority:
next bundles won't override this specific config setting.

Prepending Extension directly in your Bundle class
--------------------------------------------------

.. versionadded:: 6.1

The ``AbstractBundle`` class is introduced in Symfony 6.1.

By preference, you can append or prepend extension configuration directly in your Bundle
class for any bundle by extending from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
and defining the :method:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle::prependExtension` method::

use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

class FooBundle extends AbstractBundle
{
public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void
{
// prepend
$builder->prependExtensionConfig('framework', [
'cache' => ['prefix_seed' => 'foo/bar'],
]);

// append
$container->extension('framework', [
'cache' => ['prefix_seed' => 'foo/bar'],
])

// append from file
$container->import('../config/packages/cache.php');
}
}

This method is a shortcut of the previous "PrependExtensionInterface::prepend" method,
allowing you also to import and append extension config from an external file in one of
the supported formats (php, yaml, xml).

.. note::

The "prependExtension()" like "prepend()" method is called only at compiler time.
Loading
0