Skip to content

Commit 98c5c38

Browse files
committed
feature #5014 Updated the best practices article for reusable bundles (javiereguiluz)
This PR was merged into the 2.3 branch. Discussion ---------- Updated the best practices article for reusable bundles | Q | A | ------------- | --- | Doc fix? | yes | New docs? | no | Applies to | 2.3+ | Fixed tickets | #3616 Commits ------- 286631d Added a blank line beteen definition list items 776eaee Reworded as a definition list 4276ced Added back some information wrongly removed during the rebase fa0b902 Fixed a minor syntax issue 9981193 Minor fixes and added a cross link a391563 Updated the best practices article for reusable bundles
2 parents 317c868 + 286631d commit 98c5c38

File tree

2 files changed

+138
-97
lines changed

2 files changed

+138
-97
lines changed

components/dependency_injection/advanced.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
Advanced Container Configuration
55
================================
66

7+
.. _container-private-services:
8+
79
Marking Services as public / private
810
------------------------------------
911

cookbook/bundles/best_practices.rst

Lines changed: 136 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ This article is all about how to structure your **reusable bundles** so that
1313
they're easy to configure and extend. Many of these recommendations do not
1414
apply to application bundles because you'll want to keep those as simple
1515
as possible. For application bundles, just follow the practices shown throughout
16-
the :doc:`book </book/index>`, the :doc:`cookbook </cookbook/index>` and the
17-
:doc:`best practices </best_practices/index>` book.
16+
the book and cookbook.
17+
18+
.. seealso::
19+
20+
The best practices for application-specific bundles are discussed in
21+
:doc:`/best_practices/introduction`.
1822

1923
.. index::
2024
pair: Bundle; Naming conventions
@@ -24,8 +28,8 @@ the :doc:`book </book/index>`, the :doc:`cookbook </cookbook/index>` and the
2428
Bundle Name
2529
-----------
2630

27-
A bundle is also a PHP namespace. The namespace must follow the technical
28-
interoperability `standards`_ for PHP namespaces and class names: it starts
31+
A bundle is also a PHP namespace. The namespace must follow the `PSR-0`_ or
32+
`PSR-4`_ interoperability standards for PHP namespaces and class names: it starts
2933
with a vendor segment, followed by zero or more category segments, and it ends
3034
with the namespace short name, which must end with a ``Bundle`` suffix.
3135

@@ -41,15 +45,12 @@ bundle class name must follow these simple rules:
4145

4246
Here are some valid bundle namespaces and class names:
4347

44-
+-----------------------------------+--------------------------+
45-
| Namespace | Bundle Class Name |
46-
+===================================+==========================+
47-
| ``Acme\Bundle\BlogBundle`` | ``AcmeBlogBundle`` |
48-
+-----------------------------------+--------------------------+
49-
| ``Acme\Bundle\Social\BlogBundle`` | ``AcmeSocialBlogBundle`` |
50-
+-----------------------------------+--------------------------+
51-
| ``Acme\BlogBundle`` | ``AcmeBlogBundle`` |
52-
+-----------------------------------+--------------------------+
48+
========================== ==================
49+
Namespace Bundle Class Name
50+
========================== ==================
51+
``Acme\Bundle\BlogBundle`` ``AcmeBlogBundle``
52+
``Acme\BlogBundle`` ``AcmeBlogBundle``
53+
========================== ==================
5354

5455
By convention, the ``getName()`` method of the bundle class should return the
5556
class name.
@@ -67,49 +68,47 @@ class name.
6768
:class:`Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle`.
6869

6970
Each bundle has an alias, which is the lower-cased short version of the bundle
70-
name using underscores (``acme_hello`` for ``AcmeHelloBundle``, or
71-
``acme_social_blog`` for ``Acme\Social\BlogBundle`` for instance). This alias
72-
is used to enforce uniqueness within a bundle (see below for some usage
73-
examples).
71+
name using underscores (``acme_blog`` for ``AcmeBlogBundle``). This alias
72+
is used to enforce uniqueness within a project and for defining bundle's
73+
configuration options (see below for some usage examples).
7474

