-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Updated the best practices article for reusable bundles #5014
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
Changes from all commits
a391563
9981193
fa0b902
4276ced
776eaee
286631d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,8 +13,12 @@ This article is all about how to structure your **reusable bundles** so that | |
they're easy to configure and extend. Many of these recommendations do not | ||
apply to application bundles because you'll want to keep those as simple | ||
as possible. For application bundles, just follow the practices shown throughout | ||
the :doc:`book </book/index>`, the :doc:`cookbook </cookbook/index>` and the | ||
:doc:`best practices </best_practices/index>` book. | ||
the book and cookbook. | ||
|
||
.. seealso:: | ||
|
||
The best practices for application-specific bundles are discussed in | ||
:doc:`/best_practices/introduction`. | ||
|
||
.. index:: | ||
pair: Bundle; Naming conventions | ||
|
@@ -24,8 +28,8 @@ the :doc:`book </book/index>`, the :doc:`cookbook </cookbook/index>` and the | |
Bundle Name | ||
----------- | ||
|
||
A bundle is also a PHP namespace. The namespace must follow the technical | ||
interoperability `standards`_ for PHP namespaces and class names: it starts | ||
A bundle is also a PHP namespace. The namespace must follow the `PSR-0`_ or | ||
`PSR-4`_ interoperability standards for PHP namespaces and class names: it starts | ||
with a vendor segment, followed by zero or more category segments, and it ends | ||
with the namespace short name, which must end with a ``Bundle`` suffix. | ||
|
||
|
@@ -41,15 +45,12 @@ bundle class name must follow these simple rules: | |
|
||
Here are some valid bundle namespaces and class names: | ||
|
||
+-----------------------------------+--------------------------+ | ||
| Namespace | Bundle Class Name | | ||
+===================================+==========================+ | ||
| ``Acme\Bundle\BlogBundle`` | ``AcmeBlogBundle`` | | ||
+-----------------------------------+--------------------------+ | ||
| ``Acme\Bundle\Social\BlogBundle`` | ``AcmeSocialBlogBundle`` | | ||
+-----------------------------------+--------------------------+ | ||
| ``Acme\BlogBundle`` | ``AcmeBlogBundle`` | | ||
+-----------------------------------+--------------------------+ | ||
========================== ================== | ||
Namespace Bundle Class Name | ||
========================== ================== | ||
``Acme\Bundle\BlogBundle`` ``AcmeBlogBundle`` | ||
``Acme\BlogBundle`` ``AcmeBlogBundle`` | ||
========================== ================== | ||
|
||
By convention, the ``getName()`` method of the bundle class should return the | ||
class name. | ||
|
@@ -67,49 +68,47 @@ class name. | |
:class:`Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle`. | ||
|
||
Each bundle has an alias, which is the lower-cased short version of the bundle | ||
name using underscores (``acme_hello`` for ``AcmeHelloBundle``, or | ||
``acme_social_blog`` for ``Acme\Social\BlogBundle`` for instance). This alias | ||
is used to enforce uniqueness within a bundle (see below for some usage | ||
examples). | ||
name using underscores (``acme_blog`` for ``AcmeBlogBundle``). This alias | ||
is used to enforce uniqueness within a project and for defining bundle's | ||
configuration options (see below for some usage examples). | ||
|
||
Directory Structure | ||
------------------- | ||
|
||
The basic directory structure of a HelloBundle must read as follows: | ||
The basic directory structure of an AcmeBlogBundle must read as follows: | ||
|
||
.. code-block:: text | ||
|
||
XXX/... | ||
HelloBundle/ | ||
HelloBundle.php | ||
Controller/ | ||
Resources/ | ||
meta/ | ||
LICENSE | ||
config/ | ||
doc/ | ||
index.rst | ||
translations/ | ||
views/ | ||
public/ | ||
Tests/ | ||
|
||
The ``XXX`` directory(ies) reflects the namespace structure of the bundle. | ||
|
||
The following files are mandatory: | ||
|
||
* ``HelloBundle.php``; | ||
* ``Resources/meta/LICENSE``: The full license for the code; | ||
<your-bundle>/ | ||
├─ AcmeBlogBundle.php | ||
├─ Controller/ | ||
├─ README.md | ||
├─ Resources/ | ||
│ ├─ meta/ | ||
│ │ └─ LICENSE | ||
│ ├─ config/ | ||
│ ├─ doc/ | ||
│ │ └─ index.rst | ||
│ ├─ translations/ | ||
│ ├─ views/ | ||
│ └─ public/ | ||
└─ Tests/ | ||
|
||
**The following files are mandatory**, because they ensure a structure convention | ||
that automated tools can rely on: | ||
|
||
* ``AcmeBlogBundle.php``: This is the class that transforms a plain directory | ||
into a Symfony bundle; | ||
* ``README.md``: This file contains the basic description of the bundle and it | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should allow to use other formats supported by Github for the readme (or whatever project hosting you use). |
||
usually shows some basic examples and links to its full documentation (it | ||
can use any of the markup formats supported by GitHub, such as ``README.rst``); | ||
* ``Resources/meta/LICENSE``: The full license for the code. The license file | ||
can also be stored in the bundle's root directory to follow the generic | ||
conventions about packages; | ||
* ``Resources/doc/index.rst``: The root file for the Bundle documentation. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also add a README file (no shared project should be allowed to omit the readme) |
||
|
||
.. note:: | ||
|
||
These conventions ensure that automated tools can rely on this default | ||
structure to work. | ||
|
||
The depth of sub-directories should be kept to the minimal for most used | ||
classes and files (two levels at a maximum). More levels can be defined for | ||
non-strategic, less-used files. | ||
The depth of sub-directories should be kept to the minimum for most used | ||
classes and files (two levels maximum). | ||
|
||
The bundle directory is read-only. If you need to write temporary files, store | ||
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. | |
|
||
The following classes and files have specific emplacements: | ||
|
||
+------------------------------+-----------------------------+ | ||
| Type | Directory | | ||
+==============================+=============================+ | ||
| Commands | ``Command/`` | | ||
+------------------------------+-----------------------------+ | ||
| Controllers | ``Controller/`` | | ||
+------------------------------+-----------------------------+ | ||
| Service Container Extensions | ``DependencyInjection/`` | | ||
+------------------------------+-----------------------------+ | ||
| Event Listeners | ``EventListener/`` | | ||
+------------------------------+-----------------------------+ | ||
| Configuration | ``Resources/config/`` | | ||
+------------------------------+-----------------------------+ | ||
| Web Resources | ``Resources/public/`` | | ||
+------------------------------+-----------------------------+ | ||
| Translation files | ``Resources/translations/`` | | ||
+------------------------------+-----------------------------+ | ||
| Templates | ``Resources/views/`` | | ||
+------------------------------+-----------------------------+ | ||
| Unit and Functional Tests | ``Tests/`` | | ||
+------------------------------+-----------------------------+ | ||
|
||
.. note:: | ||
|
||
When building a reusable bundle, model classes should be placed in the | ||
``Model`` namespace. See :doc:`/cookbook/doctrine/mapping_model_classes` for | ||
how to handle the mapping with a compiler pass. | ||
=============================== ============================= | ||
Type Directory | ||
=============================== ============================= | ||
Commands ``Command/`` | ||
Controllers ``Controller/`` | ||
Service Container Extensions ``DependencyInjection/`` | ||
Event Listeners ``EventListener/`` | ||
Model classes [1] ``Model/`` | ||
Configuration ``Resources/config/`` | ||
Web Resources (CSS, JS, images) ``Resources/public/`` | ||
Translation files ``Resources/translations/`` | ||
Templates ``Resources/views/`` | ||
Unit and Functional Tests ``Tests/`` | ||
=============================== ============================= | ||
|
||
[1] See :doc:`/cookbook/doctrine/mapping_model_classes` for how to handle the | ||
mapping with a compiler pass. | ||
|
||
Classes | ||
------- | ||
|
||
The bundle directory structure is used as the namespace hierarchy. For | ||
instance, a ``HelloController`` controller is stored in | ||
``Bundle/HelloBundle/Controller/HelloController.php`` and the fully qualified | ||
class name is ``Bundle\HelloBundle\Controller\HelloController``. | ||
instance, a ``ContentController`` controller is stored in | ||
``Acme/BlogBundle/Controller/ContentController.php`` and the fully qualified | ||
class name is ``Acme\BlogBundle\Controller\ContentController``. | ||
|
||
All classes and files must follow the :doc:`Symfony coding standards </contributing/code/standards>`. | ||
|
||
|
@@ -162,7 +151,7 @@ Commands, Helpers, Listeners, and Controllers. | |
Classes that connect to the event dispatcher should be suffixed with | ||
``Listener``. | ||
|
||
Exception classes should be stored in an ``Exception`` sub-namespace. | ||
Exceptions classes should be stored in an ``Exception`` sub-namespace. | ||
|
||
Vendors | ||
------- | ||
|
@@ -177,7 +166,7 @@ Tests | |
----- | ||
|
||
A bundle should come with a test suite written with PHPUnit and stored under | ||
the ``Tests/`` directory. Tests should follow these principles: | ||
the ``Tests/`` directory. Tests should follow the following principles: | ||
|
||
* The test suite must be executable with a simple ``phpunit`` command run from | ||
a sample application; | ||
|
@@ -186,14 +175,13 @@ the ``Tests/`` directory. Tests should follow these principles: | |
* The tests should cover at least 95% of the code base. | ||
|
||
.. note:: | ||
|
||
A test suite must not contain ``AllTests.php`` scripts, but must rely on the | ||
existence of a ``phpunit.xml.dist`` file. | ||
|
||
Documentation | ||
------------- | ||
|
||
All classes and functions must be fully documented using `PHPDoc`_ tags. | ||
All classes and functions must come with full PHPDoc. | ||
|
||
Extensive documentation should also be provided in the | ||
:doc:`reStructuredText </contributing/documentation/format>` format, under | ||
|
@@ -317,8 +305,8 @@ Routing | |
------- | ||
|
||
If the bundle provides routes, they must be prefixed with the bundle alias. | ||
For an AcmeBlogBundle for instance, all routes must be prefixed with | ||
``acme_blog_``. | ||
For example, if your bundle is called AcmeBlogBundle, all its routes must be | ||
prefixed with ``acme_blog_``. | ||
|
||
Templates | ||
--------- | ||
|
@@ -330,8 +318,7 @@ Translation Files | |
----------------- | ||
|
||
If a bundle provides message translations, they must be defined in the XLIFF | ||
format; the :ref:`translation domain <using-message-domains>` should be named | ||
after the bundle name (``bundle.hello``). | ||
format; the domain should be named after the bundle name (``acme_blog``). | ||
|
||
A bundle must not override existing messages from another bundle. | ||
|
||
|
@@ -346,7 +333,7 @@ the Symfony configuration. Symfony parameters are simple key/value pairs; a | |
value being any valid PHP value. Each parameter name should start with the | ||
bundle alias, though this is just a best-practice suggestion. The rest of the | ||
parameter name will use a period (``.``) to separate different parts (e.g. | ||
``acme_hello.email.from``). | ||
``acme_blog.author.email``). | ||
|
||
The end user can provide values in any configuration file: | ||
|
||
|
@@ -356,31 +343,83 @@ The end user can provide values in any configuration file: | |
|
||
# app/config/config.yml | ||
parameters: | ||
acme_hello.email.from: [email protected] | ||
acme_blog.author.email: [email protected] | ||
|
||
.. code-block:: xml | ||
|
||
<!-- app/config/config.xml --> | ||
<parameters> | ||
<parameter key="acme_hello.email.from">[email protected]</parameter> | ||
<parameter key="acme_blog.author.email">[email protected]</parameter> | ||
</parameters> | ||
|
||
.. code-block:: php | ||
|
||
// app/config/config.php | ||
$container->setParameter('acme_hello.email.from', '[email protected]'); | ||
$container->setParameter('acme_blog.author.email', '[email protected]'); | ||
|
||
Retrieve the configuration parameters in your code from the container:: | ||
|
||
$container->getParameter('acme_hello.email.from'); | ||
$container->getParameter('acme_blog.author.email'); | ||
|
||
Even if this mechanism is simple enough, you are highly encouraged to use the | ||
:doc:`semantic bundle configuration </cookbook/bundles/extension>` instead. | ||
Even if this mechanism is simple enough, you should consider using the more | ||
advanced :doc:`semantic bundle configuration </cookbook/bundles/configuration>`. | ||
|
||
.. note:: | ||
Versioning | ||
---------- | ||
|
||
Bundles must be versioned following the `Semantic Versioning Standard`_. | ||
|
||
Services | ||
-------- | ||
|
||
If the bundle defines services, they must be prefixed with the bundle alias. | ||
For example, AcmeBlogBundle services must be prefixed with ``acme_blog``. | ||
|
||
In addition, services not meant to be used by the application directly, should | ||
be :ref:`defined as private <container-private-services>`. | ||
|
||
.. seealso:: | ||
|
||
You can learn much more about service loading in bundles reading this article: | ||
:doc:`How to Load Service Configuration inside a Bundle </cookbook/bundles/extension>`. | ||
|
||
Composer Metadata | ||
----------------- | ||
|
||
The ``composer.json`` file should include at least the following metadata: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also add the |
||
|
||
``name`` | ||
Consists of the vendor and the short bundle name. If you are releasing the | ||
bundle on your own instead of on behalf of a company, use your personal name | ||
(e.g. ``johnsmith/blog-bundle``). The bundle short name excludes the vendor | ||
name and separates each word with an hyphen. For example: ``AcmeBlogBundle`` | ||
is transformed into ``blog-bundle`` and ``AcmeSocialConnectBundle`` is | ||
transformed into ``social-connect-bundle``. | ||
|
||
``description`` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will it render properly without a blank line between the entries? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know ... so I've added a blank line as suggested. Thanks. |
||
A brief explanation of the purpose of the bundle. | ||
|
||
``type`` | ||
Use the ``symfony-bundle`` value. | ||
|
||
``license`` | ||
``MIT`` is the preferred license for Symfony bundles, but you can use any | ||
other license. | ||
|
||
``autoload`` | ||
This information is used by Symfony to load the classes of the bundle. The | ||
`PSR-4`_ autoload standard is recommended for modern bundles, but `PSR-0`_ | ||
standard is also supported. | ||
|
||
In order to make it easier for developers to find your bundle, register it on | ||
`Packagist`_, the official repository for Composer packages. | ||
|
||
Learn more from the Cookbook | ||
---------------------------- | ||
|
||
If you are defining services, they should also be prefixed with the bundle | ||
alias. | ||
* :doc:`/cookbook/bundles/extension` | ||
|
||
.. _`standards`: http://www.php-fig.org/psr/psr-0/ | ||
.. _`PHPDoc`: https://en.wikipedia.org/wiki/PHPDoc | ||
.. _`PSR-0`: http://www.php-fig.org/psr/psr-0/ | ||
.. _`PSR-4`: http://www.php-fig.org/psr/psr-4/ | ||
.. _`Semantic Versioning Standard`: http://semver.org/ | ||
.. _`Packagist`: https://packagist.org/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bundle has a namespace?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, bundle is in fact just a namespace or a name to refer to a location on the filesystem