8000 Rewrite the bundle docs a bit more · symfony/symfony-docs@558b02e · GitHub
[go: up one dir, main page]

Skip to content

Commit 558b02e

Browse files
committed
Rewrite the bundle docs a bit more
1 parent 7cf9bf4 commit 558b02e

File tree

5 files changed

+191
-139
lines changed

5 files changed

+191
-139
lines changed

bundles.rst

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,11 @@ Creating a Bundle
4646
This section creates and enables a new bundle to show there are only a few steps required.
4747
The new bundle is called AcmeTestBundle, where the ``Acme`` portion is an example
4848
name that should be replaced by some "vendor" name that represents you or your
49-
organization (e.g. ABCTestBundle for some company named ``ABC``).
49+
organization (e.g. AbcTestBundle for some company named ``Abc``).
5050

51-
Start by creating a ``Acme/TestBundle/src/`` directory and adding a new file
52-
called ``AcmeTestBundle.php``::
51+
Start by adding creating a new class called ``AcmeTestBundle``::
5352

54-
// Acme/TestBundle/src/AcmeTestBundle.php
53+
// src/AcmeTestBundle.php
5554
namespace Acme\TestBundle;
5655

5756
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
@@ -62,9 +61,10 @@ called ``AcmeTestBundle.php``::
6261

6362
.. versionadded:: 6.1
6463

65-
The ``AbstractBundle`` was introduced in Symfony 6.1.
64+
The :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle` was
65+
introduced in Symfony 6.1.
6666

67-
.. warning::
67+
.. caution::
6868

6969
If your bundle must be compatible with previous Symfony versions you have to
7070
extend from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\Bundle` instead.
@@ -96,7 +96,7 @@ between all Symfony bundles. It follows a set of conventions, but is flexible
9696
to be adjusted if needed:
9797

9898
``src/``
99-
Contains mainly PHP classes related to the bundle logic (e.g. ``Controller/RandomController.php``).
99+
Contains all PHP classes related to the bundle logic (e.g. ``Controller/RandomController.php``).
100100

101101
``config/``
102102
Houses configuration, including routing configuration (e.g. ``routing.yaml``).
@@ -115,32 +115,44 @@ to be adjusted if needed:
115115
``tests/``
116116
Holds all tests for the bundle.
117117

118-
It's recommended to use the `PSR-4`_ autoload standard: use the namespace as key,
119-
and the location of the bundle's main class (relative to ``composer.json``)
120-
as value. As the main class is located in the ``src/`` directory of the bundle:
118+
.. caution::
121119

122-
.. code-block:: json
120+
The recommended bundle structure was changed in Symfony 5, read the
121+
`Symfony 4.4 bundle documentation`_ for information about the old
122+
structure.
123123