7575
Directory Structure
7676
-------------------
7777

78-
The basic directory structure of a HelloBundle must read as follows:
78+
The basic directory structure of an AcmeBlogBundle must read as follows:
7979

8080
.. code-block:: text
8181
82-
XXX/...
83-
HelloBundle/
84-
HelloBundle.php
85-
Controller/
86-
Resources/
87-
meta/
88-
LICENSE
89-
config/
90-
doc/
91-
index.rst
92-
translations/
93-
views/
94-
public/
95-
Tests/
96-
97-
The ``XXX`` directory(ies) reflects the namespace structure of the bundle.
98-
99-
The following files are mandatory:
100-
101-
* ``HelloBundle.php``;
102-
* ``Resources/meta/LICENSE``: The full license for the code;
82+
<your-bundle>/
83+
├─ AcmeBlogBundle.php
84+
├─ Controller/
85+
├─ README.md
86+
├─ Resources/
87+
│ ├─ meta/
88+
│ │ └─ LICENSE
89+
│ ├─ config/
90+
│ ├─ doc/
91+
│ │ └─ index.rst
92+
│ ├─ translations/
93+
│ ├─ views/
94+
│ └─ public/
95+
└─ Tests/
96+
97+
**The following files are mandatory**, because they ensure a structure convention
98+
that automated tools can rely on:
99+
100+
* ``AcmeBlogBundle.php``: This is the class that transforms a plain directory
101+
into a Symfony bundle;
102+
* ``README.md``: This file contains the basic description of the bundle and it
103+
usually shows some basic examples and links to its full documentation (it
104+
can use any of the markup formats supported by GitHub, such as ``README.rst``);
105+
* ``Resources/meta/LICENSE``: The full license for the code. The license file
106+
can also be stored in the bundle's root directory to follow the generic
107+
conventions about packages;
103108
* ``Resources/doc/index.rst``: The root file for the Bundle documentation.
104109

105-
.. note::
106-
107-
These conventions ensure that automated tools can rely on this default
108-
structure to work.
109-
110-
The depth of sub-directories should be kept to the minimal for most used
111-
classes and files (two levels at a maximum). More levels can be defined for
112-
non-strategic, less-used files.
110+
The depth of sub-directories should be kept to the minimum for most used
111+
classes and files (two levels maximum).
113112

114113
The bundle directory is read-only. If you need to write temporary files, store
115114
them under the ``cache/`` or ``log/`` directory of the host application. Tools
@@ -118,41 +117,31 @@ files are going to be part of the repository.
118117

119118
The following classes and files have specific emplacements:
120119

121-
+------------------------------+-----------------------------+
122-
| Type | Directory |
123-
+==============================+=============================+
124-
| Commands | ``Command/`` |
125-
+------------------------------+-----------------------------+
126-
| Controllers | ``Controller/`` |
127-
+------------------------------+-----------------------------+
128-
| Service Container Extensions | ``DependencyInjection/`` |
129-
+------------------------------+-----------------------------+
130-
| Event Listeners | ``EventListener/`` |
131-
+------------------------------+-----------------------------+
132-
| Configuration | ``Resources/config/`` |
133-
+------------------------------+-----------------------------+
134-
| Web Resources | ``Resources/public/`` |
135-
+------------------------------+-----------------------------+
136-
| Translation files | ``Resources/translations/`` |
137-
+------------------------------+-----------------------------+
138-
| Templates | ``Resources/views/`` |
139-
+------------------------------+-----------------------------+
140-
| Unit and Functional Tests | ``Tests/`` |
141-
+------------------------------+-----------------------------+
142-
143-
.. note::
144-
145-
When building a reusable bundle, model classes should be placed in the
146-
``Model`` namespace. See :doc:`/cookbook/doctrine/mapping_model_classes` for
147-
how to handle the mapping with a compiler pass.
120+
=============================== =============================
121+
Type Directory
122+
=============================== =============================
123+
Commands ``Command/``
124+
Controllers ``Controller/``
125+
Service Container Extensions ``DependencyInjection/``
126+
Event Listeners ``EventListener/``
127+
Model classes [1] ``Model/``
128+
Configuration ``Resources/config/``
129+
Web Resources (CSS, JS, images) ``Resources/public/``
130+
Translation files ``Resources/translations/``
131+
Templates ``Resources/views/``
132+
Unit and Functional Tests ``Tests/``
133+
=============================== =============================
134+
135+
[1] See :doc:`/cookbook/doctrine/mapping_model_classes` for how to handle the
136+
mapping with a compiler pass.
148137

