From a3915632424d5f932a9c6ef54cc35d05ed930e88 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 19 Feb 2015 10:25:31 +0100 Subject: [PATCH 1/6] Updated the best practices article for reusable bundles --- cookbook/bundles/best_practices.rst | 343 +++++++++++++--------------- 1 file changed, 160 insertions(+), 183 deletions(-) diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 4a9468b11cd..7f410200831 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -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 `, the :doc:`cookbook ` and the -:doc:`best practices ` 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 `, the :doc:`cookbook ` 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; + / + ├─ 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 + 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. -.. 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 `. @@ -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 ` format, under @@ -206,108 +194,55 @@ Installation Instructions In order to ease the installation of third-party bundles, consider using the following standardized instructions in your ``README.md`` file. -.. configuration-block:: - - .. code-block:: markdown +.. code-block:: text - Installation - ============ + Installation + ============ - Step 1: Download the Bundle - --------------------------- + Step 1: Download the Bundle + --------------------------- - Open a command console, enter your project directory and execute the - following command to download the latest stable version of this bundle: + Open a command console, enter your project directory and execute the + following command to download the latest stable version of this bundle: - ```bash - $ composer require "~1" - ``` + ```bash + $ composer require "~1" + ``` - This command requires you to have Composer installed globally, as explained - in the [installation chapter](https://getcomposer.org/doc/00-intro.md) - of the Composer documentation. + This command requires you to have Composer installed globally, as explained + in the [installation chapter](https://getcomposer.org/doc/00-intro.md) + of the Composer documentation. - Step 2: Enable the Bundle - ------------------------- + Step 2: Enable the Bundle + ------------------------- - Then, enable the bundle by adding it to the list of registered bundles - in the `app/AppKernel.php` file of your project: + Then, enable the bundle by adding the following in the `app/AppKernel.php` + file of your project: - ```php - \\(), - ); - + $bundles = array( // ... - } - - // ... - } - ``` - - .. code-block:: rst - - Installation - ============ - - Step 1: Download the Bundle - --------------------------- - Open a command console, enter your project directory and execute the - following command to download the latest stable version of this bundle: - - .. code-block:: bash - - $ composer require "~1" - - This command requires you to have Composer installed globally, as explained - in the `installation chapter`_ of the Composer documentation. - - Step 2: Enable the Bundle - ------------------------- - - Then, enable the bundle by adding it to the list of registered bundles - in the ``app/AppKernel.php`` file of your project: - - .. code-block:: php - - \\(), + ); // ... - class AppKernel extends Kernel - { - public function registerBundles() - { - $bundles = array( - // ... - - new \\(), - ); - - // ... - } - - // ... - } + } - .. _`installation chapter`: https://getcomposer.org/doc/00-intro.md + // ... + } + ``` -The example above assumes that you are installing the latest stable version of -the bundle, where you don't have to provide the package version number -(e.g. ``composer require friendsofsymfony/user-bundle``). If the installation -instructions refer to some past bundle version or to some unstable version, -include the version constraint (e.g. ``composer require friendsofsymfony/user-bundle "~2.0@dev"``). +This template assumes that your bundle is in its ``1.x`` version. If not, change +the ``"~1"`` installation version accordingly (``"~2"``, ``"~3"``, etc.) Optionally, you can add more installation steps (*Step 3*, *Step 4*, etc.) to explain other required installation tasks, such as registering routes or @@ -317,8 +252,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 +265,7 @@ Translation Files ----------------- If a bundle provides message translations, they must be defined in the XLIFF -format; the :ref:`translation domain ` 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 +280,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 +290,74 @@ The end user can provide values in any configuration file: # app/config/config.yml parameters: - acme_hello.email.from: fabien@example.com + acme_blog.author.email: fabien@example.com .. code-block:: xml - fabien@example.com + fabien@example.com .. code-block:: php // app/config/config.php - $container->setParameter('acme_hello.email.from', 'fabien@example.com'); + $container->setParameter('acme_blog.author.email', 'fabien@example.com'); 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 ` instead. +Even if this mechanism is simple enough, you should consider using the more +advanced :doc:`semantic bundle configuration `. -.. note:: +Versioning +---------- + +Bundles must be versioned following the `Semantic Versioning Standard`_. + +Services +-------- - If you are defining services, they should also be prefixed with the bundle - alias. +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 `. + +.. seealso:: + + You can learn much more about service loading in bundles reading this article: + :doc:`How to Load Service Configuration inside a Bundle `. + +Composer Metadata +----------------- -.. _`standards`: http://www.php-fig.org/psr/psr-0/ -.. _`PHPDoc`: https://en.wikipedia.org/wiki/PHPDoc +The ``composer.json`` file should include at least the following metadata: + +* ``name``, which includes 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``, 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 value. +* ``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 +---------------------------- + +* :doc:`/cookbook/bundles/extension` + +.. _`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/ From 9981193333c3f257f6affb03923d5f40397abece Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 19 Feb 2015 17:50:32 +0100 Subject: [PATCH 2/6] Minor fixes and added a cross link --- components/dependency_injection/advanced.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/dependency_injection/advanced.rst b/components/dependency_injection/advanced.rst index 0ea6b296a67..5e9b09d5ae0 100644 --- a/components/dependency_injection/advanced.rst +++ b/components/dependency_injection/advanced.rst @@ -4,6 +4,8 @@ Advanced Container Configuration ================================ +.. _container-private-services: + Marking Services as public / private ------------------------------------ From fa0b9029fa3d5a2f6cd2707fb83a307112a57750 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 24 Jun 2015 09:00:57 +0200 Subject: [PATCH 3/6] Fixed a minor syntax issue --- cookbook/bundles/best_practices.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 7f410200831..88f9f25653d 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -346,8 +346,8 @@ The ``composer.json`` file should include at least the following metadata: * ``license``, ``MIT`` is the preferred license for Symfony bundles, but you can use any other value. * ``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. + 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. From 4276ced28474d7b56dfc169d51fbf93dfbdea873 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 24 Jun 2015 09:03:37 +0200 Subject: [PATCH 4/6] Added back some information wrongly removed during the rebase --- cookbook/bundles/best_practices.rst | 119 ++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 33 deletions(-) diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 88f9f25653d..81e3d688948 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -194,55 +194,108 @@ Installation Instructions In order to ease the installation of third-party bundles, consider using the following standardized instructions in your ``README.md`` file. -.. code-block:: text +.. configuration-block:: - Installation - ============ + .. code-block:: markdown - Step 1: Download the Bundle - --------------------------- + Installation + ============ - Open a command console, enter your project directory and execute the - following command to download the latest stable version of this bundle: + Step 1: Download the Bundle + --------------------------- - ```bash - $ composer require "~1" - ``` + Open a command console, enter your project directory and execute the + following command to download the latest stable version of this bundle: - This command requires you to have Composer installed globally, as explained - in the [installation chapter](https://getcomposer.org/doc/00-intro.md) - of the Composer documentation. + ```bash + $ composer require "~1" + ``` - Step 2: Enable the Bundle - ------------------------- + This command requires you to have Composer installed globally, as explained + in the [installation chapter](https://getcomposer.org/doc/00-intro.md) + of the Composer documentation. - Then, enable the bundle by adding the following in the `app/AppKernel.php` - file of your project: + Step 2: Enable the Bundle + ------------------------- - ```php - \\(), + ); - new \\(), - ); + // ... + } // ... } + ``` - // ... - } - ``` + .. code-block:: rst + + Installation + ============ + + Step 1: Download the Bundle + --------------------------- + + Open a command console, enter your project directory and execute the + following command to download the latest stable version of this bundle: + + .. code-block:: bash + + $ composer require "~1" + + This command requires you to have Composer installed globally, as explained + in the `installation chapter`_ of the Composer documentation. + + Step 2: Enable the Bundle + ------------------------- + + Then, enable the bundle by adding it to the list of registered bundles + in the ``app/AppKernel.php`` file of your project: + + .. code-block:: php + + \\(), + ); + + // ... + } + + // ... + } + + .. _`installation chapter`: https://getcomposer.org/doc/00-intro.md -This template assumes that your bundle is in its ``1.x`` version. If not, change -the ``"~1"`` installation version accordingly (``"~2"``, ``"~3"``, etc.) +The example above assumes that you are installing the latest stable version of +the bundle, where you don't have to provide the package version number +(e.g. ``composer require friendsofsymfony/user-bundle``). If the installation +instructions refer to some past bundle version or to some unstable version, +include the version constraint (e.g. ``composer require friendsofsymfony/user-bundle "~2.0@dev"``). Optionally, you can add more installation steps (*Step 3*, *Step 4*, etc.) to explain other required installation tasks, such as registering routes or From 776eaee16020a4a4c5879091423291c2f8602d5a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 24 Jun 2015 16:21:59 +0200 Subject: [PATCH 5/6] Reworded as a definition list --- cookbook/bundles/best_practices.rst | 31 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 81e3d688948..2600df7d237 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -388,19 +388,24 @@ Composer Metadata The ``composer.json`` file should include at least the following metadata: -* ``name``, which includes 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``, 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 value. -* ``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. +``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`` + 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. From 286631ddc3ba44059c44ac2ce23d123a9ac6d7b5 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 24 Jun 2015 16:51:05 +0200 Subject: [PATCH 6/6] Added a blank line beteen definition list items --- cookbook/bundles/best_practices.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cookbook/bundles/best_practices.rst b/cookbook/bundles/best_practices.rst index 2600df7d237..d273fe7ccf0 100644 --- a/cookbook/bundles/best_practices.rst +++ b/cookbook/bundles/best_practices.rst @@ -395,13 +395,17 @@ The ``composer.json`` file should include at least the following metadata: 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`` 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`_