124-
{
125-
"autoload": {
126-
"psr-4": {
127-
"Acme\\TestBundle\\": "src/"
128-
}
129-
},
130-
"autoload-dev": {
131-
"psr-4": {
132-
"Acme\\TestBundle\\Tests\\": "tests/"
124+
When using the new ``AbstractBundle`` class, the bundle defaults to the
125+
new structure. Override the ``Bundle::getPath()`` method to change to
126+
the old structure::
127+
128+
class AcmeTestBundle extends AbstractBundle
129+
{
130+
public function getPath(): string
131+
{
132+
return __DIR__;
133133
}
134134
}
135-
}
136135

137-
A bundle can be as small or large as the feature it implements. It contains
138-
only the files you need and nothing else.
136+
.. tip::
139137

140-
As you move through the guides, you'll learn how to persist objects to a
141-
database, create and validate forms, create translations for your application,
142-
write tests and much more. Each of these has their own place and role within
143-
the bundle.
138+
It's recommended to use the `PSR-4`_ autoload standard: use the namespace as key,
139+
and the location of the bundle's main class (relative to ``composer.json``)
140+
as value. As the main class is located in the ``src/`` directory of the bundle:
141+
142+
.. code-block:: json
143+
144+
{
145+
"autoload": {
146+
"psr-4": {
147+
"Acme\\TestBundle\\": "src/"
148+
}
149+
},
150+
"autoload-dev": {
151+
"psr-4": {
152+
"Acme\\TestBundle\\Tests\\": "tests/"
153+
}
154+
}
155+
}
144156
145157
Learn more
146158
----------
@@ -152,4 +164,5 @@ Learn more
152164
* :doc:`/bundles/prepend_extension`
153165

154166
.. _`third-party bundles`: https://github.com/search?q=topic%3Asymfony-bundle&type=Repositories
167+
.. _`Symfony 4.4 bundle documentation`: https://symfony.com/doc/4.4/bundles.html#bundle-directory-structure
155168
.. _`PSR-4`: https://www.php-fig.org/psr/psr-4/

bundles/configuration.rst

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,88 @@ In your extension, you can load this and dynamically set its arguments::
315315
// ... now use the flat $config array
316316
}
317317

318+
Using the Bundle Class
319+
----------------------
320+
321+
.. versionadded:: 6.1
322+
323+
The ``AbstractBundle`` class is introduced in Symfony 6.1.
324+
325+
Instead of creating an extension and configuration class, you can also
326+
extend :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle` to
327+
add this logic to the bundle class directly::
328+
329+
// src/AcmeSocialBundle.php
330+
namespace Acme\SocialBundle;
331+
332+
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
333+
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
334+
335+
class AcmeSocialBundle extends AbstractBundle
336+
{
337+
public function configure(DefinitionConfigurator $definition): void
338+
{
339+
$definition->rootNode()
340+
->children()
341+
->arrayNode('twitter')
342+
->children()
343+
->integerNode('client_id')->end()
344+
->scalarNode('client_secret')->end()
345+
->end()
346+
->end() // twitter
347+
->end()
348+
;
349+
}
350+
351+
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
352+
{
353+
// Contrary to the Extension class, the "$config" variable is already merged
354+
// and processed. You can use it directly to configure the service container.
355+
$container->services()
356+
->get('acme.social.twitter_client')
357+
->arg(0, $config['twitter']['client_id'])
358+
->arg(1, $config['twitter']['client_secret'])
359+
;
360+
}
361+
}
362+
363+
.. note::
364+
365+
The ``configure()`` and ``loadExtension()`` methods are called only at compile time.
366+
367+
.. tip::
368+
369+
The ``AbstractBundle::configure()`` method also allows to import the
370+
configuration definitino from one or more files::
371+
372+
// src/AcmeSocialBundle.php
373+
374+
// ...
375+
class AcmeSocialBundle extends AbstractBundle
376+
{
377+
public function configure(DefinitionConfigurator $definition): void
378+
{
379+
$definition->import('../config/definition.php');
380+
// you can also use glob patterns
381+
//$definition->import('../config/definition/*.php');
382+
}
383+
384+
// ...
385+
}
386+
387+
.. code-block:: php
388+
389+
// config/definition.php
390+
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
391+
392+
return static function (DefinitionConfigurator $definition) {
393+
$definition->rootNode()
394+
->children()
395+
->scalarNode('foo')->defaultValue('bar')->end()
396+
->end()
397+
;
398+
};
399+
318400
Modifying the Configuration of Another Bundle
319401
---------------------------------------------
320402

@@ -431,57 +513,6 @@ Assuming the XSD file is called ``hello-1.0.xsd``, the schema location will be
431513
<!-- ... -->
432514
</container>
433515
434-
Defining Configuration directly in your Bundle class
435-
----------------------------------------------------
436-
437-
.. versionadded:: 6.1
438-
439-
The ``AbstractBundle`` class is introduced in Symfony 6.1.
440-
441-
As another option, you can define the extension configuration directly in your Bundle
442-
class by implementing :class:`Symfony\\Component\\Config\\Definition\\ConfigurableInterface`,
443-
which is already supported when your bundle extend from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`::
444-
445-
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
446-
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
447-
448-
class AcmeFooBundle extends AbstractBundle
449-
{
450-
public function configure(DefinitionConfigurator $definition): void
451-
{
452-
// loads config definition from a file
453-
$definition->import('../config/definition.php');
454-
455-
// loads config definition from multiple files (when it's too long you can split it)
456-
$definition->import('../config/definition/*.php');
457-
458-
// if the configuration is short, consider adding it in this class
459-
$definition->rootNode()
460-
->children()
461-
->scalarNode('foo')->defaultValue('bar')->end()
462-
->end()
463-
;
464-
}
465-
}
466-
467-
This method is a shortcut of the previous "Extension", "Configuration" and "TreeBuilder" convention,
468-
now you also have the possibility to import configuration definition from an external file::
469-
470-
// Acme/FooBundle/config/definition.php
471-
use Symfony\Component\Config\Definition\Configurator\DefinitionConfigurator;
472-
473-
return static function (DefinitionConfigurator $definition) {
474-
$definition->rootNode()
475-
->children()
476-
->scalarNode('foo')->defaultValue('bar')->end()
477-
->end()
478-
;
479-
};
480-
481-
.. note::
482-
483-
The "configure()" method is called only at compile time.
484-
485516
.. _`FrameworkBundle Configuration`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
486517
.. _`TwigBundle Configuration`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/TwigBundle/DependencyInjection/Configuration.php
487518
.. _`XML namespace`: https://en.wikipedia.org/wiki/XML_namespace

bundles/extension.rst

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ For instance, assume you have a file called ``services.xml`` in the
9797
{
9898
$loader = new XmlFileLoader(
9999
$container,
100-
new FileLocator(__DIR__.'/../Resources/config')
100+
new FileLocator(__DIR__.'/../config')
101101
);
102102
$loader->load('services.xml');
103103
}
10000
@@ -111,6 +111,57 @@ The Extension is also the class that handles the configuration for that
111111
particular bundle (e.g. the configuration in ``config/packages/<bundle_alias>.yaml``).
112112
To read more about it, see the ":doc:`/bundles/configuration`" article.
113113

114+
Loading Services directly in your Bundle class
115+
----------------------------------------------
116+
117+
.. versionadded:: 6.1
118+
119+
The ``AbstractBundle`` class is introduced in Symfony 6.1.
120+
121+
Alternatively, you can define and load services configuration directly in a
122+
bundle class instead of creating a specific ``Extension`` class. You can do
123+
this by extending from :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
124+
and defining the :method:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle::loadExtension`
125+
method::
126+
127+
// ...
128+
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
129+
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
130+
131+
class AcmeHelloBundle extends AbstractBundle
132+
{
133+
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
134+
{
135+
// load an XML, PHP or Yaml file
136+
$container->import('../config/services.xml');
137+
138+
// you can also add or replace parameters and services
139+
$container->parameters()
140+
->set('acme_hello.phrase', $config['phrase'])
141+
;
142+
143+
if ($config['scream']) {
144+
$container->services()
145+
->get('acme_hello.printer')
146+
->class(ScreamingPrinter::class)
147+
;
148+
}
149+
}
150+
}
151+
152+
This method works similar to the ``Extension::load()`` method, but it uses
153+
a new API to define and import service configuration.
154+
155+
.. note::
156+
157+
Contrary to the ``$configs`` parameter in ``Extension::load()``, the
158+
``$config`` parameter is already merged and processed by the
159+
``AbstractBundle``.
160+
161+
.. note::
162+
163+
The ``loadExtension()`` is called only at compile time.
164+
114165
Adding Classes to Compile
115166
-------------------------
116167

@@ -147,44 +198,3 @@ the full classmap executing the ``dump-autoload`` command of Composer.
147198
This technique can't be used when the classes to compile use the ``__DIR__``
148199
or ``__FILE__`` constants, because their values will change when loading
149200
these classes from the ``classes.php`` file.
150-
151-
Loading Services directly in your Bundle class
152-
----------------------------------------------
153-
154-
.. versionadded:: 6.1
155-
156-
The ``AbstractBundle`` class is introduced in Symfony 6.1.
157-
158-
Alternatively, you can define and load services configuration directly in a bundle class
159-
by extending from the :class:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle`
160-
and defining the :method:`Symfony\\Component\\HttpKernel\\Bundle\\AbstractBundle::loadExtension` method::
161-
162-
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
163-
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
164-
165-
class AcmeFooBundle extends AbstractBundle
166-
{
167-
public function loadExtension(array $config, ContainerConfigurator $container, ContainerBuilder $builder): void
168-
{
169-
$container->parameters()
170-
->set('foo', $config['foo']);
171-
172-
$container->import('../config/services.php');
173-
174-
if ('bar' === $config['foo']) {
175-
$container->services()
176-
->set(Parser::class);
177-
}
178-
}
179-
}
180-
181-
This method is a shortcut of the previous "load()" method, but with more options
182-
to define and import the service configuration with less effort. The ``$config``
183-
argument is the previous ``$configs`` array but already merged and processed. And
184-
through the ``$container`` configurator you can import the services configuration
185-
from an external file in any supported format (php, yaml, xml) or simply define
186-
them in place using the fluent interfaces.
187-
188-
.. note::
189-
190-
The "loadExtension()", as the "load()" method, are called only at compile time.

0 commit comments

Comments
 (0)
0