149138
Classes
150139
-------
151140

152141
The bundle directory structure is used as the namespace hierarchy. For
153-
instance, a ``HelloController`` controller is stored in
154-
``Bundle/HelloBundle/Controller/HelloController.php`` and the fully qualified
155-
class name is ``Bundle\HelloBundle\Controller\HelloController``.
142+
instance, a ``ContentController`` controller is stored in
143+
``Acme/BlogBundle/Controller/ContentController.php`` and the fully qualified
144+
class name is ``Acme\BlogBundle\Controller\ContentController``.
156145

157146
All classes and files must follow the :doc:`Symfony coding standards </contributing/code/standards>`.
158147

@@ -162,7 +151,7 @@ Commands, Helpers, Listeners, and Controllers.
162151
Classes that connect to the event dispatcher should be suffixed with
163152
``Listener``.
164153

165-
Exception classes should be stored in an ``Exception`` sub-namespace.
154+
Exceptions classes should be stored in an ``Exception`` sub-namespace.
166155

167156
Vendors
168157
-------
@@ -177,7 +166,7 @@ Tests
177166
-----
178167

179168
A bundle should come with a test suite written with PHPUnit and stored under
180-
the ``Tests/`` directory. Tests should follow these principles:
169+
the ``Tests/`` directory. Tests should follow the following principles:
181170

182171
* The test suite must be executable with a simple ``phpunit`` command run from
183172
a sample application;
@@ -186,14 +175,13 @@ the ``Tests/`` directory. Tests should follow these principles:
186175
* The tests should cover at least 95% of the code base.
187176

188177
.. note::
189-
190178
A test suite must not contain ``AllTests.php`` scripts, but must rely on the
191179
existence of a ``phpunit.xml.dist`` file.
192180

193181
Documentation
194182
-------------
195183

196-
All classes and functions must be fully documented using `PHPDoc`_ tags.
184+
All classes and functions must come with full PHPDoc.
197185

198186
Extensive documentation should also be provided in the
199187
:doc:`reStructuredText </contributing/documentation/format>` format, under
@@ -317,8 +305,8 @@ Routing
317305
-------
318306

319307
If the bundle provides routes, they must be prefixed with the bundle alias.
320-
For an AcmeBlogBundle for instance, all routes must be prefixed with
321-
``acme_blog_``.
308+
For example, if your bundle is called AcmeBlogBundle, all its routes must be
309+
prefixed with ``acme_blog_``.
322310

323311
Templates
324312
---------
@@ -330,8 +318,7 @@ Translation Files
330318
-----------------
331319

332320
If a bundle provides message translations, they must be defined in the XLIFF
333-
format; the :ref:`translation domain <using-message-domains>` should be named
334-
after the bundle name (``bundle.hello``).
321+
format; the domain should be named after the bundle name (``acme_blog``).
335322

336323
A bundle must not override existing messages from another bundle.
337324

@@ -346,7 +333,7 @@ the Symfony configuration. Symfony parameters are simple key/value pairs; a
346333
value being any valid PHP value. Each parameter name should start with the
347334
bundle alias, though this is just a best-practice suggestion. The rest of the
348335
parameter name will use a period (``.``) to separate different parts (e.g.
349-
``acme_hello.email.from``).
336+
``acme_blog.author.email``).
350337

