@@ -13,8 +13,12 @@ This article is all about how to structure your **reusable bundles** so that
1313they're easy to configure and extend. Many of these recommendations do not
1414apply to application bundles because you'll want to keep those as simple
1515as 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
2428Bundle 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
2933with a vendor segment, followed by zero or more category segments, and it ends
3034with 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
4246Here 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
5455By convention, the ``getName() `` method of the bundle class should return the
5556class name.
@@ -67,49 +68,47 @@ class name.
6768 :class: `Symfony\\ Bundle\\ FrameworkBundle\\ FrameworkBundle `.
6869
6970Each 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
7575Directory 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
114113The bundle directory is read-only. If you need to write temporary files, store
115114them 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
119118The 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
149138Classes
150139-------
151140
152141The 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
157146All classes and files must follow the :doc: `Symfony coding standards </contributing/code/standards >`.
158147
@@ -162,7 +151,7 @@ Commands, Helpers, Listeners, and Controllers.
162151Classes 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
167156Vendors
168157-------
@@ -177,7 +166,7 @@ Tests
177166-----
178167
179168A 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
193181Documentation
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
198186Extensive documentation should also be provided in the
199187:doc: `reStructuredText </contributing/documentation/format >` format, under
@@ -317,8 +305,8 @@ Routing
317305-------
318306
319307If 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
323311Templates
324312---------
@@ -330,8 +318,7 @@ Translation Files
330318-----------------
331319
332320If 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
336323A 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
346333value being any valid PHP value. Each parameter name should start with the
347334bundle alias, though this is just a best-practice suggestion. The rest of the
348335parameter name will use a period (``. ``) to separate different parts (e.g.
349- ``acme_hello.email.from ``).
336+ ``acme_blog.author.email ``).
350337
351338The 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 : fabien@example.com
346+ acme_blog.author.email : fabien@example.com
360347
361348 .. code-block :: xml
362349
363350 <!-- app/config/config.xml -->
364351 <parameters >
365- <parameter key =" acme_hello.email.from " >fabien@example.com</parameter >
352+ <parameter key =" acme_blog.author.email " >fabien@example.com</parameter >
366353 </parameters >
367354
368355 .. code-block :: php
369356
370357 // app/config/config.php
371- $container->setParameter('acme_hello.email.from ', 'fabien@example.com');
358+ $container->setParameter('acme_blog.author.email ', 'fabien@example.com');
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