351338
The end user can provide values in any configuration file:
352339

@@ -356,31 +343,83 @@ The end user can provide values in any configuration file:
356343
357344
# app/config/config.yml
358345
parameters:
359-
acme_hello.email.from: [email protected]
346+
acme_blog.author.email: [email protected]
360347
361348
.. code-block:: xml
362349
363350
<!-- app/config/config.xml -->
364351
<parameters>
365-
<parameter key="acme_hello.email.from">[email protected]</parameter>
352+
<parameter key="acme_blog.author.email">[email protected]</parameter>
366353
</parameters>
367354
368355
.. code-block:: php
369356
370357
// app/config/config.php
371-
$container->setParameter('acme_hello.email.from', '[email protected]');
358+
$container->setParameter('acme_blog.author.email', '[email protected]');
372359
373360
Retrieve the configuration parameters in your code from the container::
374361

375-
$container->getParameter('acme_hello.email.from');
362+
$container->getParameter('acme_blog.author.email');
376363

377-
Even if this mechanism is simple enough, you are highly encouraged to use the
378-
:doc:`semantic bundle configuration </cookbook/bundles/extension>` instead.
364+
Even if this mechanism is simple enough, you should consider using the more
365+
advanced :doc:`semantic bundle configuration </cookbook/bundles/configuration>`.
379366

380-
.. note::
367+
Versioning
368+
----------
369+
370+
Bundles must be versioned following the `Semantic Versioning Standard`_.
371+
372+
Services
373+
--------
374+
375+
If the bundle defines services, they must be prefixed with the bundle alias.
376+
For example, AcmeBlogBundle services must be prefixed with ``acme_blog``.
377+
378+
In addition, services not meant to be used by the application directly, should
379+
be :ref:`defined as private <container-private-services>`.
380+
381+
.. seealso::
382+
383+
You can learn much more about service loading in bundles reading this article:
384+
:doc:`How to Load Service Configuration inside a Bundle </cookbook/bundles/extension>`.
385+
386+
Composer Metadata
387+
-----------------
388+
389+
The ``composer.json`` file should include at least the following metadata:
390+
391+
``name``
392+
Consists of the vendor and the short bundle name. If you are releasing the
393+
bundle on your own instead of on behalf of a company, use your personal name
394+
(e.g. ``johnsmith/blog-bundle``). The bundle short name excludes the vendor
395+
name and separates each word with an hyphen. For example: ``AcmeBlogBundle``
396+
is transformed into ``blog-bundle`` and ``AcmeSocialConnectBundle`` is
397+
transformed into ``social-connect-bundle``.
398+
399+
``description``
400+
A brief explanation of the purpose of the bundle.
401+
402+
``type``
403+
Use the ``symfony-bundle`` value.
404+
405+
``license``
406+
``MIT`` is the preferred license for Symfony bundles, but you can use any
407+
other license.
408+
409+
``autoload``
410+
This information is used by Symfony to load the classes of the bundle. The
411+
`PSR-4`_ autoload standard is recommended for modern bundles, but `PSR-0`_
412+
standard is also supported.
413+
414+
In order to make it easier for developers to find your bundle, register it on
415+
`Packagist`_, the official repository for Composer packages.
416+
417+
Learn more from the Cookbook
418+
----------------------------
381419

382-
If you are defining services, they should also be prefixed with the bundle
383-
alias.
420+
* :doc:`/cookbook/bundles/extension`
384421

385-
.. _`standards`: http://www.php-fig.org/psr/psr-0/
386-
.. _`PHPDoc`: https://en.wikipedia.org/wiki/PHPDoc
422+
.. _`PSR-0`: http://www.php-fig.org/psr/psr-0/
423+
.. _`PSR-4`: http://www.php-fig.org/psr/psr-4/
424+
.. _`Semantic Versioning Standard`: http://semver.org/
425+
.. _`Packagist`: https://packagist.org/

0 commit comments

Comments
 (0)