From 2d5055077dce4f2c5c282d3daaf0baf3389f4f95 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 18 May 2017 09:36:41 +0200 Subject: [PATCH 0001/2437] minor #7914 Fix a typo (GuilhemN) This PR was merged into the master branch. Discussion ---------- Fix a typo Commits ------- f5e9e6b typo --- _exts | 1 + 1 file changed, 1 insertion(+) create mode 160000 _exts diff --git a/_exts b/_exts new file mode 160000 index 00000000000..52f7bd2216c --- /dev/null +++ b/_exts @@ -0,0 +1 @@ +Subproject commit 52f7bd2216cc22ef52494f346c5643bb2a74513f From 4283d7a210b9b91bcc53879f95595aac1b05f81c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 18 May 2017 10:08:46 +0200 Subject: [PATCH 0002/2437] Revert "minor #7914 Fix a typo (GuilhemN)" This reverts commit 2d5055077dce4f2c5c282d3daaf0baf3389f4f95. --- _exts | 1 - 1 file changed, 1 deletion(-) delete mode 160000 _exts diff --git a/_exts b/_exts deleted file mode 160000 index 52f7bd2216c..00000000000 --- a/_exts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 52f7bd2216cc22ef52494f346c5643bb2a74513f From bd5d036313917df4e5062a69072a76bdcc5b089c Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Mon, 12 Jun 2017 21:59:29 +0200 Subject: [PATCH 0003/2437] Update example comment to remove unnecessary text --- frontend/encore/simple-example.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/encore/simple-example.rst b/frontend/encore/simple-example.rst index 65ee0891107..137b6b34b31 100644 --- a/frontend/encore/simple-example.rst +++ b/frontend/encore/simple-example.rst @@ -22,7 +22,7 @@ Inside, use Encore to help generate your Webpack configuration. var Encore = require('@symfony/webpack-encore'); Encore - // directory where should all compiled assets will be stored + // directory where all compiled assets will be stored .setOutputPath('web/build/') // what's the public path to this directory (relative to your project's document root dir) From 49e24b9fea97c8ac105915c34efdcb34a9d75b63 Mon Sep 17 00:00:00 2001 From: Fabien Bourigault Date: Wed, 14 Jun 2017 15:25:56 +0200 Subject: [PATCH 0004/2437] remove debugging class cache and bootstrap section --- debug/debugging.rst | 47 --------------------------------------------- 1 file changed, 47 deletions(-) diff --git a/debug/debugging.rst b/debug/debugging.rst index 2bb3a585830..a633ef7872c 100644 --- a/debug/debugging.rst +++ b/debug/debugging.rst @@ -14,53 +14,6 @@ configuration is optimized for two main purposes: * Be as similar as possible as the production environment to avoid problems when deploying the project. -Disabling the Bootstrap File and Class Caching ----------------------------------------------- - -And to make the production environment as fast as possible, Symfony creates -big PHP files in your cache containing the aggregation of PHP classes your -project needs for every request. However, this behavior can confuse your debugger, -because the same class can be located in two different places: the original class -file and the big file which aggregates lots of classes. - -This recipe shows you how you can tweak this caching mechanism to make it friendlier -when you need to debug code that involves Symfony classes. - -The ``app_dev.php`` front controller reads as follows by default:: - - // ... - - $loader = require __DIR__.'/../app/autoload.php'; - Debug::enable(); - - $kernel = new AppKernel('dev', true); - $kernel->loadClassCache(); - $request = Request::createFromGlobals(); - // ... - -To make your debugger happier, disable the loading of all PHP class caches -by removing the call to ``loadClassCache()``:: - - // ... - - $loader = require_once __DIR__.'/../app/autoload.php'; - Debug::enable(); - - $kernel = new AppKernel('dev', true); - // $kernel->loadClassCache(); - $request = Request::createFromGlobals(); - -.. tip:: - - If you disable the PHP caches, don't forget to revert after your debugging - session. - -Some IDEs do not like the fact that some classes are stored in different -locations. To avoid problems, you can either tell your IDE to ignore the PHP -cache files, or you can change the extension used by Symfony for these files:: - - $kernel->loadClassCache('classes', '.php.cache'); - Useful Debugging Commands ------------------------- From 4b2113349c9f67e7569f684edcb6c991249684a6 Mon Sep 17 00:00:00 2001 From: Jose Gonzalez Date: Sat, 24 Jun 2017 12:50:00 +0100 Subject: [PATCH 0005/2437] [Stopwatch] Document the reset method --- components/stopwatch.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/stopwatch.rst b/components/stopwatch.rst index d2791f5bbb5..3d1d02c68c9 100644 --- a/components/stopwatch.rst +++ b/components/stopwatch.rst @@ -41,6 +41,10 @@ from the :method:`Symfony\\Component\\Stopwatch\\Stopwatch::start`, The latter should be used when you need to retrieve the duration of an event while it is still running. +The stopwatch can be reset to its original state at any given time with the +:method:`Symfony\\Component\\Stopwatch\\Stopwatch::reset` method, which deletes +all the data measured so far. + You can also provide a category name to an event:: $stopwatch->start('eventName', 'categoryName'); From 2565b476ab2a68d65e170f8aa0bcd47f531dfbaa Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sun, 9 Jul 2017 11:22:39 +0200 Subject: [PATCH 0006/2437] Updated the installation instructions for Symfony 4 --- setup.rst | 295 +++++++++++++++++------------------------------------- 1 file changed, 92 insertions(+), 203 deletions(-) diff --git a/setup.rst b/setup.rst index 51c20a9a0c8..47025d249a5 100644 --- a/setup.rst +++ b/setup.rst @@ -4,121 +4,48 @@ Installing & Setting up the Symfony Framework ============================================= -This article explains how to install Symfony in different ways and how to solve -the most common issues that may appear during the installation process. +This article explains how to install Symfony and solve the most common issues +that may appear during the installation process. .. seealso:: Do you prefer video tutorials? Check out the `Joyful Development with Symfony`_ screencast series from KnpUniversity. +.. _installation-creating-the-app: + Creating Symfony Applications ----------------------------- -Symfony provides a dedicated application called the **Symfony Installer** to ease -the creation of Symfony applications. This installer is a PHP 5.4 compatible -executable that needs to be installed on your system only once: - -.. code-block:: terminal - - # Linux and macOS systems - $ sudo mkdir -p /usr/local/bin - $ sudo curl -LsS https://symfony.com/installer -o /usr/local/bin/symfony - $ sudo chmod a+x /usr/local/bin/symfony - - # Windows systems - c:\> php -r "file_put_contents('symfony', file_get_contents('https://symfony.com/installer'));" - -.. note:: - - In Linux and macOS, a global ``symfony`` command is created. In Windows, - move the ``symfony`` file to a directory that's included in the ``PATH`` - environment variable and create a ``symfony.bat`` file to create the global - command or move it to any other directory convenient for you: - - .. code-block:: terminal - - # for example, if WAMP is used ... - c:\> move symfony c:\wamp\bin\php - # create symfony.bat in the same folder - c:\> cd c:\wamp\bin\php - c:\> (echo @ECHO OFF & echo php "%~dp0symfony" %*) > symfony.bat - # ... then, execute the command as: - c:\> symfony - - # moving it to your projects folder ... - c:\> move symfony c:\projects - # ... then, execute the command as - c:\> cd projects - c:\projects\> php symfony - -.. _installation-creating-the-app: - -Once the Symfony Installer is installed, create your first Symfony application -with the ``new`` command: +Symfony applications are created with `Composer`_, the package manager used by +modern PHP applications. If you don't have Composer installed in your computer, +start by :doc:`installing Composer globally `. Then, execute +this command to create a new empty Symfony application based on its latest +stable version: .. code-block:: terminal - $ symfony new my_project_name - -This command creates a new directory called ``my_project_name/`` that contains -an empty project based on the most recent stable Symfony version available. In -addition, the installer checks if your system meets the technical requirements -to execute Symfony applications. If not, you'll see the list of changes needed -to meet those requirements. - -.. note:: - - If the installer doesn't work for you or doesn't output anything, make sure - that the PHP `Phar extension`_ is installed and enabled on your computer. - -.. note:: - - If the SSL certificates are not properly installed in your system, you - may get this error: + $ composer create-project symfony/skeleton my-project - cURL error 60: SSL certificate problem: unable to get local issuer certificate. - - You can solve this issue as follows: - - #. Download a file with the updated list of certificates from - https://curl.haxx.se/ca/cacert.pem - #. Move the downloaded ``cacert.pem`` file to some safe location in your system - #. Update your ``php.ini`` file and configure the path to that file: - - .. code-block:: ini - - ; Linux and macOS systems - curl.cainfo = "/path/to/cacert.pem" - - ; Windows systems - curl.cainfo = "C:\path\to\cacert.pem" +.. tip:: -Basing your Project on a Specific Symfony Version -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + If your Internet connection is slow, you may think that Composer is not + doing anything. If that's your case, add the ``-vvv`` flag to the previous + command to display a detailed output of everything that Composer is doing. -In case your project needs to be based on a specific Symfony version, use the -optional second argument of the ``new`` command: +If your project needs to be based on a specific Symfony version, use the +optional third argument of the ``create-project`` command: .. code-block:: terminal # use the most recent version in any Symfony branch - $ symfony new my_project_name 2.8 - $ symfony new my_project_name 3.1 + $ composer create-project symfony/skeleton my-project "3.3.*" # use a specific Symfony version - $ symfony new my_project_name 2.8.3 - $ symfony new my_project_name 3.1.5 + $ composer create-project symfony/skeleton my-project "3.3.5" # use a beta or RC version (useful for testing new Symfony versions) - $ symfony new my_project 2.7.0-BETA1 - $ symfony new my_project 2.7.0-RC1 - - # use the most recent 'lts' version (Long Term Support version) - $ symfony new my_project_name lts - -Each version has its *own* documentation, which you can select on any documentation -page. + $ composer create-project symfony/skeleton my-project 3.3.0-BETA1 .. note:: @@ -126,61 +53,27 @@ page. to better understand why there are several Symfony versions and which one to use for your projects. -Creating Symfony Applications with Composer -------------------------------------------- - -If you still use PHP 5.3 or can't use the Symfony installer for any reason, you -can create Symfony applications with `Composer`_, the dependency manager used by -modern PHP applications. - -If you don't have Composer installed in your computer, start by -:doc:`installing Composer globally `. Then, execute the -``create-project`` command to create a new Symfony application based on its -latest stable version: - -.. code-block:: terminal - - $ composer create-project symfony/framework-standard-edition my_project_name - -You can also install any other Symfony version by passing a second argument to -the ``create-project`` command: - -.. code-block:: terminal - - $ composer create-project symfony/framework-standard-edition my_project_name "2.8.*" - -.. tip:: - - If your Internet connection is slow, you may think that Composer is not - doing anything. If that's your case, add the ``-vvv`` flag to the previous - command to display a detailed output of everything that Composer is doing. - Running the Symfony Application ------------------------------- -Symfony leverages the internal PHP web server (available since PHP 5.4) to run -applications while developing them. Therefore, running a Symfony application is -a matter of browsing to the project directory and executing this command: +Symfony provides a utility called ``server`` that leverages the internal PHP web +server to run applications while developing them. First, install that utility +in your application: .. code-block:: terminal - $ cd my_project_name/ - $ php bin/console server:run + $ cd my-project/ + $ composer require server -Then, open your browser and access the ``http://localhost:8000/`` URL to see the -Welcome Page of Symfony: +Then, whenever you want to run the application, execute this command: -.. image:: /_images/quick_tour/welcome.png - :align: center - :alt: Symfony Welcome Page - :class: with-browser +.. code-block:: terminal -If you see a blank page or an error page instead of the Welcome Page, there is -a directory permission misconfiguration. The solution to this problem is -explained in the :doc:`/setup/file_permissions`. + $ php bin/console server:run -When you are finished working on your Symfony application, stop the server by -pressing ``Ctrl+C`` from the terminal or command console. +Open your browser, access the ``http://localhost:8000/`` URL and you'll see the +application running. When you are finished working on your Symfony application, +stop the server by pressing ``Ctrl+C`` from the terminal or command console. .. tip:: @@ -188,35 +81,40 @@ pressing ``Ctrl+C`` from the terminal or command console. used on production. Instead, use Apache or Nginx. See :doc:`/setup/web_server_configuration`. -Checking Symfony Application Configuration and Setup ----------------------------------------------------- +Checking Symfony Requirements +----------------------------- -The Symfony Installer checks if your system is ready to run Symfony applications. -However, the PHP configuration for the command console can be different from the -PHP web configuration. For that reason, Symfony provides a visual configuration -checker. Access the following URL to check your configuration and fix any issue -before moving on: +In addition to PHP 7.1, Symfony has other `technical requirements`_ that your +server must meet. Symfony provides a tool called "Requirements Checker" (or +``req-checker``) to check those requirements: -.. code-block:: text +.. code-block:: terminal + + $ cd my-project/ + $ composer require req-checker - http://localhost:8000/config.php +The ``req-checker`` utility adds two PHP scripts in your application: +``bin/check.php`` and ``public/check.php``. Run the first one in the command +console and the second one in the browser. This is needed because PHP can define +a different configuration for both the command console and the web server, so +you need to check both. -Fixing Permissions Problems ---------------------------- +Once you've fixed all the reported issues, uninstall the requirements checker: -If you have any file permission errors or see a white screen, then read -:doc:`/setup/file_permissions` for more information. +.. code-block:: terminal + + $ composer remove req-checker .. _installation-updating-vendors: Updating Symfony Applications ----------------------------- -At this point, you've created a fully-functional Symfony application! Every Symfony -app depends on a number of third-party libraries stored in the ``vendor/`` directory -and managed by Composer. +At this point, you've created a fully-functional Symfony application! Every +Symfony app depends on a number of third-party libraries stored in the +``vendor/`` directory and managed by Composer. -Updating those libraries frequently is a good practice to prevent bugs and +Updating those libraries frequently is a good practice to fix bugs and prevent security vulnerabilities. Execute the ``update`` Composer command to update them all at once (this can take up to several minutes to complete depending on the complexity of your project): @@ -226,68 +124,64 @@ complexity of your project): $ cd my_project_name/ $ composer update -.. tip:: - - Symfony provides a command to check whether your project's dependencies - contain any known security vulnerability: +.. _install-existing-app: - .. code-block:: terminal +Installing an Existing Symfony Application +------------------------------------------ - $ php bin/console security:check +When working collaboratively in a Symfony application, it's uncommon to create +a new Symfony application as explained in the previous sections. Instead, +someone else has already created and submitted it to a shared repository. - A good security practice is to execute this command regularly to be able to - update or replace compromised dependencies as soon as possible. +It's recommended to not submit some files (``.env``) and directories (``vendor/``, +cache, logs) to the repository, so you'll have to do the following when +installing an existing Symfony application: -.. _installing-a-symfony2-distribution: +.. code-block:: terminal -Installing the Symfony Demo or Other Distributions --------------------------------------------------- + # clone the project to download its contents + $ cd projects/ + $ git clone ... -You've already downloaded the `Symfony Standard Edition`_: the default starting project -for all Symfony apps. You'll use this project throughout the documentation to build -your app! + # make Composer install the project's dependencies into vendor/ + $ cd my-project/ + $ composer install -Symfony also provides some other projects and starting skeletons that you can use: +Checking for Security Vulnerabilities +------------------------------------- -`The Symfony Demo Application`_ - This is a fully-functional application that shows the recommended way to develop - Symfony applications. The app has been conceived as a learning tool for Symfony - newcomers and its source code contains tons of comments and helpful notes. +Symfony provides a utility called "Security Checker" (or ``sec-checker``) to +check whether your project's dependencies contain any known security +vulnerability. Run this command to install it in your application: -`The Symfony CMF Standard Edition`_ - The `Symfony CMF`_ is a project that helps make it easier for developers to add - CMS functionality to their Symfony applications. This is a starting project - containing the Symfony CMF. +.. code-block:: terminal -`The Symfony REST Edition`_ - Shows how to build an application that provides a RESTful API using the - `FOSRestBundle`_ and several other related Bundles. + $ cd my-project/ + $ composer require sec-checker -.. _install-existing-app: +From now on, this command will be run automatically whenever you install or +update any dependency in the application. -Installing an Existing Symfony Application -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Installing the Symfony Demo application +--------------------------------------- -When working collaboratively in a Symfony application, it's uncommon to create -a new Symfony application as explained in the previous sections. Instead, -someone else has already created and submitted it to a shared repository. +`The Symfony Demo Application`_ is a fully-functional application that shows the +recommended way to develop Symfony applications. It's a great learning tool for +Symfony newcomers and its code contains tons of comments and helpful notes. -It's recommended to not submit some files (:ref:`parameters.yml `) -and directories (``vendor/``, cache, logs) to the repository, so you'll have to do -the following when installing an existing Symfony application: +Run the following command to download and install the Symfony Demo application: .. code-block:: terminal - # clone the project to download its contents - $ cd projects/ - $ git clone ... + $ composer create-project symfony/symfony-demo my-project - # make Composer install the project's dependencies into vendor/ - $ cd my_project_name/ - $ composer install +Now, enter the ``my-project/`` directory, run the internal web server and +browse ``http://127.0.0.1:8000``: + +.. code-block:: terminal - # now Composer will ask you for the values of any undefined parameter - $ ... + $ cd my-project + $ php bin/console server:start Keep Going! ----------- @@ -315,10 +209,5 @@ Go Deeper with Setup .. _`Joyful Development with Symfony`: http://knpuniversity.com/screencast/symfony .. _`Composer`: https://getcomposer.org/ -.. _`Phar extension`: http://php.net/manual/en/intro.phar.php -.. _`Symfony Standard Edition`: https://github.com/symfony/symfony-standard +.. _`technical requirements`: https://symfony.com/doc/current/reference/requirements.html .. _`The Symfony Demo application`: https://github.com/symfony/symfony-demo -.. _`The Symfony CMF Standard Edition`: https://github.com/symfony-cmf/standard-edition -.. _`Symfony CMF`: http://cmf.symfony.com/ -.. _`The Symfony REST Edition`: https://github.com/gimler/symfony-rest-edition -.. _`FOSRestBundle`: https://github.com/FriendsOfSymfony/FOSRestBundle From 0ddc1d6c487ad9ade1c5c0142d515761fcb14eb8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 20 Jul 2017 09:15:00 +0200 Subject: [PATCH 0007/2437] Updated the Requirements article for Symfony 4.0 --- reference/requirements.rst | 58 +++++++++++++++----------------------- 1 file changed, 22 insertions(+), 36 deletions(-) diff --git a/reference/requirements.rst b/reference/requirements.rst index 620d02e771b..aee434ed454 100644 --- a/reference/requirements.rst +++ b/reference/requirements.rst @@ -6,50 +6,36 @@ Requirements for Running Symfony ================================ -To run Symfony, your system needs to adhere to a list of requirements. You -can easily see if your system passes all requirements by running the -``web/config.php`` in your Symfony distribution. Since the CLI often uses -a different ``php.ini`` configuration file, it's also a good idea to check -your requirements from the command line via: +Symfony 4.0 requires **PHP 7.1.3** or higher to run, in addition to other minor +requirements. To make things simple, Symfony provides a tool to quickly check if +your system meets all those requirements. Run this command to install the tool: .. code-block:: terminal - $ php bin/symfony_requirements + $ cd your-project/ + $ composer require requirements-checker -Below is the list of required and optional requirements. +Beware that PHP can define a different configuration for the command console and +the web server, so you need to check requirements in both environments. -Required --------- +Checking Requirements for the Web Server +---------------------------------------- -* PHP needs to be a minimum version of PHP 5.5.9 -* `JSON extension`_ needs to be enabled -* `ctype extension`_ needs to be enabled -* Your ``php.ini`` needs to have the ``date.timezone`` setting +The requirements checker tool creates a file called ``check.php`` in the +``public/`` directory of your project. Open that file with your browser to check +the requirements. -Optional --------- +Once you've fixed all the reported issues, uninstall the requirements checker +to avoid leaking internal information about your application to visitors: -* You need to have the PHP-XML module installed -* You need to have at least version 2.6.21 of libxml -* PHP tokenizer needs to be enabled -* mbstring functions need to be enabled -* iconv needs to be enabled -* POSIX needs to be enabled (only on \*nix) -* Intl needs to be installed with ICU 4+ -* APC 3.0.17+ (or another opcode cache needs to be installed) -* ``php.ini`` recommended settings - - * ``short_open_tag = Off`` - * ``magic_quotes_gpc = Off`` - * ``register_globals = Off`` - * ``session.auto_start = Off`` +.. code-block:: terminal -Doctrine --------- + $ cd your-project/ + $ composer remove requirements-checker -If you want to use Doctrine, you will need to have PDO installed. Additionally, -you need to have the PDO driver installed for the database server you want -to use. +Checking Requirements for the Command Console +--------------------------------------------- -.. _`JSON extension`: https://php.net/manual/book.json.php -.. _`ctype extension`: https://php.net/manual/book.ctype.php +The requirements checker tool adds a script to your Composer configuration to +check the requirements automatically. There's no need to execute any command; if +there is any issue, you'll see them in the console output. From bd765c1bf820a7dfd1ad4840863cdbf6af68bf01 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 5 Oct 2017 20:22:17 +0200 Subject: [PATCH 0008/2437] Update outdated session documentation with SF 4 --- .../http_foundation/session_configuration.rst | 53 ------------------- 1 file changed, 53 deletions(-) diff --git a/components/http_foundation/session_configuration.rst b/components/http_foundation/session_configuration.rst index 66d0087189d..ca5524adbe4 100644 --- a/components/http_foundation/session_configuration.rst +++ b/components/http_foundation/session_configuration.rst @@ -72,7 +72,6 @@ The Symfony HttpFoundation component provides some by default and these can easily serve as examples if you wish to write your own. * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\PdoSessionHandler` -* :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MemcacheSessionHandler` * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MemcachedSessionHandler` * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\MongoDbSessionHandler` * :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NullSessionHandler` @@ -262,58 +261,6 @@ particular cookie by reading the ``getLifetime()`` method:: The expiry time of the cookie can be determined by adding the created timestamp and the lifetime. -PHP 5.4 Compatibility -~~~~~~~~~~~~~~~~~~~~~ - -Since PHP 5.4.0, :phpclass:`SessionHandler` and :phpclass:`SessionHandlerInterface` -are available. Symfony provides forward compatibility for the :phpclass:`SessionHandlerInterface` -so it can be used under PHP 5.3. This greatly improves interoperability with other -libraries. - -:phpclass:`SessionHandler` is a special PHP internal class which exposes native save -handlers to PHP user-space. - -In order to provide a solution for those using PHP 5.4, Symfony has a special -class called :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Handler\\NativeSessionHandler` -which under PHP 5.4, extends from ``\SessionHandler`` and under PHP 5.3 is just a -empty base class. This provides some interesting opportunities to leverage -PHP 5.4 functionality if it is available. - -Save Handler Proxy -~~~~~~~~~~~~~~~~~~ - -A Save Handler Proxy is basically a wrapper around a Save Handler that was -introduced to seamlessly support the migration from PHP 5.3 to PHP 5.4+. It -further creates an extension point from where custom logic can be added that -works independently of which handler is being wrapped inside. - -There are two kinds of save handler class proxies which inherit from -:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\AbstractProxy`: -they are :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\NativeProxy` -and :class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\SessionHandlerProxy`. - -:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\NativeSessionStorage` -automatically injects storage handlers into a save handler proxy unless already -wrapped by one. - -:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\NativeProxy` -is used automatically under PHP 5.3 when internal PHP save handlers are specified -using the ``Native*SessionHandler`` classes, while -:class:`Symfony\\Component\\HttpFoundation\\Session\\Storage\\Proxy\\SessionHandlerProxy` -will be used to wrap any custom save handlers, that implement :phpclass:`SessionHandlerInterface`. - -From PHP 5.4 and above, all session handlers implement :phpclass:`SessionHandlerInterface` -including ``Native*SessionHandler`` classes which inherit from :phpclass:`SessionHandler`. - -The proxy mechanism allows you to get more deeply involved in session save handler -classes. A proxy for example could be used to encrypt any session transaction -without knowledge of the specific save handler. - -.. note:: - - Before PHP 5.4, you can only proxy user-land save handlers but not - native PHP save handlers. - .. _`php.net/session.customhandler`: http://php.net/session.customhandler .. _`php.net/session.configuration`: http://php.net/session.configuration .. _`php.net/memcached.setoption`: http://php.net/memcached.setoption From 46e5655f4ffcfc7340149c29295f06bd34c18ac8 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Tue, 24 Oct 2017 11:25:56 -0400 Subject: [PATCH 0009/2437] Fix default log directory name --- best_practices/creating-the-project.rst | 2 +- configuration/micro_kernel_trait.rst | 2 +- configuration/multiple_kernels.rst | 2 +- configuration/override_dir_structure.rst | 4 ++-- deployment/azure-website.rst | 4 ++-- deployment/platformsh.rst | 2 +- logging.rst | 6 +++--- page_creation.rst | 2 +- quick_tour/the_architecture.rst | 2 +- reference/configuration/kernel.rst | 2 +- setup/file_permissions.rst | 2 +- setup/new_project_svn.rst | 6 +++--- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/best_practices/creating-the-project.rst b/best_practices/creating-the-project.rst index 7aa8236a2d5..5bdfbd08693 100644 --- a/best_practices/creating-the-project.rst +++ b/best_practices/creating-the-project.rst @@ -87,7 +87,7 @@ following: * ``src/AppBundle/``, stores the Symfony specific code (controllers and routes), your domain code (e.g. Doctrine classes) and all your business logic; * ``var/cache/``, stores all the cache files generated by the application; -* ``var/logs/``, stores all the log files generated by the application; +* ``var/log/``, stores all the log files generated by the application; * ``var/sessions/``, stores all the session files generated by the application; * ``tests/AppBundle/``, stores the automatic tests (e.g. Unit tests) of the application. diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 165c4aed5b7..3bceafc99ff 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -197,7 +197,7 @@ hold the kernel. Now it looks like this:: // optional, to use the standard Symfony logs directory public function getLogDir() { - return __DIR__.'/../var/logs'; + return __DIR__.'/../var/log'; } } diff --git a/configuration/multiple_kernels.rst b/configuration/multiple_kernels.rst index e71c0270a8f..078de65adeb 100644 --- a/configuration/multiple_kernels.rst +++ b/configuration/multiple_kernels.rst @@ -96,7 +96,7 @@ they don't collide with the files from ``AppKernel``:: public function getLogDir() { - return dirname(__DIR__).'/var/logs/api'; + return dirname(__DIR__).'/var/log/api'; } public function registerContainerConfiguration(LoaderInterface $loader) diff --git a/configuration/override_dir_structure.rst b/configuration/override_dir_structure.rst index 809c71244ea..9febff0012e 100644 --- a/configuration/override_dir_structure.rst +++ b/configuration/override_dir_structure.rst @@ -82,11 +82,11 @@ method:: public function getLogDir() { - return dirname(__DIR__).'/var/'.$this->environment.'/logs'; + return dirname(__DIR__).'/var/'.$this->environment.'/log'; } } -Here you have changed the location of the directory to ``var/{environment}/logs``. +Here you have changed the location of the directory to ``var/{environment}/log``. .. _override-templates-dir: diff --git a/deployment/azure-website.rst b/deployment/azure-website.rst index 0c0c0bef337..4c408bedda6 100644 --- a/deployment/azure-website.rst +++ b/deployment/azure-website.rst @@ -255,9 +255,9 @@ directory with at least the following contents: /var/bootstrap.php.cache /var/cache/* /app/config/parameters.yml - /var/logs/* + /var/log/* !var/cache/.gitkeep - !var/logs/.gitkeep + !var/log/.gitkeep /var/SymfonyRequirements.php /build/ /vendor/ diff --git a/deployment/platformsh.rst b/deployment/platformsh.rst index 0cf1c4c54f3..01cc2189a39 100644 --- a/deployment/platformsh.rst +++ b/deployment/platformsh.rst @@ -63,7 +63,7 @@ Platform.sh how to deploy your application (read more about # The mounts that will be performed when the package is deployed. mounts: '/var/cache': 'shared:files/cache' - '/var/logs': 'shared:files/logs' + '/var/log': 'shared:files/log' # The hooks that will be performed when the package is deployed. hooks: diff --git a/logging.rst b/logging.rst index e46398b44de..8b1e2b6b111 100644 --- a/logging.rst +++ b/logging.rst @@ -41,8 +41,8 @@ The configuration for *where* logs are stored lives in the specific :doc:`environment ` configuration files: ``config_dev.yml`` and ``config_prod.yml``. -By default, log entries are written to the ``var/logs/dev.log`` file when you're in -the ``dev`` environment. In the ``prod`` environment, logs are written to ``var/logs/prod.log``, +By default, log entries are written to the ``var/log/dev.log`` file when you're in +the ``dev`` environment. In the ``prod`` environment, logs are written to ``var/log/prod.log``, but *only* during a request where an error or high-priority log entry was made (i.e. ``error()`` , ``critical()``, ``alert()`` or ``emergency()``). @@ -77,7 +77,7 @@ to write logs using the :phpfunction:`syslog` function: # this "file_log" key could be anything file_log: type: stream - # log to var/logs/(environment).log + # log to var/log/(environment).log path: "%kernel.logs_dir%/%kernel.environment%.log" # log *all* messages (debug is lowest level) level: debug diff --git a/page_creation.rst b/page_creation.rst index 9d79b1f537d..06fbdb00df0 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -179,7 +179,7 @@ So what about the other directories in the project? ``var/`` This is where automatically-created files are stored, like cache files - (``var/cache/``), logs (``var/logs/``) and sessions (``var/sessions/``). + (``var/cache/``), logs (``var/log/``) and sessions (``var/sessions/``). ``vendor/`` Third-party (i.e. "vendor") libraries live here! These are downloaded via the `Composer`_ diff --git a/quick_tour/the_architecture.rst b/quick_tour/the_architecture.rst index 4130cd063ae..ce8c9ccef9a 100644 --- a/quick_tour/the_architecture.rst +++ b/quick_tour/the_architecture.rst @@ -280,7 +280,7 @@ the ``prod`` environment: $ php bin/console cache:clear --env=prod When developing a web application, things can go wrong in many ways. The -log files in the ``var/logs/`` directory tell you everything about the requests +log files in the ``var/log/`` directory tell you everything about the requests and help you fix the problem quickly. Using the Command Line Interface diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index a2b4d54da6e..3a0e51fbda3 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -121,7 +121,7 @@ This returns the path to the cache directory. To change it, override the Log Directory ~~~~~~~~~~~~~ -**type**: ``string`` **default**: ``$this->rootDir/logs`` +**type**: ``string`` **default**: ``$this->rootDir/log`` This returns the path to the log directory. To change it, override the :method:`Symfony\\Component\\HttpKernel\\Kernel::getLogDir` method. Read diff --git a/setup/file_permissions.rst b/setup/file_permissions.rst index 09fc1d3f46e..5c5b8fbb8c7 100644 --- a/setup/file_permissions.rst +++ b/setup/file_permissions.rst @@ -32,7 +32,7 @@ needed permissions: .. code-block:: terminal $ rm -rf var/cache/* - $ rm -rf var/logs/* + $ rm -rf var/log/* $ HTTPDUSER=$(ps axo user,comm | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1) $ sudo chmod +a "$HTTPDUSER allow delete,write,append,file_inherit,directory_inherit" var diff --git a/setup/new_project_svn.rst b/setup/new_project_svn.rst index 563f8f21250..073d76ca698 100644 --- a/setup/new_project_svn.rst +++ b/setup/new_project_svn.rst @@ -75,18 +75,18 @@ with these steps: .. code-block:: terminal $ cd myproject/ - $ svn add --depth=empty app var var/cache var/logs app/config web + $ svn add --depth=empty app var var/cache var/log app/config web $ svn propset svn:ignore "vendor" . $ svn propset svn:ignore "bootstrap*" var/ $ svn propset svn:ignore "parameters.yml" app/config/ $ svn propset svn:ignore "*" var/cache/ - $ svn propset svn:ignore "*" var/logs/ + $ svn propset svn:ignore "*" var/log/ $ svn propset svn:ignore "*" var/sessions/ $ svn propset svn:ignore "bundles" web - $ svn ci -m "commit basic Symfony ignore list (vendor, var/bootstrap*, app/config/parameters.yml, var/cache/*, var/logs/*, web/bundles)" + $ svn ci -m "commit basic Symfony ignore list (vendor, var/bootstrap*, app/config/parameters.yml, var/cache/*, var/log/*, web/bundles)" #. The rest of the files can now be added and committed to the project: From ba220f0f63a928c753d970f38c6dcf74e55e19ff Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sat, 28 Oct 2017 21:58:06 -0400 Subject: [PATCH 0010/2437] Removing deprecated feature --- reference/configuration/security.rst | 52 ---------------------------- 1 file changed, 52 deletions(-) diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index dfa75ab9d80..3f17b03f51f 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -687,57 +687,5 @@ multiple firewalls, the "context" could actually be shared: ignored and you won't be able to authenticate on multiple firewalls at the same time. -HTTP-Digest Authentication --------------------------- - -.. versionadded:: 3.4 - HTTP-Digest Authentication was deprecated in Symfony 3.4 and it will be - removed in Symfony 4.0. - -To use HTTP-Digest authentication you need to provide a realm and a secret: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - firewalls: - somename: - http_digest: - secret: '%secret%' - realm: 'secure-api' - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // app/config/security.php - $container->loadFromExtension('security', array( - 'firewalls' => array( - 'somename' => array( - 'http_digest' => array( - 'secret' => '%secret%', - 'realm' => 'secure-api', - ), - ), - ), - )); - .. _`PBKDF2`: https://en.wikipedia.org/wiki/PBKDF2 .. _`ircmaxell/password-compat`: https://packagist.org/packages/ircmaxell/password-compat From 185509c7506e4f2235883aa2e1069a24b6e13b51 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 22 Oct 2017 19:30:15 -0400 Subject: [PATCH 0011/2437] [4.0] Setup & Page Creation updates --- configuration.rst | 9 + configuration/micro_kernel_trait.rst | 2 +- page_creation.rst | 236 +++++++++++++++++---------- setup.rst | 167 ++++++++----------- setup/_vendor_deps.rst.inc | 3 +- 5 files changed, 231 insertions(+), 186 deletions(-) diff --git a/configuration.rst b/configuration.rst index e6a4358210a..1b120db7e1a 100644 --- a/configuration.rst +++ b/configuration.rst @@ -295,6 +295,15 @@ signs - e.g. ``%locale%``. For more information about parameters - including how to reference them from inside a controller - see :ref:`service-container-parameters`. +.. _config-dot-env: + +The .env File +~~~~~~~~~~~~~ + +There is also a ``.env`` file which is loaded. Its contents become environment variables +in the dev environment, making it easier to reference environment variables in your +code. + .. _config-parameters-yml: The Special parameters.yml File diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 3bceafc99ff..8e834079271 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -1,7 +1,7 @@ Building your own Framework with the MicroKernelTrait ===================================================== -A :ref:`traditional Symfony app ` contains a sensible +A traditional Symfony app contains a sensible directory structure, various configuration files and an ``AppKernel`` with several bundles already-registered. This is a fully-featured app that's ready to go. diff --git a/page_creation.rst b/page_creation.rst index 06fbdb00df0..2889e2b0b49 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -41,21 +41,16 @@ Creating a Page: Route and Controller Suppose you want to create a page - ``/lucky/number`` - that generates a lucky (well, random) number and prints it. To do that, create a "Controller class" and a -"controller" method inside of it that will be executed when someone goes to -``/lucky/number``:: +"controller" method inside of it:: - // src/AppBundle/Controller/LuckyController.php - namespace AppBundle\Controller; + // src/Controller/LuckyController.php + namespace App\Controller; use Symfony\Component\HttpFoundation\Response; - use Symfony\Component\Routing\Annotation\Route; class LuckyController { - /** - * @Route("/lucky/number") - */ - public function numberAction() + public function number() { $number = mt_rand(0, 100); @@ -65,8 +60,20 @@ random) number and prints it. To do that, create a "Controller class" and a } } -Before diving into this, test it out! If you are using PHP's internal web server -go to: +Now you need to associate this controller function with a public URL (e.g. ``/lucky/number``) +so that the ``number()`` method is executed when a user browses to it. This association +is defined by creating a **route** in the ``config/routes.yaml`` file: + +.. code-block:: yaml + + # config/routes.yaml + + # the "app_lucky_number" route name is not important yet + app_lucky_number: + path: /lucky/number + controller: App\Controller\LuckyController::number + +That's it! If you are using Symfony web server, try it out by going to: http://localhost:8000/lucky/number @@ -74,35 +81,136 @@ If you see a lucky number being printed back to you, congratulations! But before you run off to play the lottery, check out how this works. Remember the two steps to creating a page? -#. *Create a route*: The ``@Route`` above ``numberAction()`` is the *route*: it - defines the URL pattern for this page. You'll learn more about :doc:`routing ` - in its own section, including how to make *variable* URLs; +#. *Create a route*: In ``config/routes.yaml``, the route defines the URL to your + page (``path``) and what ``controller`` to call. You'll learn more about :doc:`routing ` + in its own section, including how to make *variable* URLs; -#. *Create a controller*: The method below the route - ``numberAction()`` - is called - the *controller*. This is a function where *you* build the page and ultimately +#. *Create a controller*: This is a function where *you* build the page and ultimately return a ``Response`` object. You'll learn more about :doc:`controllers ` in their own section, including how to return JSON responses. +Annotation Routes +----------------- + +Instead of defining your route in YAML, Symfony also allows you to use *annotation* +routes. First, install the annotations package: + +.. code-block:: terminal + + $ composer require annotations + +Then, in ``config/routes.yaml``, remove the route you just created and uncomment +the annotation route import at the bottom: + +.. code-block:: yaml + + controllers: + resource: ../src/Controller/ + type: annotation + +After this one-time setup, you can now add your route directly *above* the controller: + +.. code-block:: diff + + // src/Controller/LuckyController.php + + // ... + + use Symfony\Component\Routing\Annotation\Route; + + + /** + + * @Route("/lucky/number") + + */ + class LuckyController + { + public function number() + { + // this looks exactly the same + } + } + +That's it! The page - ``http://localhost:8000/lucky/number`` will work exactly +like before! Annotations are the recommended way to configure routes. + +Auto-Installing Recipes with Symfony Flex +----------------------------------------- + +You may not have noticed, but when you ran ``composer require annotations``, two +special things happened, both thanks to a powerful Composer plugin called +:doc:`Flex `. + +First, ``annotations`` isn't a real package name: it's an *alias* (i.e. shortcut) +that Flex resolves to ``sensio/framework-extra-bundle``. + +Second, after this package was downloaded, Flex executed a *recipe*, which is a +set of automated instructions that tell Symfony how to integrate an external +package. Flex recipes exist for many packages (see `symfony.sh`_) and have the ability +to do a lot, like adding configuration files, creating directories, updating ``.gitignore`` +and adding new config to your ``.env`` file. Flex *automates* the installation of +packages so you can get back to coding. + +You can learn more about Flex by reading ":doc:`/setup/flex`". But that's not necessary: +Flex works automatically in the background when you add packages. + +The bin/console Command +----------------------- + +Your project already has a powerful debugging tool inside: the ``bin/console`` command. +Try running it: + +.. code-block:: terminal + + $ php bin/console + +You should see a list of commands that can give you debugging information, help generate +code, generate database migrations and a lot more. As you install more packages, +you'll see more commands. + +To get a list of *all* of the routes in your system, use the ``debug:router`` command: + +.. code-block:: terminal + + $ php bin/console debug:router + +You'll learn about many more commands as you continue! + The Web Debug Toolbar: Debugging Dream -------------------------------------- -If your page is working, then you should *also* see a bar along the bottom of your -browser. This is called the Web Debug Toolbar: and it's your debugging best friend. -You'll learn more about all the information it holds along the way, but feel free -to experiment: hover over and click the different icons to get information about -routing, performance, logging and more. +One of Symfony's *killer* features is the Web Debug Toolbar: a bar that displays +a *huge* amount of debugging information along the bottom of your page while developing. + +To use the web debug toolbar, just install it: -Rendering a Template (with the Service Container) -------------------------------------------------- +.. code-block:: terminal + + $ composer require profiler + +As soon as this finishes, refresh your page. You should see a black bar along the +bottom of the page. You'll learn more about all the information it holds along the +way, but feel free to experiment: hover over and click the different icons to get +information about routing, performance, logging and more. + +The ``profiler`` package is also a great example of Flex! After downloading the +package, the recipe created several configuration files so that the web debug toolbar +worked instantly. + +Rendering a Template +-------------------- If you're returning HTML from your controller, you'll probably want to render a template. Fortunately, Symfony comes with `Twig`_: a templating language that's easy, powerful and actually quite fun. -First, make sure that ``LuckyController`` extends Symfony's base +First, install Twig:: + +.. code-block:: terminal + + $ composer require twig + +Second, make sure that ``LuckyController`` extends Symfony's base :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` class:: - // src/AppBundle/Controller/LuckyController.php + // src/Controller/LuckyController.php // ... // --> add this new use statement @@ -113,10 +221,10 @@ First, make sure that ``LuckyController`` extends Symfony's base // ... } -Now, use the handy ``render()`` function to render a template. Pass it our ``number`` -variable so we can render that:: +Now, use the handy ``render()`` function to render a template. Pass it a ``number`` +variable so you can use it in Twig:: - // src/AppBundle/Controller/LuckyController.php + // src/Controller/LuckyController.php // ... class LuckyController extends Controller @@ -124,7 +232,7 @@ variable so we can render that:: /** * @Route("/lucky/number") */ - public function numberAction() + public function number() { $number = mt_rand(0, 100); @@ -134,13 +242,13 @@ variable so we can render that:: } } -Finally, template files should live in the ``app/Resources/views`` directory. Create -a new ``app/Resources/views/lucky`` directory with a new ``number.html.twig`` file -inside: +Template files live in the ``templates/`` directory, which was created for you automatically +when you installed Twig. Create a new ``templates/lucky`` directory with a new +``number.html.twig`` file inside: .. code-block:: twig - {# app/Resources/views/lucky/number.html.twig #} + {# templates/lucky/number.html.twig #}

Your lucky number is {{ number }}

@@ -155,17 +263,17 @@ other templates and leverage its powerful layout inheritance system. Checking out the Project Structure ---------------------------------- -Great news! You've already worked inside the two most important directories in your +Great news! You've already worked inside the most important directories in your project: -``app/`` - Contains things like configuration and templates. Basically, anything - that is *not* PHP code goes here. +``config/`` + Contains... configuration of course!. You will configure routes, :doc:`services ` + and packages. ``src/`` - Your PHP code lives here. + All your PHP code lives here. -99% of the time, you'll be working in ``src/`` (PHP files) or ``app/`` (everything +99% of the time, you'll be working in ``src/`` (PHP files) or ``config/`` (everything else). As you keep reading, you'll learn what can be done inside each of these. So what about the other directories in the project? @@ -174,58 +282,17 @@ So what about the other directories in the project? The famous ``bin/console`` file lives here (and other, less important executable files). -``tests/`` - The automated tests (e.g. Unit tests) for your application live here. - ``var/`` This is where automatically-created files are stored, like cache files - (``var/cache/``), logs (``var/log/``) and sessions (``var/sessions/``). + (``var/cache/``) and logs (``var/log/``). ``vendor/`` Third-party (i.e. "vendor") libraries live here! These are downloaded via the `Composer`_ package manager. -``web/`` - This is the document root for your project: put any publicly accessible files - here (e.g. CSS, JS and images). - -Bundles & Configuration ------------------------ - -Your Symfony application comes pre-installed with a collection of *bundles*, like -``FrameworkBundle`` and ``TwigBundle``. Bundles are similar to the idea of a *plugin*, -but with one important difference: *all* functionality in a Symfony application comes -from a bundle. - -Bundles are registered in your ``app/AppKernel.php`` file (a rare PHP file in the -``app/`` directory) and each gives you more *tools*, sometimes called *services*:: - - class AppKernel extends Kernel - { - public function registerBundles() - { - $bundles = array( - new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - new Symfony\Bundle\TwigBundle\TwigBundle(), - // ... - ); - // ... - - return $bundles; - } - - // ... - } - -For example, ``TwigBundle`` is responsible for adding the Twig tool to your app! - -Eventually, you'll download and add more third-party bundles to your app in order -to get even more tools. Imagine a bundle that helps you create paginated lists. -That exists! - -You can control how your bundles behave via the ``app/config/config.yml`` file. -That file - and other details like environments & parameters - are discussed in -the :doc:`/configuration` article. +``public/`` + This is the document root for your project: you put any publicly accessible files + here. What's Next? ------------ @@ -264,3 +331,4 @@ Go Deeper with HTTP & Framework Fundamentals .. _`Twig`: http://twig.sensiolabs.org .. _`Composer`: https://getcomposer.org .. _`Joyful Development with Symfony`: http://knpuniversity.com/screencast/symfony/first-page +.. _`symfony.sh`: https://symfony.sh/ diff --git a/setup.rst b/setup.rst index 5d295693395..9debd159aad 100644 --- a/setup.rst +++ b/setup.rst @@ -4,135 +4,111 @@ Installing & Setting up the Symfony Framework ============================================= -This article explains how to install Symfony and solve the most common issues -that may appear during the installation process. - .. seealso:: Do you prefer video tutorials? Check out the `Joyful Development with Symfony`_ screencast series from KnpUniversity. -.. _installation-creating-the-app: - -Creating Symfony Applications ------------------------------ +To create your new Symfony application, first make sure you're using PHP 7.1 or higher +and have `Composer`_ installed. If you don't, start by :doc:`installing Composer globally ` +on your system. If you want to use a virtual machine (VM), check out :doc:`Homestead `. -Symfony applications are created with `Composer`_, the package manager used by -modern PHP applications. If you don't have Composer installed in your computer, -start by :doc:`installing Composer globally `. Then, execute -this command to create a new empty Symfony application based on its latest -stable version: +Create your new project by running: .. code-block:: terminal $ composer create-project symfony/skeleton my-project +This will create a new ``my-project`` directory, download some dependencies into +it and even generate the basic directories and files you'll need to get started. +In other words, your new app is ready! + .. tip:: - If your Internet connection is slow, you may think that Composer is not - doing anything. If that's your case, add the ``-vvv`` flag to the previous - command to display a detailed output of everything that Composer is doing. + You can also download a specific version of Symfony: -If your project needs to be based on a specific Symfony version, use the -optional third argument of the ``create-project`` command: + .. code-block:: terminal -.. code-block:: terminal + # use the most recent version in any Symfony branch + $ composer create-project symfony/skeleton my-project "3.3.*" - # use the most recent version in any Symfony branch - $ composer create-project symfony/skeleton my-project "3.3.*" + # use a beta or RC version (useful for testing new Symfony versions) + $ composer create-project symfony/skeleton my-project 3.3.0-BETA1 - # use a specific Symfony version - $ composer create-project symfony/skeleton my-project "3.3.5" + Some version are long-term support (LTS) versions. Read the :doc:`Symfony Release process ` + to learn more. - # use a beta or RC version (useful for testing new Symfony versions) - $ composer create-project symfony/skeleton my-project 3.3.0-BETA1 +Running your Symfony Application +-------------------------------- -.. note:: +On production, you should use a web server like Nginx or Apache +(see :doc:`configuring a web server to run Symfony `). +But for development, it's even easier to use the :doc:`Symfony PHP web server `. - Read the :doc:`Symfony Release process ` - to better understand why there are several Symfony versions and which one - to use for your projects. +First, move into your new project and install the server: -Running the Symfony Application -------------------------------- +.. code-block:: terminal -On production servers, Symfony applications use web servers such as Apache or -Nginx (see :doc:`configuring a web server to run Symfony `). -However, on your local development machine you can also use the web server -provided by Symfony, which in turn uses the built-in web server provided by PHP. + cd my-project + composer require server -First, :doc:`install the Symfony Web Server ` and -then, execute this command: +To start the server, run: .. code-block:: terminal $ php bin/console server:run -Open your browser, access the ``http://localhost:8000/`` URL and you'll see the -application running. When you are finished working on your Symfony application, -stop the server by pressing ``Ctrl+C`` from the terminal or command console. +Open your browser and navigate to ``http://localhost:8000/``. If everything is working, +you'll see a welcome page. Later, when you are finished working, stop the server +by pressing ``Ctrl+C`` from your terminal. .. tip:: - Symfony's web server is great for developing, but should **not** be - used on production. Instead, use Apache or Nginx. - See :doc:`/setup/web_server_configuration`. - -Checking Symfony Requirements ------------------------------ + If you're using a VM, you may need to tell the server to bind to all IP addresses: -In addition to PHP 7.1, Symfony has other `technical requirements`_ that your -server must meet. Symfony provides a tool called "Requirements Checker" (or -``req-checker``) to check those requirements: + .. code-block:: terminal -.. code-block:: terminal + $ php bin/console server:start 0.0.0.0:8000 - $ cd my-project/ - $ composer require req-checker + You should **NEVER** listen to all interfaces on a computer that is + directly accessible from the Internet. -The ``req-checker`` utility adds two PHP scripts in your application: -``bin/check.php`` and ``public/check.php``. Run the first one in the command -console and the second one in the browser. This is needed because PHP can define -a different configuration for both the command console and the web server, so -you need to check both. +Troubleshooting: The Requirements Checker +----------------------------------------- -Once you've fixed all the reported issues, uninstall the requirements checker: +If you're having any problems running Symfony, your system may be missing some +`technical requirements`_. Symfony has a "Requirements Checker" tool that you +can use to easily make sure your system is set up. First, move into your project +directory and install it: .. code-block:: terminal - $ composer remove req-checker + $ composer require req-checker -.. _installation-updating-vendors: +The ``req-checker`` utility adds two PHP scripts to your application: +``bin/check.php`` and ``public/check.php``. Run the first one from your terminal: -Updating Symfony Applications ------------------------------ +.. code-block:: terminal -At this point, you've created a fully-functional Symfony application! Every -Symfony app depends on a number of third-party libraries stored in the -``vendor/`` directory and managed by Composer. + php bin/check.php -Updating those libraries frequently is a good practice to fix bugs and prevent -security vulnerabilities. Execute the ``update`` Composer command to update them -all at once (this can take up to several minutes to complete depending on the -complexity of your project): +This will check your CLI environment. Run the second one from a browser (e.g. +``http://localhost:8000/check.php``) to check your web server environment. + +Once you've fixed any issues, uninstall the requirements checker: .. code-block:: terminal - $ cd my_project_name/ - $ composer update + $ composer remove req-checker .. _install-existing-app: -Installing an Existing Symfony Application ------------------------------------------- - -When working collaboratively in a Symfony application, it's uncommon to create -a new Symfony application as explained in the previous sections. Instead, -someone else has already created and submitted it to a shared repository. +Setting up an Existing Symfony Project +-------------------------------------- -It's recommended to not submit some files (``.env``) and directories (``vendor/``, -cache, logs) to the repository, so you'll have to do the following when -installing an existing Symfony application: +If you're working on an existing Symfony application, you'll just need to do a few +things to get your project setup. Assuming your team uses Git, you can setup your +project with the following commands: .. code-block:: terminal @@ -144,10 +120,13 @@ installing an existing Symfony application: $ cd my-project/ $ composer install +You'll probably also need to customize your :ref:`.env ` and do a +few other project-specific tasks (e.g. creating database schema). + Checking for Security Vulnerabilities ------------------------------------- -Symfony provides a utility called "Security Checker" (or ``sec-checker``) to +Symfony provides a utility called the "Security Checker" (or ``sec-checker``) to check whether your project's dependencies contain any known security vulnerability. Run this command to install it in your application: @@ -156,32 +135,21 @@ vulnerability. Run this command to install it in your application: $ cd my-project/ $ composer require sec-checker -From now on, this command will be run automatically whenever you install or -update any dependency in the application. +From now on, this utility will be run automatically whenever you install or +update any dependency in the application. If a dependency contains a vulnerability, +you'll see a clear message. -Installing the Symfony Demo application ---------------------------------------- +The Symfony Demo application +---------------------------- `The Symfony Demo Application`_ is a fully-functional application that shows the recommended way to develop Symfony applications. It's a great learning tool for Symfony newcomers and its code contains tons of comments and helpful notes. -Run the following command to download and install the Symfony Demo application: - -.. code-block:: terminal - - $ composer create-project symfony/symfony-demo my-project - -Now, enter the ``my-project/`` directory, run the internal web server and -browse ``http://127.0.0.1:8000``: - -.. code-block:: terminal - - $ cd my-project - $ php bin/console server:start +To check out its code and install it locally, see `symfony/symfony-demo`_. -Keep Going! ------------ +Start Coding! +------------- With setup behind you, it's time to :doc:`Create your first page in Symfony `. @@ -208,3 +176,4 @@ Go Deeper with Setup .. _`Composer`: https://getcomposer.org/ .. _`technical requirements`: https://symfony.com/doc/current/reference/requirements.html .. _`The Symfony Demo application`: https://github.com/symfony/symfony-demo +.. _`symfony/symfony-demo`: https://github.com/symfony/demo diff --git a/setup/_vendor_deps.rst.inc b/setup/_vendor_deps.rst.inc index bbb4ec1f20b..420c9b2081b 100644 --- a/setup/_vendor_deps.rst.inc +++ b/setup/_vendor_deps.rst.inc @@ -11,8 +11,7 @@ you need for each. By default, these libraries are downloaded by running a ``composer install`` "downloader" binary. This ``composer`` file is from a library called `Composer`_ -and you can read more about installing it in the :ref:`Installation ` -article. +and you can read more about :doc:`installing Composer globally `. The ``composer`` command reads from the ``composer.json`` file at the root of your project. This is an JSON-formatted file, which holds a list of each From 9e5cd17b075e9cdc659ace8acac065c78f0c2d4c Mon Sep 17 00:00:00 2001 From: Wouter J Date: Mon, 30 Oct 2017 22:28:00 +0100 Subject: [PATCH 0012/2437] Lots of automated migrations to Symfony Flex structure --- bundles.rst | 4 +- bundles/extension.rst | 8 +- bundles/override.rst | 2 +- bundles/remove.rst | 8 +- components/dependency_injection.rst | 2 +- components/http_foundation.rst | 2 +- components/routing.rst | 28 ++-- .../front_controllers_and_kernel.rst | 6 +- console.rst | 18 +- console/command_in_controller.rst | 8 +- console/commands_as_services.rst | 12 +- console/hide_commands.rst | 4 +- console/lazy_commands.rst | 2 +- console/request_context.rst | 2 +- console/style.rst | 14 +- controller.rst | 32 ++-- controller/argument_value_resolver.rst | 18 +- controller/error_pages.rst | 12 +- controller/service.rst | 10 +- controller/soap_web_service.rst | 12 +- controller/upload_file.rst | 56 +++---- deployment.rst | 2 +- deployment/azure-website.rst | 26 +-- deployment/heroku.rst | 18 +- deployment/platformsh.rst | 4 +- deployment/proxies.rst | 4 +- doctrine.rst | 22 +-- doctrine/associations.rst | 28 ++-- doctrine/custom_dql_functions.rst | 30 ++-- doctrine/dbal.rst | 12 +- doctrine/event_listeners_subscribers.rst | 36 ++-- doctrine/lifecycle_callbacks.rst | 10 +- doctrine/mapping_model_classes.rst | 2 +- doctrine/registration_form.rst | 34 ++-- doctrine/repository.rst | 26 +-- doctrine/resolve_target_entity.rst | 10 +- doctrine/reverse_engineering.rst | 8 +- email.rst | 4 +- email/testing.rst | 2 +- event_dispatcher.rst | 22 +-- event_dispatcher/before_after_filters.rst | 14 +- event_dispatcher/method_behavior.rst | 14 +- form/action_method.rst | 12 +- form/create_custom_field_type.rst | 20 +-- form/create_form_type_extension.rst | 22 +-- form/csrf_protection.rst | 2 +- form/data_based_validation.rst | 6 +- form/data_transformers.rst | 40 ++--- form/dynamic_form_modification.rst | 50 +++--- form/embedded.rst | 14 +- form/events.rst | 10 +- form/form_collections.rst | 64 +++---- form/form_customization.rst | 14 +- form/form_dependencies.rst | 22 +-- form/form_themes.rst | 12 +- form/inherit_data_option.rst | 28 ++-- form/rendering.rst | 4 +- form/type_guesser.rst | 14 +- form/unit_testing.rst | 18 +- form/use_empty_data.rst | 4 +- form/validation_group_service_resolver.rst | 10 +- forms.rst | 44 ++--- frontend.rst | 2 +- frontend/custom_version_strategy.rst | 18 +- http_cache.rst | 12 +- http_cache/esi.rst | 10 +- http_cache/validation.rst | 14 +- introduction/from_flat_php_to_symfony2.rst | 26 +-- logging/formatter.rst | 2 +- logging/processors.rst | 18 +- profiler/data_collector.rst | 14 +- profiler/matchers.rst | 12 +- quick_tour/the_architecture.rst | 14 +- quick_tour/the_big_picture.rst | 24 +-- quick_tour/the_controller.rst | 30 ++-- quick_tour/the_view.rst | 16 +- reference/dic_tags.rst | 112 ++++++------- routing.rst | 32 ++-- routing/custom_route_loader.rst | 26 +-- routing/external_resources.rst | 8 +- routing/extra_information.rst | 2 +- routing/hostname_pattern.rst | 20 +-- routing/optional_placeholders.rst | 12 +- routing/redirect_in_config.rst | 4 +- routing/redirect_trailing_slash.rst | 8 +- routing/requirements.rst | 16 +- routing/scheme.rst | 6 +- routing/service_container_parameters.rst | 4 +- security.rst | 4 +- security/access_denied_handler.rst | 10 +- security/acl.rst | 8 +- security/api_key_authentication.rst | 36 ++-- security/csrf_in_login_form.rst | 4 +- security/custom_authentication_provider.rst | 44 ++--- security/custom_password_authenticator.rst | 14 +- security/custom_provider.rst | 30 ++-- security/entity_provider.rst | 18 +- security/form_login.rst | 12 +- security/form_login_setup.rst | 14 +- security/guard_authentication.rst | 20 +-- security/impersonating_user.rst | 6 +- security/json_login_setup.rst | 4 +- security/ldap.rst | 2 +- security/multiple_guard_authenticators.rst | 28 ++-- security/multiple_user_providers.rst | 6 +- security/password_encoding.rst | 2 +- security/remember_me.rst | 4 +- security/securing_services.rst | 8 +- security/user_checkers.rst | 14 +- security/voters.rst | 16 +- service_container.rst | 154 ++++++++--------- service_container/3.3-di-changes.rst | 158 +++++++++--------- service_container/alias_private.rst | 28 ++-- service_container/autowiring.rst | 100 +++++------ service_container/calls.rst | 10 +- service_container/compiler_passes.rst | 4 +- service_container/configurators.rst | 56 +++---- service_container/debug.rst | 4 +- service_container/definitions.rst | 12 +- service_container/expression_language.rst | 26 +-- service_container/factories.rst | 56 +++---- service_container/import.rst | 4 +- service_container/injection_types.rst | 20 +-- service_container/lazy_services.rst | 6 +- service_container/optional_dependencies.rst | 12 +- service_container/parameters.rst | 6 +- service_container/parent_services.rst | 70 ++++---- service_container/request.rst | 4 +- service_container/service_decoration.rst | 28 ++-- service_container/service_locators.rst | 24 +-- service_container/shared.rst | 10 +- service_container/tags.rst | 62 +++---- session/locale_sticky_session.rst | 18 +- session/proxy_examples.rst | 18 +- setup/built_in_web_server.rst | 4 +- setup/file_permissions.rst | 2 +- setup/flex.rst | 4 +- setup/new_project_svn.rst | 2 +- setup/web_server_configuration.rst | 32 ++-- templating.rst | 46 ++--- templating/PHP.rst | 26 +-- templating/debug.rst | 6 +- templating/embedding_controllers.rst | 12 +- templating/global_variables.rst | 6 +- templating/inheritance.rst | 6 +- templating/syntax.rst | 2 +- templating/twig_extension.rst | 6 +- testing.rst | 12 +- testing/database.rst | 12 +- testing/doctrine.rst | 4 +- testing/http_authentication.rst | 2 +- translation/locale.rst | 2 +- validation.rst | 72 ++++---- validation/custom_constraint.rst | 42 ++--- validation/groups.rst | 16 +- validation/sequence_provider.rst | 52 +++--- validation/severity.rst | 16 +- validation/translations.rst | 16 +- workflow/state-machines.rst | 6 +- workflow/usage.rst | 10 +- 160 files changed, 1530 insertions(+), 1540 deletions(-) diff --git a/bundles.rst b/bundles.rst index d4d692c724d..7391ffe9d25 100644 --- a/bundles.rst +++ b/bundles.rst @@ -151,14 +151,14 @@ of the most common elements of a bundle: necessary). ``Resources/config/`` - Houses configuration, including routing configuration (e.g. ``routing.yml``). + Houses configuration, including routing configuration (e.g. ``routes.yaml``). ``Resources/views/`` Holds templates organized by controller name (e.g. ``Random/index.html.twig``). ``Resources/public/`` Contains web assets (images, stylesheets, etc) and is copied or symbolically - linked into the project ``web/`` directory via the ``assets:install`` console + linked into the project ``public/`` directory via the ``assets:install`` console command. ``Tests/`` diff --git a/bundles/extension.rst b/bundles/extension.rst index 407831e6710..eee9ff05c10 100644 --- a/bundles/extension.rst +++ b/bundles/extension.rst @@ -116,7 +116,7 @@ Other available loaders are the ``YamlFileLoader``, ``PhpFileLoader`` and .. caution:: If you removed the default file with service definitions (i.e. - ``app/config/services.yml``), make sure to also remove it from the + ``app/config/services.yaml``), make sure to also remove it from the ``imports`` key in ``app/config/config.yml``. Using Configuration to Change the Services @@ -146,8 +146,8 @@ work in the same way, but the second one is for classes that contain PHP annotations). Define the classes to compile as an array of their fully qualified class names:: - use AppBundle\Manager\UserManager; - use AppBundle\Utils\Slugger; + use App\Manager\UserManager; + use App\Utils\Slugger; // ... public function load(array $configs, ContainerBuilder $container) @@ -163,7 +163,7 @@ class names:: // add here only classes that contain PHP annotations $this->addAnnotatedClassesToCompile(array( - 'AppBundle\\Controller\\DefaultController', + 'App\\Controller\\DefaultController', // ... )); } diff --git a/bundles/override.rst b/bundles/override.rst index 3c0fb8c7f2d..b1a55bfd174 100644 --- a/bundles/override.rst +++ b/bundles/override.rst @@ -26,7 +26,7 @@ Routing Routing is never automatically imported in Symfony. If you want to include the routes from any bundle, then they must be manually imported from somewhere -in your application (e.g. ``app/config/routing.yml``). +in your application (e.g. ``app/config/routes.yaml``). The easiest way to "override" a bundle's routing is to never import it at all. Instead of importing a third-party bundle's routing, simply copy diff --git a/bundles/remove.rst b/bundles/remove.rst index 644e8742310..525b3c7787a 100644 --- a/bundles/remove.rst +++ b/bundles/remove.rst @@ -42,8 +42,8 @@ that refers to the bundle. ~~~~~~~~~~~~~~~~~~~~~~~~~ *Some* bundles require you to import routing configuration. Check for references -to the bundle in ``app/config/routing.yml`` and ``app/config/routing_dev.yml``. -If you find any references, remove them completely. +to the bundle in the routing configuration (inside ``config/routes/``). If you +find any references, remove them completely. 2.2 Remove Bundle Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -74,8 +74,8 @@ directory, and any parent directories that are now empty (e.g. ``src/Acme/``). 3.1 Remove Bundle Assets ~~~~~~~~~~~~~~~~~~~~~~~~ -Remove the assets of the bundle in the web/ directory (e.g. -``web/bundles/acmedemo`` for the AcmeDemoBundle). +Remove the assets of the bundle in the public/ directory (e.g. +``public/bundles/acmedemo`` for the AcmeDemoBundle). 4. Remove Integration in other Bundles -------------------------------------- diff --git a/components/dependency_injection.rst b/components/dependency_injection.rst index 5a340a9413d..93d55fe44c7 100644 --- a/components/dependency_injection.rst +++ b/components/dependency_injection.rst @@ -210,7 +210,7 @@ Loading a YAML config file:: $container = new ContainerBuilder(); $loader = new YamlFileLoader($container, new FileLocator(__DIR__)); - $loader->load('services.yml'); + $loader->load('services.yaml'); .. note:: diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 87b340cdc40..88f7b336b58 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -285,7 +285,7 @@ represents an HTTP message. But when moving from a legacy system, adding methods or changing some default behavior might help. In that case, register a PHP callable that is able to create an instance of your ``Request`` class:: - use AppBundle\Http\SpecialRequest; + use App\Http\SpecialRequest; use Symfony\Component\HttpFoundation\Request; Request::setFactory(function ( diff --git a/components/routing.rst b/components/routing.rst index ca52b33f814..03a2ed62c17 100644 --- a/components/routing.rst +++ b/components/routing.rst @@ -364,8 +364,7 @@ routes with UTF-8 characters: .. code-block:: php-annotations - // src/AppBundle/Controller/DefaultController.php - namespace AppBundle\Controller; + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Routing\Annotation\Route; @@ -375,23 +374,21 @@ routes with UTF-8 characters: /** * @Route("/category/{name}", name="route1", options={"utf8": true}) */ - public function categoryAction() + public function category() { // ... } .. code-block:: yaml - # app/config/routing.yml route1: path: /category/{name} - defaults: { _controller: 'AppBundle:Default:category' } + defaults: { _controller: 'App\Controller\DefaultController::category' } options: utf8: true .. code-block:: xml - - AppBundle:Default:category + App\Controller\DefaultController::category .. code-block:: php - // app/config/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('route1', new Route('/category/{name}', array( - '_controller' => 'AppBundle:Default:category', + '_controller' => 'App\Controller\DefaultController::category', ), array(), array( @@ -438,8 +434,7 @@ You can also include UTF-8 strings as routing requirements: .. code-block:: php-annotations - // src/AppBundle/Controller/DefaultController.php - namespace AppBundle\Controller; + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Routing\Annotation\Route; @@ -454,17 +449,16 @@ You can also include UTF-8 strings as routing requirements: * options={"utf8": true} * ) */ - public function defaultAction() + public function default() { // ... } .. code-block:: yaml - # app/config/routing.yml route2: path: /default/{default} - defaults: { _controller: 'AppBundle:Default:default' } + defaults: { _controller: 'App\Controller\DefaultController::default' } requirements: default: "한국어" options: @@ -472,7 +466,6 @@ You can also include UTF-8 strings as routing requirements: .. code-block:: xml - - AppBundle:Default:default + App\Controller\DefaultController::default 한국어 @@ -488,14 +481,13 @@ You can also include UTF-8 strings as routing requirements: .. code-block:: php - // app/config/routing.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('route2', new Route('/default/{default}', array( - '_controller' => 'AppBundle:Default:default', + '_controller' => 'App\Controller\DefaultController::default', ), array( 'default' => '한국어', diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index 4b361724ca3..951d9edbd17 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -30,9 +30,9 @@ The Front Controller The `front controller`_ is a well-known design pattern; it is a section of code that *all* requests served by an application run through. -In the `Symfony Standard Edition`_, this role is taken by the `app.php`_ -and `app_dev.php`_ files in the ``web/`` directory. These are the very -first PHP scripts executed when a request is processed. +In the `Symfony Standard Edition`_, this role is taken by the `index.php`_ file +in the ``public/`` directory. This is the very first PHP script executed when a +request is processed. The main purpose of the front controller is to create an instance of the ``AppKernel`` (more on that in a second), make it handle the request diff --git a/console.rst b/console.rst index 8227269a07c..3b04623cefb 100644 --- a/console.rst +++ b/console.rst @@ -12,14 +12,12 @@ use it to create your own commands. Creating a Command ------------------ -Commands are defined in classes which should be created in the ``Command`` namespace -of your bundle (e.g. ``AppBundle\Command``) and their names should end with the -``Command`` suffix. +Commands are defined in classes extending +:class:`Symfony\\Component\\Console\\Command\\Command`. For example, you may +want a command to create a user:: -For example, you may want a command to create a user:: - - // src/AppBundle/Command/CreateUserCommand.php - namespace AppBundle\Command; + // src/Command/CreateUserCommand.php + namespace App\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -74,7 +72,7 @@ terminal: .. note:: - If you're using the :ref:`default services.yml configuration `, + If you're using the :ref:`default services.yaml configuration `, your command classes are automatically registered as services. You can also manually register your command as a service by configuring the service @@ -229,9 +227,9 @@ class. It uses special input and output classes to ease testing without a real console:: // tests/AppBundle/Command/CreateUserCommandTest.php - namespace Tests\AppBundle\Command; + namespace Tests\App\Command; - use AppBundle\Command\CreateUserCommand; + use App\Command\CreateUserCommand; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\Console\Tester\CommandTester; diff --git a/console/command_in_controller.rst b/console/command_in_controller.rst index 26e39fee70f..cc62d38ae1f 100644 --- a/console/command_in_controller.rst +++ b/console/command_in_controller.rst @@ -24,8 +24,8 @@ Imagine you want to send spooled Swift Mailer messages by :doc:`using the swiftmailer:spool:send command `. Run this command from inside your controller via:: - // src/AppBundle/Controller/SpoolController.php - namespace AppBundle\Controller; + // src/Controller/SpoolController.php + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -76,8 +76,8 @@ First, require the package: Now, use it in your controller:: - // src/AppBundle/Controller/SpoolController.php - namespace AppBundle\Controller; + // src/Controller/SpoolController.php + namespace App\Controller; use SensioLabs\AnsiConverter\AnsiToHtmlConverter; use Symfony\Component\Console\Output\BufferedOutput; diff --git a/console/commands_as_services.rst b/console/commands_as_services.rst index a5533ef3b82..a5e01ddb3da 100644 --- a/console/commands_as_services.rst +++ b/console/commands_as_services.rst @@ -4,7 +4,7 @@ How to Define Commands as Services ================================== -If you're using the :ref:`default services.yml configuration `, +If you're using the :ref:`default services.yaml configuration `, your command classes are already registered as services. Great! This is the recommended setup. @@ -26,7 +26,7 @@ using normal :ref:`dependency injection `. For example, suppose you want to log something from within your command:: - namespace AppBundle\Command; + namespace App\Command; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Command\Command; @@ -59,7 +59,7 @@ For example, suppose you want to log something from within your command:: } } -If you're using the :ref:`default services.yml configuration `, +If you're using the :ref:`default services.yaml configuration `, the command class will automatically be registered as a service and passed the ``$logger`` argument (thanks to autowiring). In other words, *just* by creating this class, everything works! You can call the ``app:sunshine`` command and start logging. @@ -96,7 +96,7 @@ Or set the ``command`` attribute on the ``console.command`` tag in your service services: - AppBundle\Command\SunshineCommand: + App\Command\SunshineCommand: tags: - { name: 'console.command', command: 'app:sunshine' } # ... @@ -110,7 +110,7 @@ Or set the ``command`` attribute on the ``console.command`` tag in your service - + @@ -119,7 +119,7 @@ Or set the ``command`` attribute on the ``console.command`` tag in your service .. code-block:: php - use AppBundle\Command\SunshineCommand; + use App\Command\SunshineCommand; //... diff --git a/console/hide_commands.rst b/console/hide_commands.rst index d7c9b011e94..827f93a0a4a 100644 --- a/console/hide_commands.rst +++ b/console/hide_commands.rst @@ -11,8 +11,8 @@ executed through scheduled tasks, etc. In those cases, you can define the command as **hidden** by setting the ``setHidden()`` method to ``true`` in the command configuration:: - // src/AppBundle/Command/LegacyCommand.php - namespace AppBundle\Command; + // src/Command/LegacyCommand.php + namespace App\Command; use Symfony\Component\Console\Command\Command; diff --git a/console/lazy_commands.rst b/console/lazy_commands.rst index 844bdcd0a1b..6f1a102910f 100644 --- a/console/lazy_commands.rst +++ b/console/lazy_commands.rst @@ -16,7 +16,7 @@ The traditional way of adding commands to your application is to use In order to lazy-load commands, you need to register an intermediate loader which will be responsible for returning ``Command`` instances:: - use AppBundle\Command\HeavyCommand; + use App\Command\HeavyCommand; use Symfony\Component\Console\Application; use Symfony\Component\Console\CommandLoader\FactoryCommmandLoader; diff --git a/console/request_context.rst b/console/request_context.rst index b0983d270ed..11125b58255 100644 --- a/console/request_context.rst +++ b/console/request_context.rst @@ -65,7 +65,7 @@ Configuring the Request Context per Command To change it only in one command you can simply fetch the Request Context from the ``router`` service and override its settings:: - // src/AppBundle/Command/DemoCommand.php + // src/Command/DemoCommand.php // ... class DemoCommand extends ContainerAwareCommand diff --git a/console/style.rst b/console/style.rst index db4af516969..a73523ea646 100644 --- a/console/style.rst +++ b/console/style.rst @@ -10,8 +10,8 @@ questions to the user involves a lot of repetitive code. Consider for example the code used to display the title of the following command:: - // src/AppBundle/Command/GreetCommand.php - namespace AppBundle\Command; + // src/Command/GreetCommand.php + namespace App\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Input\InputInterface; @@ -50,8 +50,8 @@ class and pass the ``$input`` and ``$output`` variables as its arguments. Then, you can start using any of its helpers, such as ``title()``, which displays the title of the command:: - // src/AppBundle/Command/GreetCommand.php - namespace AppBundle\Command; + // src/Command/GreetCommand.php + namespace App\Command; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Style\SymfonyStyle; @@ -339,7 +339,7 @@ If you don't like the design of the commands that use the Symfony Style, you can define your own set of console styles. Just create a class that implements the :class:`Symfony\\Component\\Console\\Style\\StyleInterface`:: - namespace AppBundle\Console; + namespace App\Console; use Symfony\Component\Console\Style\StyleInterface; @@ -352,9 +352,9 @@ Then, instantiate this custom class instead of the default ``SymfonyStyle`` in your commands. Thanks to the ``StyleInterface`` you won't need to change the code of your commands to change their appearance:: - namespace AppBundle\Console; + namespace App\Console; - use AppBundle\Console\CustomStyle; + use App\Console\CustomStyle; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; diff --git a/controller.rst b/controller.rst index 680c3e47452..a7433d55455 100644 --- a/controller.rst +++ b/controller.rst @@ -13,8 +13,8 @@ else you can dream up. The controller executes whatever arbitrary logic See how simple this is by looking at a Symfony controller in action. This renders a page that prints a lucky (random) number:: - // src/AppBundle/Controller/LuckyController.php - namespace AppBundle\Controller; + // src/Controller/LuckyController.php + namespace App\Controller; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -55,8 +55,8 @@ While a controller can be any PHP callable (a function, method on an object, or a ``Closure``), a controller is usually a method inside a controller class:: - // src/AppBundle/Controller/LuckyController.php - namespace AppBundle\Controller; + // src/Controller/LuckyController.php + namespace App\Controller; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -129,8 +129,8 @@ classes. You can extend either to get access to a number of `helper methods`_. Add the ``use`` statement atop the ``Controller`` class and then modify ``LuckyController`` to extend it:: - // src/AppBundle/Controller/LuckyController.php - namespace AppBundle\Controller; + // src/Controller/LuckyController.php + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -221,13 +221,13 @@ If you're serving HTML, you'll want to render a template. The ``render()`` method renders a template **and** puts that content into a ``Response`` object for you:: - // renders app/Resources/views/lucky/number.html.twig + // renders templates/lucky/number.html.twig return $this->render('lucky/number.html.twig', array('name' => $name)); Templates can also live in deeper sub-directories. Just try to avoid creating unnecessarily deep structures:: - // renders app/Resources/views/lottery/lucky/number.html.twig + // renders templates/lottery/lucky/number.html.twig return $this->render('lottery/lucky/number.html.twig', array( 'name' => $name, )); @@ -282,12 +282,12 @@ controller's service config: .. code-block:: yaml - # app/config/services.yml + # app/config/services.yaml services: # ... # explicitly configure the service - AppBundle\Controller\LuckyController: + App\Controller\LuckyController: public: true tags: # add multiple tags to control multiple args @@ -310,7 +310,7 @@ controller's service config: - + register(LuckyController::class) ->setPublic(true) @@ -354,7 +354,7 @@ For more information about services, see the :doc:`/service_container` article. is :ref:`autoconfigured ` and extends either :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller` or :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController`. If - you use the :ref:`services.yml configuration from the Symfony Standard Edition `, + you use the :ref:`services.yaml configuration from the Symfony Standard Edition `, then your controllers are already registered as services and autoconfigured. If you're not using the default configuration, you can tag your service manually @@ -424,7 +424,7 @@ Symfony will automatically return a 500 HTTP response code. throw new \Exception('Something went wrong!'); In every case, an error page is shown to the end user and a full debug -error page is shown to the developer (i.e. when you're using the ``app_dev.php`` +error page is shown to the developer (i.e. when you're using the ``index.php`` front controller - see :ref:`page-creation-environments`). You'll want to customize the error page your user sees. To do that, see @@ -536,7 +536,7 @@ read any flash messages from the session using ``app.flashes()``: .. code-block:: html+twig - {# app/Resources/views/base.html.twig #} + {# templates/base.html.twig #} {# you can read and display just one flash message type... #} {% for message in app.flashes('notice') %} @@ -556,7 +556,7 @@ read any flash messages from the session using ``app.flashes()``: .. code-block:: html+php - + // you can read and display just one flash message type... getFlashBag()->get('notice') as $message): ?> diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index 2772626e91f..6af5f9c320c 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -58,9 +58,9 @@ definition. In the next example, you'll create a value resolver to inject the ``User`` object from the security system. Given you write the following controller:: - namespace AppBundle\Controller; + namespace App\Controller; - use AppBundle\Entity\User; + use App\Entity\User; use Symfony\Component\HttpFoundation\Response; class UserController @@ -92,10 +92,10 @@ Now that you know what to do, you can implement this interface. To get the current ``User``, you need the current security token. This token can be retrieved from the token storage:: - // src/AppBundle/ArgumentResolver/UserValueResolver.php - namespace AppBundle\ArgumentResolver; + // src/ArgumentResolver/UserValueResolver.php + namespace App\ArgumentResolver; - use AppBundle\Entity\User; + use App\Entity\User; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; @@ -148,14 +148,14 @@ and adding a priority. .. code-block:: yaml - # app/config/services.yml + # app/config/services.yaml services: _defaults: # ... be sure autowiring is enabled autowire: true # ... - AppBundle\ArgumentResolver\UserValueResolver: + App\ArgumentResolver\UserValueResolver: tags: - { name: controller.argument_value_resolver, priority: 50 } @@ -172,7 +172,7 @@ and adding a priority. - + @@ -182,7 +182,7 @@ and adding a priority. .. code-block:: php // app/config/services.php - use AppBundle\ArgumentResolver\UserValueResolver; + use App\ArgumentResolver\UserValueResolver; $container->autowire(UserValueResolver::class) ->addTag('controller.argument_value_resolver', array('priority' => 50)); diff --git a/controller/error_pages.rst b/controller/error_pages.rst index 30271a46de7..413380a40aa 100644 --- a/controller/error_pages.rst +++ b/controller/error_pages.rst @@ -185,8 +185,8 @@ With this route added, you can use URLs like .. code-block:: text - http://localhost/app_dev.php/_error/{statusCode} - http://localhost/app_dev.php/_error/{statusCode}.{format} + http://localhost/index.php/_error/{statusCode} + http://localhost/index.php/_error/{statusCode}.{format} to preview the *error* page for a given status code as HTML or for a given status code and format. @@ -268,14 +268,14 @@ In that case, you might want to override one or both of the ``showAction()`` and .. code-block:: yaml - # app/config/services.yml + # app/config/services.yaml services: _defaults: # ... be sure autowiring is enabled autowire: true # ... - AppBundle\Controller\CustomExceptionController: + App\Controller\CustomExceptionController: public: true arguments: $debug: '%kernel.debug%' @@ -294,7 +294,7 @@ In that case, you might want to override one or both of the ``showAction()`` and - + %kernel.debug% @@ -304,7 +304,7 @@ In that case, you might want to override one or both of the ``showAction()`` and .. code-block:: php // app/config/services.php - use AppBundle\Controller\CustomExceptionController; + use App\Controller\CustomExceptionController; $container->autowire(CustomExceptionController::class) ->setArgument('$debug', '%kernel.debug%'); diff --git a/controller/service.rst b/controller/service.rst index 38b54f93735..0cfd6660611 100644 --- a/controller/service.rst +++ b/controller/service.rst @@ -5,7 +5,7 @@ How to Define Controllers as Services ===================================== In Symfony, a controller does *not* need to be registered as a service. But if you're -using the :ref:`default services.yml configuration `, +using the :ref:`default services.yaml configuration `, your controllers *are* already registered as services. This means you can use dependency injection like any other normal service. @@ -26,7 +26,7 @@ syntax: .. code-block:: php-annotations - // src/AppBundle/Controller/HelloController.php + // src/Controller/HelloController.php // You need to use Sensio's annotation to specify a service id use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; @@ -44,7 +44,7 @@ syntax: .. code-block:: yaml - # app/config/routing.yml + # config/routes.yaml hello: path: /hello defaults: { _controller: app.hello_controller:indexAction } @@ -100,8 +100,8 @@ template and return a Response. But, you can also do this directly: In a controller that's defined as a service, you can instead inject the ``templating`` service and use it directly:: - // src/AppBundle/Controller/HelloController.php - namespace AppBundle\Controller; + // src/Controller/HelloController.php + namespace App\Controller; use Symfony\Component\HttpFoundation\Response; diff --git a/controller/soap_web_service.rst b/controller/soap_web_service.rst index 5661646a7c5..d3375bcd37e 100644 --- a/controller/soap_web_service.rst +++ b/controller/soap_web_service.rst @@ -24,8 +24,8 @@ which represents the functionality that you'll expose in your SOAP service. In this case, the SOAP service will allow the client to call a method called ``hello``, which happens to send an email:: - // src/AppBundle/Service/HelloService.php - namespace AppBundle\Service; + // src/Service/HelloService.php + namespace App\Service; class HelloService { @@ -57,12 +57,12 @@ Finally, below is an example of a controller that is capable of handling a SOAP request. Because ``indexAction()`` is accessible via ``/soap``, the WSDL document can be retrieved via ``/soap?wsdl``:: - namespace AppBundle\Controller; + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; - use AppBundle\Service\HelloService; + use App\Service\HelloService; class HelloServiceController extends Controller { @@ -99,7 +99,7 @@ Below is an example calling the service using a `NuSOAP`_ client. This example assumes that the ``indexAction()`` in the controller above is accessible via the route ``/soap``:: - $client = new \Soapclient('http://example.com/app.php/soap?wsdl'); + $client = new \Soapclient('http://example.com/index.php/soap?wsdl'); $result = $client->call('hello', array('name' => 'Scott')); @@ -160,7 +160,7 @@ An example WSDL is below. - + diff --git a/controller/upload_file.rst b/controller/upload_file.rst index b3d7be292e9..1b5370e38db 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -15,8 +15,8 @@ Imagine that you have a ``Product`` entity in your application and you want to add a PDF brochure for each product. To do so, add a new property called ``brochure`` in the ``Product`` entity:: - // src/AppBundle/Entity/Product.php - namespace AppBundle\Entity; + // src/Entity/Product.php + namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; @@ -51,10 +51,10 @@ or ``blob`` because it just stores the PDF file name instead of the file content Then, add a new ``brochure`` field to the form that manages the ``Product`` entity:: - // src/AppBundle/Form/ProductType.php - namespace AppBundle\Form; + // src/Form/ProductType.php + namespace App\Form; - use AppBundle\Entity\Product; + use App\Entity\Product; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -87,7 +87,7 @@ to :doc:`customize form rendering `): .. code-block:: html+twig - {# app/Resources/views/product/new.html.twig #} + {# templates/product/new.html.twig #}

Adding a new product

{{ form_start(form) }} @@ -98,7 +98,7 @@ to :doc:`customize form rendering `): .. code-block:: html+php - +

Adding a new product

start($form) ?> @@ -107,14 +107,14 @@ to :doc:`customize form rendering `): Finally, you need to update the code of the controller that handles the form:: - // src/AppBundle/Controller/ProductController.php - namespace AppBundle\ProductController; + // src/Controller/ProductController.php + namespace App\ProductController; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; - use AppBundle\Entity\Product; - use AppBundle\Form\ProductType; + use App\Entity\Product; + use App\Form\ProductType; class ProductController extends Controller { @@ -165,7 +165,7 @@ controller to specify the directory in which the brochures should be stored: # ... parameters: - brochures_directory: '%kernel.project_dir%/web/uploads/brochures' + brochures_directory: '%kernel.project_dir%/public/uploads/brochures' There are some important things to consider in the code of the above controller: @@ -221,8 +221,8 @@ Creating an Uploader Service To avoid logic in controllers, making them big, you can extract the upload logic to a separate service:: - // src/AppBundle/Service/FileUploader.php - namespace AppBundle\Service; + // src/Service/FileUploader.php + namespace App\Service; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -256,11 +256,11 @@ Then, define a service for this class: .. code-block:: yaml - # app/config/services.yml + # app/config/services.yaml services: # ... - AppBundle\Service\FileUploader: + App\Service\FileUploader: arguments: $targetDir: '%brochures_directory%' @@ -274,7 +274,7 @@ Then, define a service for this class: http://symfony.com/schema/dic/services/services-1.0.xsd"> - + %brochures_directory% @@ -282,16 +282,16 @@ Then, define a service for this class: .. code-block:: php // app/config/services.php - use AppBundle\Service\FileUploader; + use App\Service\FileUploader; $container->autowire(FileUploader::class) ->setArgument('$targetDir', '%brochures_directory%'); Now you're ready to use this service in the controller:: - // src/AppBundle/Controller/ProductController.php + // src/Controller/ProductController.php use Symfony\Component\HttpFoundation\Request; - use AppBundle\Service\FileUploader; + use App\Service\FileUploader; // ... public function newAction(Request $request, FileUploader $fileUploader) @@ -317,14 +317,14 @@ If you are using Doctrine to store the Product entity, you can create a :doc:`Doctrine listener ` to automatically upload the file when persisting the entity:: - // src/AppBundle/EventListener/BrochureUploadListener.php - namespace AppBundle\EventListener; + // src/EventListener/BrochureUploadListener.php + namespace App\EventListener; use Symfony\Component\HttpFoundation\File\UploadedFile; use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Event\PreUpdateEventArgs; - use AppBundle\Entity\Product; - use AppBundle\Service\FileUploader; + use App\Entity\Product; + use App\Service\FileUploader; class BrochureUploadListener { @@ -372,14 +372,14 @@ Now, register this class as a Doctrine listener: .. code-block:: yaml - # app/config/services.yml + # app/config/services.yaml services: _defaults: # ... be sure autowiring is enabled autowire: true # ... - AppBundle\EventListener\BrochureUploadListener: + App\EventListener\BrochureUploadListener: tags: - { name: doctrine.event_listener, event: prePersist } - { name: doctrine.event_listener, event: preUpdate } @@ -397,7 +397,7 @@ Now, register this class as a Doctrine listener: - + @@ -406,7 +406,7 @@ Now, register this class as a Doctrine listener: .. code-block:: php // app/config/services.php - use AppBundle\EventListener\BrochureUploaderListener; + use App\EventListener\BrochureUploaderListener; $container->autowire(BrochureUploaderListener::class) ->addTag('doctrine.event_listener', array( diff --git a/deployment.rst b/deployment.rst index cda57c0d189..1ff67c815c3 100644 --- a/deployment.rst +++ b/deployment.rst @@ -30,7 +30,7 @@ A deployment may also include other tasks, such as: repository; * Creating a temporary staging area to build your updated setup "offline"; * Running any tests available to ensure code and/or server stability; -* Removal of any unnecessary files from the ``web/`` directory to keep your +* Removal of any unnecessary files from the ``public/`` directory to keep your production environment clean; * Clearing of external cache systems (like `Memcached`_ or `Redis`_). diff --git a/deployment/azure-website.rst b/deployment/azure-website.rst index 4c408bedda6..fe28ed9e791 100644 --- a/deployment/azure-website.rst +++ b/deployment/azure-website.rst @@ -263,9 +263,9 @@ directory with at least the following contents: /vendor/ /bin/ /composer.phar - /web/app_dev.php - /web/bundles/ - /web/config.php + /public/index.php + /public/bundles/ + /public/config.php The ``.gitignore`` file asks Git not to track any of the files and directories that match these patterns. This means these files won't be deployed to the Azure @@ -294,7 +294,7 @@ below: The code of the Symfony application has now been deployed to the Azure Website which you can browse from the file explorer of the Kudu application. You should -see the ``app/``, ``src/`` and ``web/`` directories under your ``site/wwwroot`` +see the ``app/``, ``src/`` and ``public/`` directories under your ``site/wwwroot`` directory on the Azure Website filesystem. Configure the Symfony Application @@ -377,12 +377,12 @@ This command builds the tables and indexes for your MySQL database. If your Symfony application is more complex than a basic Symfony Standard Edition, you may have additional commands to execute for setup (see :doc:`/deployment`). -Make sure that your application is running by browsing the ``app.php`` front +Make sure that your application is running by browsing the ``index.php`` front controller with your web browser and the following URL: .. code-block:: terminal - http://.azurewebsites.net/web/app.php + http://.azurewebsites.net/public/index.php If Symfony is correctly installed, you should see the front page of your Symfony application showing. @@ -412,7 +412,7 @@ application, configure it with the following content: - + @@ -420,13 +420,13 @@ application, configure it with the following content: - + - + @@ -434,14 +434,14 @@ application, configure it with the following content: As you can see, the latest rule ``RewriteRequestsToPublic`` is responsible for -rewriting any URLs to the ``web/app.php`` front controller which allows you to -skip the ``web/`` folder in the URL. The first rule called ``BlockAccessToPublic`` -matches all URL patterns that contain the ``web/`` folder and serves a +rewriting any URLs to the ``public/index.php`` front controller which allows you to +skip the ``public/`` folder in the URL. The first rule called ``BlockAccessToPublic`` +matches all URL patterns that contain the ``public/`` folder and serves a ``403 Forbidden`` HTTP response instead. This example is based on Benjamin Eberlei's sample you can find on GitHub in the `SymfonyAzureEdition`_ bundle. Deploy this file under the ``site/wwwroot`` directory of the Azure Website and -browse to your application without the ``web/app.php`` segment in the URL. +browse to your application without the ``public/index.php`` segment in the URL. Conclusion ---------- diff --git a/deployment/heroku.rst b/deployment/heroku.rst index 1fe7748e35a..d34024af5f3 100644 --- a/deployment/heroku.rst +++ b/deployment/heroku.rst @@ -86,7 +86,7 @@ below: By default, Heroku will launch an Apache web server together with PHP to serve applications. However, a special circumstance apply to Symfony applications: -the document root is in the ``web/`` directory and not in the root directory +the document root is in the ``public/`` directory and not in the root directory of the application. Create a new file called ``Procfile`` (without any extension) at the root @@ -94,7 +94,7 @@ directory of the application and add just the following content: .. code-block:: text - web: vendor/bin/heroku-php-apache2 web/ + web: vendor/bin/heroku-php-apache2 public/ .. note:: @@ -104,14 +104,14 @@ directory of the application and add just the following content: .. code-block:: text - web: vendor/bin/heroku-php-nginx -C nginx_app.conf web/ + web: vendor/bin/heroku-php-nginx -C nginx_app.conf public/ If you prefer working on the command console, execute the following commands to create the ``Procfile`` file and to add it to the repository: .. code-block:: terminal - $ echo "web: vendor/bin/heroku-php-apache2 web/" > Procfile + $ echo "web: vendor/bin/heroku-php-apache2 public/" > Procfile $ git add . $ git commit -m "Procfile for Apache and PHP" [master 35075db] Procfile for Apache and PHP @@ -199,9 +199,9 @@ Then, deploy your application executing this command: Creating the "app/config/parameters.yml" file Clearing the cache for the dev environment with debug true Installing assets using the hard copy option - Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework - Installing assets for Acme\DemoBundle into web/bundles/acmedemo - Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution + Installing assets for Symfony\Bundle\FrameworkBundle into public/bundles/framework + Installing assets for Acme\DemoBundle into public/bundles/acmedemo + Installing assets for Sensio\Bundle\DistributionBundle into public/bundles/sensiodistribution -----> Building runtime environment... @@ -241,7 +241,7 @@ Custom Compile Steps If you wish to execute additional custom commands during a build, you can leverage Heroku's `custom compile steps`_. Imagine you want to remove the ``dev`` front controller from your production environment on Heroku in order to avoid a potential vulnerability. -Adding a command to remove ``web/app_dev.php`` to Composer's `post-install-commands`_ would +Adding a command to remove ``public/index.php`` to Composer's `post-install-commands`_ would work, but it also removes the controller in your local development environment on each ``composer install`` or ``composer update`` respectively. Instead, you can add a `custom Composer command`_ named ``compile`` (this key name is a Heroku convention) to the @@ -253,7 +253,7 @@ process: { "scripts": { "compile": [ - "rm web/app_dev.php" + "rm public/index.php" ] } } diff --git a/deployment/platformsh.rst b/deployment/platformsh.rst index f498f057c07..6d9d622a714 100644 --- a/deployment/platformsh.rst +++ b/deployment/platformsh.rst @@ -54,7 +54,7 @@ Platform.sh how to deploy your application (read more about # The public directory of the app, relative to its root. document_root: '/web' # The front-controller script to send non-static requests to. - passthru: '/app.php' + passthru: '/index.php' # The size of the persistent disk of the application (in MB). disk: 2048 @@ -68,7 +68,7 @@ Platform.sh how to deploy your application (read more about # The hooks that will be performed when the package is deployed. hooks: build: | - rm web/app_dev.php + rm public/index.php bin/console --env=prod assetic:dump --no-debug deploy: | bin/console --env=prod cache:clear diff --git a/deployment/proxies.rst b/deployment/proxies.rst index 25a8026108c..436b6f23f10 100644 --- a/deployment/proxies.rst +++ b/deployment/proxies.rst @@ -26,7 +26,7 @@ and what headers your reverse proxy uses to send information: .. code-block:: php - // web/app.php + // public/index.php // ... $request = Request::createFromGlobals(); @@ -65,7 +65,7 @@ In this case, you'll need to - *very carefully* - trust *all* proxies. .. code-block:: php - // web/app.php + // public/index.php // ... Request::setTrustedProxies( diff --git a/doctrine.rst b/doctrine.rst index 67b29c0da4e..040ff0d36ec 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -249,8 +249,8 @@ Without even thinking about Doctrine or databases, you already know that you need a ``Product`` object to represent those products. Create this class inside the ``Entity`` directory of your AppBundle:: - // src/AppBundle/Entity/Product.php - namespace AppBundle\Entity; + // src/Entity/Product.php + namespace App\Entity; class Product { @@ -303,8 +303,8 @@ directly inside the ``Product`` class via DocBlock annotations: .. code-block:: php-annotations - // src/AppBundle/Entity/Product.php - namespace AppBundle\Entity; + // src/Entity/Product.php + namespace App\Entity; use Doctrine\ORM\Mapping as ORM; @@ -339,8 +339,8 @@ directly inside the ``Product`` class via DocBlock annotations: .. code-block:: yaml - # src/AppBundle/Resources/config/doctrine/Product.orm.yml - AppBundle\Entity\Product: + # src/Resources/config/doctrine/Product.orm.yml + App\Entity\Product: type: entity table: product id: @@ -359,14 +359,14 @@ directly inside the ``Product`` class via DocBlock annotations: .. code-block:: xml - + - + @@ -495,10 +495,10 @@ a controller, this is pretty easy. Add the following method to the ``DefaultController`` of the bundle:: - // src/AppBundle/Controller/DefaultController.php + // src/Controller/DefaultController.php // ... - use AppBundle\Entity\Product; + use App\Entity\Product; use Symfony\Component\HttpFoundation\Response; use Doctrine\ORM\EntityManagerInterface; @@ -680,7 +680,7 @@ Updating an Object Once you've fetched an object from Doctrine, updating it is easy. Suppose you have a route that maps a product id to an update action in a controller:: - use AppBundle\Entity\Product; + use App\Entity\Product; // ... public function updateAction($productId) diff --git a/doctrine/associations.rst b/doctrine/associations.rst index 94dd37f0356..517eacf2735 100644 --- a/doctrine/associations.rst +++ b/doctrine/associations.rst @@ -42,7 +42,7 @@ property on the ``Product`` class, annotated as follows: .. code-block:: php-annotations - // src/AppBundle/Entity/Product.php + // src/Entity/Product.php // ... class Product @@ -58,8 +58,8 @@ property on the ``Product`` class, annotated as follows: .. code-block:: yaml - # src/AppBundle/Resources/config/doctrine/Product.orm.yml - AppBundle\Entity\Product: + # src/Resources/config/doctrine/Product.orm.yml + App\Entity\Product: type: entity # ... manyToOne: @@ -72,14 +72,14 @@ property on the ``Product`` class, annotated as follows: .. code-block:: xml - + - + + - + getEntityManager() diff --git a/doctrine/custom_dql_functions.rst b/doctrine/custom_dql_functions.rst index bc9687c065a..e19c9a26eb6 100644 --- a/doctrine/custom_dql_functions.rst +++ b/doctrine/custom_dql_functions.rst @@ -19,12 +19,12 @@ In Symfony, you can register your custom DQL functions as follows: # ... dql: string_functions: - test_string: AppBundle\DQL\StringFunction - second_string: AppBundle\DQL\SecondStringFunction + test_string: App\DQL\StringFunction + second_string: App\DQL\SecondStringFunction numeric_functions: - test_numeric: AppBundle\DQL\NumericFunction + test_numeric: App\DQL\NumericFunction datetime_functions: - test_datetime: AppBundle\DQL\DatetimeFunction + test_datetime: App\DQL\DatetimeFunction .. code-block:: xml @@ -41,10 +41,10 @@ In Symfony, you can register your custom DQL functions as follows: - AppBundle\DQL\StringFunction - AppBundle\DQL\SecondStringFunction - AppBundle\DQL\NumericFunction - AppBundle\DQL\DatetimeFunction + App\DQL\StringFunction + App\DQL\SecondStringFunction + App\DQL\NumericFunction + App\DQL\DatetimeFunction @@ -53,10 +53,10 @@ In Symfony, you can register your custom DQL functions as follows: .. code-block:: php // app/config/config.php - use AppBundle\DQL\StringFunction; - use AppBundle\DQL\SecondStringFunction; - use AppBundle\DQL\NumericFunction; - use AppBundle\DQL\DatetimeFunction; + use App\DQL\StringFunction; + use App\DQL\SecondStringFunction; + use App\DQL\NumericFunction; + use App\DQL\DatetimeFunction; $container->loadFromExtension('doctrine', array( 'orm' => array( @@ -95,7 +95,7 @@ In Symfony, you can register your custom DQL functions as follows: # Place your functions here dql: datetime_functions: - test_datetime: AppBundle\DQL\DatetimeFunction + test_datetime: App\DQL\DatetimeFunction .. code-block:: xml @@ -117,7 +117,7 @@ In Symfony, you can register your custom DQL functions as follows: - AppBundle\DQL\DatetimeFunction + App\DQL\DatetimeFunction @@ -128,7 +128,7 @@ In Symfony, you can register your custom DQL functions as follows: .. code-block:: php // app/config/config.php - use AppBundle\DQL\DatetimeFunction; + use App\DQL\DatetimeFunction; $container->loadFromExtension('doctrine', array( 'doctrine' => array( diff --git a/doctrine/dbal.rst b/doctrine/dbal.rst index 299446ad541..63829c74674 100644 --- a/doctrine/dbal.rst +++ b/doctrine/dbal.rst @@ -110,8 +110,8 @@ mapping types, read Doctrine's `Custom Mapping Types`_ section of their document doctrine: dbal: types: - custom_first: AppBundle\Type\CustomFirst - custom_second: AppBundle\Type\CustomSecond + custom_first: App\Type\CustomFirst + custom_second: App\Type\CustomSecond .. code-block:: xml @@ -126,8 +126,8 @@ mapping types, read Doctrine's `Custom Mapping Types`_ section of their document - - + + @@ -135,8 +135,8 @@ mapping types, read Doctrine's `Custom Mapping Types`_ section of their document .. code-block:: php // app/config/config.php - use AppBundle\Type\CustomFirst; - use AppBundle\Type\CustomSecond; + use App\Type\CustomFirst; + use App\Type\CustomSecond; $container->loadFromExtension('doctrine', array( 'dbal' => array( diff --git a/doctrine/event_listeners_subscribers.rst b/doctrine/event_listeners_subscribers.rst index e69c7b2d80c..48c3d8a33a3 100644 --- a/doctrine/event_listeners_subscribers.rst +++ b/doctrine/event_listeners_subscribers.rst @@ -35,13 +35,13 @@ managers that use this connection. services: # ... - AppBundle\EventListener\SearchIndexer: + App\EventListener\SearchIndexer: tags: - { name: doctrine.event_listener, event: postPersist } - AppBundle\EventListener\SearchIndexer2: + App\EventListener\SearchIndexer2: tags: - { name: doctrine.event_listener, event: postPersist, connection: default } - AppBundle\EventListener\SearchIndexerSubscriber: + App\EventListener\SearchIndexerSubscriber: tags: - { name: doctrine.event_subscriber, connection: default } @@ -53,13 +53,13 @@ managers that use this connection. - + - + - + @@ -67,9 +67,9 @@ managers that use this connection. .. code-block:: php - use AppBundle\EventListener\SearchIndexer; - use AppBundle\EventListener\SearchIndexer2; - use AppBundle\EventListener\SearchIndexerSubscriber; + use App\EventListener\SearchIndexer; + use App\EventListener\SearchIndexer2; + use App\EventListener\SearchIndexerSubscriber; $container->autowire(SearchIndexer::class) ->addTag('doctrine.event_listener', array('event' => 'postPersist')) @@ -91,11 +91,11 @@ In the previous example, a ``SearchIndexer`` service was configured as a Doctrin listener on the event ``postPersist``. The class behind that service must have a ``postPersist()`` method, which will be called when the event is dispatched:: - // src/AppBundle/EventListener/SearchIndexer.php - namespace AppBundle\EventListener; + // src/EventListener/SearchIndexer.php + namespace App\EventListener; use Doctrine\ORM\Event\LifecycleEventArgs; - use AppBundle\Entity\Product; + use App\Entity\Product; class SearchIndexer { @@ -135,13 +135,13 @@ Creating the Subscriber Class A Doctrine event subscriber must implement the ``Doctrine\Common\EventSubscriber`` interface and have an event method for each event it subscribes to:: - // src/AppBundle/EventListener/SearchIndexerSubscriber.php - namespace AppBundle\EventListener; + // src/EventListener/SearchIndexerSubscriber.php + namespace App\EventListener; use Doctrine\Common\EventSubscriber; // for Doctrine < 2.4: use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\Common\Persistence\Event\LifecycleEventArgs; - use AppBundle\Entity\Product; + use App\Entity\Product; class SearchIndexerSubscriber implements EventSubscriber { @@ -207,7 +207,7 @@ to the tag like so: services: my.listener: - class: AppBundle\EventListener\SearchIndexer + class: App\EventListener\SearchIndexer tags: - { name: doctrine.event_listener, event: postPersist, lazy: true } @@ -218,7 +218,7 @@ to the tag like so: xmlns:doctrine="http://symfony.com/schema/dic/doctrine"> - + @@ -226,7 +226,7 @@ to the tag like so: .. code-block:: php - use AppBundle\EventListener\SearchIndexer; + use App\EventListener\SearchIndexer; $container ->register('my.listener', SearchIndexer::class) diff --git a/doctrine/lifecycle_callbacks.rst b/doctrine/lifecycle_callbacks.rst index a6535a9c749..6f7bf14a6e4 100644 --- a/doctrine/lifecycle_callbacks.rst +++ b/doctrine/lifecycle_callbacks.rst @@ -32,7 +32,7 @@ the current date, only when the entity is first persisted (i.e. inserted): .. code-block:: php-annotations - // src/AppBundle/Entity/Product.php + // src/Entity/Product.php /** * @ORM\PrePersist @@ -44,8 +44,8 @@ the current date, only when the entity is first persisted (i.e. inserted): .. code-block:: yaml - # src/AppBundle/Resources/config/doctrine/Product.orm.yml - AppBundle\Entity\Product: + # src/Resources/config/doctrine/Product.orm.yml + App\Entity\Product: type: entity # ... lifecycleCallbacks: @@ -53,14 +53,14 @@ the current date, only when the entity is first persisted (i.e. inserted): .. code-block:: xml - + - + diff --git a/doctrine/mapping_model_classes.rst b/doctrine/mapping_model_classes.rst index 8052b51dbe0..134912d2dea 100644 --- a/doctrine/mapping_model_classes.rst +++ b/doctrine/mapping_model_classes.rst @@ -117,7 +117,7 @@ Annotations, XML, Yaml, PHP and StaticPHP. The arguments are: use Doctrine\Common\Persistence\Mapping\Driver\DefaultFileLocator; use Doctrine\ORM\Mapping\Driver\XmlDriver; - use AppBundle\Model; + use App\Model; // ... private function buildMappingCompilerPass() diff --git a/doctrine/registration_form.rst b/doctrine/registration_form.rst index 9320e456b96..5e44f9d2833 100644 --- a/doctrine/registration_form.rst +++ b/doctrine/registration_form.rst @@ -39,8 +39,8 @@ Your ``User`` entity will probably at least have the following fields: With some validation added, your class may look something like this:: - // src/AppBundle/Entity/User.php - namespace AppBundle\Entity; + // src/Entity/User.php + namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; @@ -167,10 +167,10 @@ Create a Form for the Entity Next, create the form for the ``User`` entity:: - // src/AppBundle/Form/UserType.php - namespace AppBundle\Form; + // src/Form/UserType.php + namespace App\Form; - use AppBundle\Entity\User; + use App\Entity\User; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -217,11 +217,11 @@ Next, you need a controller to handle the form rendering and submission. If the form is submitted, the controller performs the validation and saves the data into the database:: - // src/AppBundle/Controller/RegistrationController.php - namespace AppBundle\Controller; + // src/Controller/RegistrationController.php + namespace App\Controller; - use AppBundle\Form\UserType; - use AppBundle\Entity\User; + use App\Form\UserType; + use App\Entity\User; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; @@ -274,7 +274,7 @@ encoder in the security configuration: # app/config/security.yml security: encoders: - AppBundle\Entity\User: bcrypt + App\Entity\User: bcrypt .. code-block:: xml @@ -286,14 +286,14 @@ encoder in the security configuration: xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - bcrypt + bcrypt .. code-block:: php // app/config/security.php - use AppBundle\Entity\User; + use App\Entity\User; $container->loadFromExtension('security', array( 'encoders' => array( @@ -313,7 +313,7 @@ the :ref:`user password encoding ` article. .. code-block:: yaml - # app/config/routing.yml + # config/routes.yaml user_registration: path: /register defaults: { _controller: AppBundle:Registration:register } @@ -350,7 +350,7 @@ Next, create the template: .. code-block:: html+twig - {# app/Resources/views/registration/register.html.twig #} + {# templates/registration/register.html.twig #} {{ form_start(form) }} {{ form_row(form.username) }} @@ -363,7 +363,7 @@ Next, create the template: .. code-block:: html+php - + start($form) ?> row($form['username']) ?> @@ -398,7 +398,7 @@ If you want your users to login via email and you don't need a username, then yo can remove it from your ``User`` entity entirely. Instead, make ``getUsername()`` return the ``email`` property:: - // src/AppBundle/Entity/User.php + // src/Entity/User.php // ... class User implements UserInterface @@ -428,7 +428,7 @@ that you'll never need. To do this, add a ``termsAccepted`` field to your form, but set its :ref:`mapped ` option to ``false``:: - // src/AppBundle/Form/UserType.php + // src/Form/UserType.php // ... use Symfony\Component\Validator\Constraints\IsTrue; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; diff --git a/doctrine/repository.rst b/doctrine/repository.rst index e89a24361e1..d92d0885c62 100644 --- a/doctrine/repository.rst +++ b/doctrine/repository.rst @@ -15,13 +15,13 @@ To do this, add the repository class name to your entity's mapping definition: .. code-block:: php-annotations - // src/AppBundle/Entity/Product.php - namespace AppBundle\Entity; + // src/Entity/Product.php + namespace App\Entity; use Doctrine\ORM\Mapping as ORM; /** - * @ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository") + * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") */ class Product { @@ -30,15 +30,15 @@ To do this, add the repository class name to your entity's mapping definition: .. code-block:: yaml - # src/AppBundle/Resources/config/doctrine/Product.orm.yml - AppBundle\Entity\Product: + # src/Resources/config/doctrine/Product.orm.yml + App\Entity\Product: type: entity - repositoryClass: AppBundle\Repository\ProductRepository + repositoryClass: App\Repository\ProductRepository # ... .. code-block:: xml - + + name="App\Entity\Product" + repository-class="App\Repository\ProductRepository"> -Then, create an empty ``AppBundle\Repository\ProductRepository`` class extending +Then, create an empty ``App\Repository\ProductRepository`` class extending from ``Doctrine\ORM\EntityRepository``. Next, add a new method - ``findAllOrderedByName()`` - to the newly-generated @@ -62,8 +62,8 @@ entities, ordered alphabetically by name. .. code-block:: php - // src/AppBundle/Repository/ProductRepository.php - namespace AppBundle\Repository; + // src/Repository/ProductRepository.php + namespace App\Repository; use Doctrine\ORM\EntityRepository; @@ -86,7 +86,7 @@ entities, ordered alphabetically by name. You can use this new method just like the default finder methods of the repository:: - use AppBundle\Entity\Product; + use App\Entity\Product; // ... public function listAction() diff --git a/doctrine/resolve_target_entity.rst b/doctrine/resolve_target_entity.rst index 9c5901b354d..4bf4aba7566 100644 --- a/doctrine/resolve_target_entity.rst +++ b/doctrine/resolve_target_entity.rst @@ -39,9 +39,9 @@ brevity) to explain how to set up and use the ``ResolveTargetEntityListener``. A Customer entity:: - // src/AppBundle/Entity/Customer.php + // src/Entity/Customer.php - namespace AppBundle\Entity; + namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Acme\CustomerBundle\Entity\Customer as BaseCustomer; @@ -118,7 +118,7 @@ about the replacement: orm: # ... resolve_target_entities: - Acme\InvoiceBundle\Model\InvoiceSubjectInterface: AppBundle\Entity\Customer + Acme\InvoiceBundle\Model\InvoiceSubjectInterface: App\Entity\Customer .. code-block:: xml @@ -135,7 +135,7 @@ about the replacement: - AppBundle\Entity\Customer + App\Entity\Customer @@ -144,7 +144,7 @@ about the replacement: // app/config/config.php use Acme\InvoiceBundle\Model\InvoiceSubjectInterface; - use AppBundle\Entity\Customer; + use App\Entity\Customer; $container->loadFromExtension('doctrine', array( 'orm' => array( diff --git a/doctrine/reverse_engineering.rst b/doctrine/reverse_engineering.rst index 1e82856bd48..c5263ce915b 100644 --- a/doctrine/reverse_engineering.rst +++ b/doctrine/reverse_engineering.rst @@ -60,7 +60,7 @@ table fields. $ php bin/console doctrine:mapping:import --force AppBundle xml This command line tool asks Doctrine to introspect the database and generate -the XML metadata files under the ``src/AppBundle/Resources/config/doctrine`` +the XML metadata files under the ``src/Resources/config/doctrine`` folder of your bundle. This generates two files: ``BlogPost.orm.xml`` and ``BlogComment.orm.xml``. @@ -75,7 +75,7 @@ The generated ``BlogPost.orm.xml`` metadata file looks as follows: - + @@ -101,8 +101,8 @@ entity classes by executing the following command. For example, the newly created ``BlogComment`` entity class looks as follow:: - // src/AppBundle/Entity/BlogComment.php - namespace AppBundle\Entity; + // src/Entity/BlogComment.php + namespace App\Entity; use Doctrine\ORM\Mapping as ORM; diff --git a/email.rst b/email.rst index 4ed365c673c..c03ad166a56 100644 --- a/email.rst +++ b/email.rst @@ -108,7 +108,7 @@ an email is pretty straightforward:: ->setTo('recipient@example.com') ->setBody( $this->renderView( - // app/Resources/views/Emails/registration.html.twig + // templates/Emails/registration.html.twig 'Emails/registration.html.twig', array('name' => $name) ), @@ -140,7 +140,7 @@ template might look something like this: .. code-block:: html+jinja - {# app/Resources/views/Emails/registration.html.twig #} + {# templates/Emails/registration.html.twig #}

You did it! You registered!

Hi {{ name }}! You're successfully registered. diff --git a/email/testing.rst b/email/testing.rst index 2403cfdde8e..acd4b7f66c8 100644 --- a/email/testing.rst +++ b/email/testing.rst @@ -29,7 +29,7 @@ In your functional test, use the ``swiftmailer`` collector on the profiler to get information about the messages sent on the previous request:: // tests/AppBundle/Controller/MailControllerTest.php - namespace Tests\AppBundle\Controller; + namespace Tests\App\Controller; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; diff --git a/event_dispatcher.rst b/event_dispatcher.rst index b21f34f1a54..f76fa6f8f09 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -23,8 +23,8 @@ Creating an Event Listener The most common way to listen to an event is to register an **event listener**:: - // src/AppBundle/EventListener/ExceptionListener.php - namespace AppBundle\EventListener; + // src/EventListener/ExceptionListener.php + namespace App\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpFoundation\Response; @@ -75,9 +75,9 @@ using a special "tag": .. code-block:: yaml - # app/config/services.yml + # app/config/services.yaml services: - AppBundle\EventListener\ExceptionListener: + App\EventListener\ExceptionListener: tags: - { name: kernel.event_listener, event: kernel.exception } @@ -92,7 +92,7 @@ using a special "tag": + class="App\EventListener\ExceptionListener"> @@ -102,7 +102,7 @@ using a special "tag": .. code-block:: php // app/config/services.php - use AppBundle\EventListener\ExceptionListener; + use App\EventListener\ExceptionListener; $container ->register('app.exception_listener', ExceptionListener::class) @@ -141,8 +141,8 @@ about event subscribers, read :doc:`/components/event_dispatcher`. The following example shows an event subscriber that defines several methods which listen to the same ``kernel.exception`` event:: - // src/AppBundle/EventSubscriber/ExceptionSubscriber.php - namespace AppBundle\EventSubscriber; + // src/EventSubscriber/ExceptionSubscriber.php + namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; @@ -178,7 +178,7 @@ listen to the same ``kernel.exception`` event:: } } -That's it! Your ``services.yml`` file should already be setup to load services from +That's it! Your ``services.yaml`` file should already be setup to load services from the ``EventSubscriber`` directory. Symfony takes care of the rest. .. _ref-event-subscriber-configuration: @@ -198,8 +198,8 @@ sub-requests - typically by :doc:`/templating/embedding_controllers`). For the c Symfony events, you might need to check to see if the event is for a "master" request or a "sub request":: - // src/AppBundle/EventListener/RequestListener.php - namespace AppBundle\EventListener; + // src/EventListener/RequestListener.php + namespace App\EventListener; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\HttpKernel; diff --git a/event_dispatcher/before_after_filters.rst b/event_dispatcher/before_after_filters.rst index 6e38cfe4846..bb1d7f2f755 100644 --- a/event_dispatcher/before_after_filters.rst +++ b/event_dispatcher/before_after_filters.rst @@ -81,7 +81,7 @@ some way to identify if the controller that matches the request needs token vali A clean and easy way is to create an empty interface and make the controllers implement it:: - namespace AppBundle\Controller; + namespace App\Controller; interface TokenAuthenticatedController { @@ -90,9 +90,9 @@ implement it:: A controller that implements this interface simply looks like this:: - namespace AppBundle\Controller; + namespace App\Controller; - use AppBundle\Controller\TokenAuthenticatedController; + use App\Controller\TokenAuthenticatedController; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class FooController extends Controller implements TokenAuthenticatedController @@ -111,10 +111,10 @@ Next, you'll need to create an event listener, which will hold the logic that you want to be executed before your controllers. If you're not familiar with event listeners, you can learn more about them at :doc:`/event_dispatcher`:: - // src/AppBundle/EventSubscriber/TokenSubscriber.php - namespace AppBundle\EventSubscriber; + // src/EventSubscriber/TokenSubscriber.php + namespace App\EventSubscriber; - use AppBundle\Controller\TokenAuthenticatedController; + use App\Controller\TokenAuthenticatedController; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -158,7 +158,7 @@ event listeners, you can learn more about them at :doc:`/event_dispatcher`:: } } -That's it! Your ``services.yml`` file should already be setup to load services from +That's it! Your ``services.yaml`` file should already be setup to load services from the ``EventSubscriber`` directory. Symfony takes care of the rest. Your ``TokenSubscriber`` ``onKernelController()`` method will be executed on each request. If the controller that is about to be executed implements ``TokenAuthenticatedController``, diff --git a/event_dispatcher/method_behavior.rst b/event_dispatcher/method_behavior.rst index 274f8f1983b..0577989350e 100644 --- a/event_dispatcher/method_behavior.rst +++ b/event_dispatcher/method_behavior.rst @@ -41,8 +41,8 @@ executed, and ``mailer.post_send`` after the method is executed. Each uses a custom Event class to communicate information to the listeners of the two events. For example, ``BeforeSendMailEvent`` might look like this:: - // src/AppBundle/Event/BeforeSendMailEvent.php - namespace AppBundle\Event; + // src/Event/BeforeSendMailEvent.php + namespace App\Event; use Symfony\Component\EventDispatcher\Event; @@ -80,8 +80,8 @@ events. For example, ``BeforeSendMailEvent`` might look like this:: And the ``AfterSendMailEvent`` even like this:: - // src/AppBundle/Event/AfterSendMailEvent.php - namespace AppBundle\Event; + // src/Event/AfterSendMailEvent.php + namespace App\Event; use Symfony\Component\EventDispatcher\Event; @@ -111,11 +111,11 @@ that information (e.g. ``setMessage()``). Now, you can create an event subscriber to hook into this event. For example, you could listen to the ``mailer.post_send`` event and change the method's return value:: - // src/AppBundle/EventSubscriber/MailPostSendSubscriber.php - namespace AppBundle\EventSubscriber; + // src/EventSubscriber/MailPostSendSubscriber.php + namespace App\EventSubscriber; use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use AppBundle\Event\AfterSendMailEvent; + use App\Event\AfterSendMailEvent; class MailPostSendSubscriber implements EventSubscriberInterface { diff --git a/form/action_method.rst b/form/action_method.rst index 5178a917887..bb99ab052e9 100644 --- a/form/action_method.rst +++ b/form/action_method.rst @@ -16,7 +16,7 @@ form, you can use ``setAction()`` and ``setMethod()``: .. code-block:: php-symfony // AppBundle/Controller/DefaultController.php - namespace AppBundle\Controller; + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Form\Extension\Core\Type\DateType; @@ -76,10 +76,10 @@ options: .. code-block:: php-symfony // AppBundle/Controller/DefaultController.php - namespace AppBundle\Controller; + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; - use AppBundle\Form\TaskType; + use App\Form\TaskType; class DefaultController extends Controller { @@ -99,7 +99,7 @@ options: .. code-block:: php-standalone use Symfony\Component\Form\Forms; - use AppBundle\Form\TaskType; + use App\Form\TaskType; $formFactoryBuilder = Forms::createFormFactoryBuilder(); @@ -119,12 +119,12 @@ to the ``form()`` or the ``form_start()`` helper functions: .. code-block:: html+twig - {# app/Resources/views/default/new.html.twig #} + {# templates/default/new.html.twig #} {{ form_start(form, {'action': path('target_route'), 'method': 'GET'}) }} .. code-block:: html+php - + start($form, array( // The path() method was introduced in Symfony 2.8. Prior to 2.8, // you had to use generate(). diff --git a/form/create_custom_field_type.rst b/form/create_custom_field_type.rst index 7860ef75f3c..40c223f8267 100644 --- a/form/create_custom_field_type.rst +++ b/form/create_custom_field_type.rst @@ -19,8 +19,8 @@ will be called ``ShippingType`` and the file will be stored in the default locat for form fields, which is ``\Form\Type``. Make sure the field extends :class:`Symfony\\Component\\Form\\AbstractType`:: - // src/AppBundle/Form/Type/ShippingType.php - namespace AppBundle\Form\Type; + // src/Form/Type/ShippingType.php + namespace App\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -120,7 +120,7 @@ link for details), create a ``shipping_widget`` block to handle this: .. code-block:: html+twig - {# app/Resources/views/form/fields.html.twig #} + {# templates/form/fields.html.twig #} {% block shipping_widget %} {% spaceless %} {% if expanded %} @@ -141,7 +141,7 @@ link for details), create a ``shipping_widget`` block to handle this: .. code-block:: html+php - +
    block($form, 'widget_container_attributes') ?>> @@ -251,12 +251,12 @@ Using the Field Type You can now use your custom field type immediately, simply by creating a new instance of the type in one of your forms:: - // src/AppBundle/Form/Type/OrderType.php - namespace AppBundle\Form\Type; + // src/Form/Type/OrderType.php + namespace App\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; - use AppBundle\Form\Type\ShippingType; + use App\Form\Type\ShippingType; class OrderType extends AbstractType { @@ -281,8 +281,8 @@ Accessing Services and Config If you need to access :doc:`services ` from your form class, add a ``__construct()`` method like normal:: - // src/AppBundle/Form/Type/ShippingType.php - namespace AppBundle\Form\Type; + // src/Form/Type/ShippingType.php + namespace App\Form\Type; // ... use Doctrine\ORM\EntityManagerInterface; @@ -299,7 +299,7 @@ add a ``__construct()`` method like normal:: // use $this->em down anywhere you want ... } -If you're using the default ``services.yml`` configuration (i.e. services from the +If you're using the default ``services.yaml`` configuration (i.e. services from the ``Form/`` are loaded and ``autoconfigure`` is enabled), this will already work! See :ref:`service-container-creating-service` for more details. diff --git a/form/create_form_type_extension.rst b/form/create_form_type_extension.rst index 0e730ad126e..d2ef0bea408 100644 --- a/form/create_form_type_extension.rst +++ b/form/create_form_type_extension.rst @@ -24,8 +24,8 @@ Defining the Form Type Extension First, create the form type extension class:: - // src/AppBundle/Form/Extension/ImageTypeExtension.php - namespace AppBundle\Form\Extension; + // src/Form/Extension/ImageTypeExtension.php + namespace App\Form\Extension; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\Core\Type\FileType; @@ -74,7 +74,7 @@ your class as a service and using the ``form.type_extension`` tag: services: # ... - AppBundle\Form\Extension\ImageTypeExtension: + App\Form\Extension\ImageTypeExtension: tags: - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FileType } @@ -87,7 +87,7 @@ your class as a service and using the ``form.type_extension`` tag: http://symfony.com/schema/dic/services/services-1.0.xsd"> - + @@ -95,7 +95,7 @@ your class as a service and using the ``form.type_extension`` tag: .. code-block:: php - use AppBundle\Form\Extension\ImageTypeExtension; + use App\Form\Extension\ImageTypeExtension; use Symfony\Component\Form\Extension\Core\Type\FileType; $container->autowire(ImageTypeExtension::class) @@ -134,8 +134,8 @@ you use an approach similar to the one described in you have a Media model with a path property, corresponding to the image path in the database:: - // src/AppBundle/Entity/Media.php - namespace AppBundle\Entity; + // src/Entity/Media.php + namespace App\Entity; use Symfony\Component\Validator\Constraints as Assert; @@ -167,8 +167,8 @@ the ``FileType::class`` form type: For example:: - // src/AppBundle/Form/Extension/ImageTypeExtension.php - namespace AppBundle\Form\Extension; + // src/Form/Extension/ImageTypeExtension.php + namespace App\Form\Extension; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\FormView; @@ -256,8 +256,8 @@ From now on, when adding a field of type ``FileType::class`` to your form, you c specify an ``image_property`` option that will be used to display an image next to the file field. For example:: - // src/AppBundle/Form/Type/MediaType.php - namespace AppBundle\Form\Type; + // src/Form/Type/MediaType.php + namespace App\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; diff --git a/form/csrf_protection.rst b/form/csrf_protection.rst index 266555579c0..f06b7cf3947 100644 --- a/form/csrf_protection.rst +++ b/form/csrf_protection.rst @@ -31,7 +31,7 @@ that all un-rendered fields are output. The CSRF token can be customized on a form-by-form basis. For example:: // ... - use AppBundle\Entity\Task; + use App\Entity\Task; use Symfony\Component\OptionsResolver\OptionsResolver; class TaskType extends AbstractType diff --git a/form/data_based_validation.rst b/form/data_based_validation.rst index 3e31be7cd67..c8a74bb99f3 100644 --- a/form/data_based_validation.rst +++ b/form/data_based_validation.rst @@ -8,7 +8,7 @@ If you need some advanced logic to determine the validation groups (e.g. based on submitted data), you can set the ``validation_groups`` option to an array callback:: - use AppBundle\Entity\Client; + use App\Entity\Client; use Symfony\Component\OptionsResolver\OptionsResolver; // ... @@ -27,7 +27,7 @@ This will call the static method ``determineValidationGroups()`` on the The Form object is passed as an argument to that method (see next example). You can also define whole logic inline by using a ``Closure``:: - use AppBundle\Entity\Client; + use App\Entity\Client; use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -51,7 +51,7 @@ Using the ``validation_groups`` option overrides the default validation group which is being used. If you want to validate the default constraints of the entity as well you have to adjust the option as follows:: - use AppBundle\Entity\Client; + use App\Entity\Client; use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; diff --git a/form/data_transformers.rst b/form/data_transformers.rst index 08390909d9c..248001d7697 100644 --- a/form/data_transformers.rst +++ b/form/data_transformers.rst @@ -23,10 +23,10 @@ Simple Example: Transforming String Tags from User Input to an Array Suppose you have a Task form with a tags ``text`` type:: - // src/AppBundle/Form/Type/TaskType.php - namespace AppBundle\Form\Type; + // src/Form/Type/TaskType.php + namespace App\Form\Type; - use AppBundle\Entity\Task; + use App\Entity\Task; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -56,8 +56,8 @@ This is a *perfect* time to attach a custom data transformer to the ``tags`` field. The easiest way to do this is with the :class:`Symfony\\Component\\Form\\CallbackTransformer` class:: - // src/AppBundle/Form/Type/TaskType.php - namespace AppBundle\Form\Type; + // src/Form/Type/TaskType.php + namespace App\Form\Type; use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\FormBuilderInterface; @@ -120,10 +120,10 @@ issue number. Start by setting up the text field like normal:: - // src/AppBundle/Form/Type/TaskType.php - namespace AppBundle\Form\Type; + // src/Form/Type/TaskType.php + namespace App\Form\Type; - use AppBundle\Entity\Task; + use App\Entity\Task; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -161,10 +161,10 @@ complex, creating a new transformer class will keep the ``TaskType`` form class Create an ``IssueToNumberTransformer`` class: it will be responsible for converting to and from the issue number and the ``Issue`` object:: - // src/AppBundle/Form/DataTransformer/IssueToNumberTransformer.php - namespace AppBundle\Form\DataTransformer; + // src/Form/DataTransformer/IssueToNumberTransformer.php + namespace App\Form\DataTransformer; - use AppBundle\Entity\Issue; + use App\Entity\Issue; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Exception\TransformationFailedException; @@ -250,10 +250,10 @@ Next, you need to use the ``IssueToNumberTransformer`` object inside if ``TaskTy and add it to the ``issue`` field. No problem! Just add a ``__construct()`` method and type-hint the new class:: - // src/AppBundle/Form/Type/TaskType.php - namespace AppBundle\Form\Type; + // src/Form/Type/TaskType.php + namespace App\Form\Type; - use AppBundle\Form\DataTransformer\IssueToNumberTransformer; + use App\Form\DataTransformer\IssueToNumberTransformer; use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -332,10 +332,10 @@ that does this automatically. First, create the custom field type class:: - // src/AppBundle/Form/IssueSelectorType.php - namespace AppBundle\Form; + // src/Form/IssueSelectorType.php + namespace App\Form; - use AppBundle\Form\DataTransformer\IssueToNumberTransformer; + use App\Form\DataTransformer\IssueToNumberTransformer; use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -374,10 +374,10 @@ have the data transformer *and* a nice default value for the ``invalid_message`` As long as you're using :ref:`autowire ` and :ref:`autoconfigure `, you can start using the form immediately:: - // src/AppBundle/Form/Type/TaskType.php - namespace AppBundle\Form\Type; + // src/Form/Type/TaskType.php + namespace App\Form\Type; - use AppBundle\Form\DataTransformer\IssueToNumberTransformer; + use App\Form\DataTransformer\IssueToNumberTransformer; use Symfony\Component\Form\Extension\Core\Type\TextareaType; // ... diff --git a/form/dynamic_form_modification.rst b/form/dynamic_form_modification.rst index d4e216c1175..bb64ef3a938 100644 --- a/form/dynamic_form_modification.rst +++ b/form/dynamic_form_modification.rst @@ -35,10 +35,10 @@ Customizing your Form Based on the Underlying Data Before starting with dynamic form generation, remember what a bare form class looks like:: - // src/AppBundle/Form/Type/ProductType.php - namespace AppBundle\Form\Type; + // src/Form/Type/ProductType.php + namespace App\Form\Type; - use AppBundle\Entity\Product; + use App\Entity\Product; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -83,8 +83,8 @@ Adding an Event Listener to a Form Class So, instead of directly adding that ``name`` widget, the responsibility of creating that particular field is delegated to an event listener:: - // src/AppBundle/Form/Type/ProductType.php - namespace AppBundle\Form\Type; + // src/Form/Type/ProductType.php + namespace App\Form\Type; // ... use Symfony\Component\Form\FormEvent; @@ -142,8 +142,8 @@ For better reusability or if there is some heavy logic in your event listener, you can also move the logic for creating the ``name`` field to an :ref:`event subscriber `:: - // src/AppBundle/Form/EventListener/AddNameFieldSubscriber.php - namespace AppBundle\Form\EventListener; + // src/Form/EventListener/AddNameFieldSubscriber.php + namespace App\Form\EventListener; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; @@ -172,11 +172,11 @@ you can also move the logic for creating the ``name`` field to an Great! Now use that in your form class:: - // src/AppBundle/Form/Type/ProductType.php - namespace AppBundle\Form\Type; + // src/Form/Type/ProductType.php + namespace App\Form\Type; // ... - use AppBundle\Form\EventListener\AddNameFieldSubscriber; + use App\Form\EventListener\AddNameFieldSubscriber; class ProductType extends AbstractType { @@ -206,8 +206,8 @@ Creating the Form Type Using an event listener, your form might look like this:: - // src/AppBundle/Form/Type/FriendMessageFormType.php - namespace AppBundle\Form\Type; + // src/Form/Type/FriendMessageFormType.php + namespace App\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -260,9 +260,9 @@ Customizing the Form Type Now that you have all the basics in place you can take advantage of the ``TokenStorageInterface`` and fill in the listener logic:: - // src/AppBundle/Form/Type/FriendMessageFormType.php + // src/Form/Type/FriendMessageFormType.php - use AppBundle\Entity\User; + use App\Entity\User; use Doctrine\ORM\EntityRepository; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\Extension\Core\Type\TextType; @@ -376,8 +376,8 @@ will need the correct options in order for validation to pass. The meetup is passed as an entity field to the form. So we can access each sport like this:: - // src/AppBundle/Form/Type/SportMeetupType.php - namespace AppBundle\Form\Type; + // src/Form/Type/SportMeetupType.php + namespace App\Form\Type; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; @@ -442,13 +442,13 @@ new field automatically and map it to the submitted client data. The type would now look like:: - // src/AppBundle/Form/Type/SportMeetupType.php - namespace AppBundle\Form\Type; + // src/Form/Type/SportMeetupType.php + namespace App\Form\Type; // ... use Symfony\Component\Form\FormInterface; use Symfony\Bridge\Doctrine\Form\Type\EntityType; - use AppBundle\Entity\Sport; + use App\Entity\Sport; class SportMeetupType extends AbstractType { @@ -507,13 +507,13 @@ One piece that is still missing is the client-side updating of your form after the sport is selected. This should be handled by making an AJAX call back to your application. Assume that you have a sport meetup creation controller:: - // src/AppBundle/Controller/MeetupController.php - namespace AppBundle\Controller; + // src/Controller/MeetupController.php + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; - use AppBundle\Entity\SportMeetup; - use AppBundle\Form\Type\SportMeetupType; + use App\Entity\SportMeetup; + use App\Form\Type\SportMeetupType; // ... class MeetupController extends Controller @@ -543,7 +543,7 @@ field according to the current selection in the ``sport`` field: .. code-block:: html+twig - {# app/Resources/views/meetup/create.html.twig #} + {# templates/meetup/create.html.twig #} {{ form_start(form) }} {{ form_row(form.sport) }} {# + {{ form_end(form) }} Rendering the Form @@ -161,7 +152,7 @@ all of the fields: .. code-block:: html+twig - {{ form_start(form, {'attr': {'class': 'my-form-class'} }) }} + {{ form_start(form, {attr: {class: 'my-form-class'} }) }} {{ form_widget(form) }} {{ form_end(form) }} @@ -197,13 +188,8 @@ Handling a form submit usually follows a similar template: // render the template } -There are really only two notable things here. First, we recommend that you -use a single action for both rendering the form and handling the form submit. -For example, you *could* have a ``newAction()`` that *only* renders the form -and a ``createAction()`` that *only* processes the form submit. Both those -actions will be almost identical. So it's much simpler to let ``newAction()`` -handle everything. - -Second, is it required to call ``$form->isSubmitted()`` in the ``if`` statement -before calling ``isValid()``. Calling ``isValid()`` with an unsubmitted form -is deprecated since version 3.2 and will throw an exception in 4.0. +We recommend that you use a single action for both rendering the form and +handling the form submit. For example, you *could* have a ``newAction()`` that +*only* renders the form and a ``createAction()`` that *only* processes the form +submit. Both those actions will be almost identical. So it's much simpler to let +``newAction()`` handle everything. diff --git a/best_practices/i18n.rst b/best_practices/i18n.rst index 39473373df1..362af65bfa0 100644 --- a/best_practices/i18n.rst +++ b/best_practices/i18n.rst @@ -3,20 +3,18 @@ Internationalization Internationalization and localization adapt the applications and their contents to the specific region or language of the users. In Symfony this is an opt-in -feature that needs to be enabled before using it. To do this, uncomment the -following ``translator`` configuration option and set your application locale: +feature that needs to be installed before using it (``composer require translation``). -.. code-block:: yaml +Translation Source File Location +-------------------------------- + +.. best-practice:: - # app/config/config.yml - framework: - # ... - translator: { fallbacks: ['%locale%'] } + Store the translation files in the ``translations/`` directory at the root + of your project. - # app/config/parameters.yml - parameters: - # ... - locale: en +Your translators' lives will be much easier if all the application translations +are in one central location. Translation Source File Format ------------------------------ @@ -42,21 +40,6 @@ XLIFF notes allow you to define that context. viewing and editing these translation files. It also has advanced extractors that can read your project and automatically update the XLIFF files. -Translation Source File Location --------------------------------- - -.. best-practice:: - - Store the translation files in the ``app/Resources/translations/`` - directory. - -Traditionally, Symfony developers have created these files in the -``Resources/translations/`` directory of each bundle. But since the -``app/Resources/`` directory is considered the global location for the -application's resources, storing translations in ``app/Resources/translations/`` -centralizes them *and* gives them priority over any other translation file. -This let's you override translations defined in third-party bundles. - Translation Keys ---------------- @@ -64,8 +47,8 @@ Translation Keys Always use keys for translations instead of content strings. -Using keys simplifies the management of the translation files because you -can change the original contents without having to update all of the translation +Using keys simplifies the management of the translation files because you can +change the original contents without having to update all of the translation files. Keys should always describe their *purpose* and *not* their location. For @@ -80,7 +63,7 @@ English in the application would be: .. code-block:: xml - + diff --git a/best_practices/introduction.rst b/best_practices/introduction.rst index 4260b79fd1a..c0507a08af6 100644 --- a/best_practices/introduction.rst +++ b/best_practices/introduction.rst @@ -58,8 +58,8 @@ Who this Book Is for (Hint: It's not a Tutorial) Any Symfony developer, whether you are an expert or a newcomer, can read this guide. But since this isn't a tutorial, you'll need some basic knowledge of -Symfony to follow everything. If you are totally new to Symfony, welcome! -Start with :doc:`The Quick Tour ` tutorial first. +Symfony to follow everything. If you are totally new to Symfony, welcome! and +read the :doc:`Getting Started guides ` first. We've deliberately kept this guide short. We won't repeat explanations that you can find in the vast Symfony documentation, like discussions about Dependency @@ -69,14 +69,13 @@ what you already know. The Application --------------- -In addition to this guide, a sample application has been developed with all these -best practices in mind. This project, called the Symfony Demo application, can -be obtained through the Symfony Installer. First, `download and install`_ the -installer and then execute this command to download the demo application: +In addition to this guide, a sample application called `Symfony Demo`_ has been +developed with all these best practices in mind. Execute this command to download +the demo application: .. code-block:: terminal - $ symfony demo + $ composer create-project symfony/symfony-demo **The demo application is a simple blog engine**, because that will allow us to focus on the Symfony concepts and features without getting buried in difficult @@ -87,9 +86,10 @@ Don't Update Your Existing Applications --------------------------------------- After reading this handbook, some of you may be considering refactoring your -existing Symfony applications. Our recommendation is sound and clear: **you -should not refactor your existing applications to comply with these best -practices**. The reasons for not doing it are various: +existing Symfony applications. Our recommendation is sound and clear: you may +use these best practices for **new applications** but **you should not refactor +your existing applications to comply with these best practices**. The reasons +for not doing it are various: * Your existing applications are not wrong, they just follow another set of guidelines; @@ -99,4 +99,4 @@ practices**. The reasons for not doing it are various: your tests or adding features that provide real value to the end users. .. _`Fabien Potencier`: https://connect.sensiolabs.com/profile/fabpot -.. _`download and install`: https://symfony.com/download +.. _`Symfony Demo`: https://github.com/symfony/demo diff --git a/best_practices/security.rst b/best_practices/security.rst index ece701c78bf..a83e5efacaf 100644 --- a/best_practices/security.rst +++ b/best_practices/security.rst @@ -6,8 +6,7 @@ Authentication and Firewalls (i.e. Getting the User's Credentials) You can configure Symfony to authenticate your users using any method you want and to load user information from any source. This is a complex topic, but -the :doc:`Security guide` has a lot of information about -this. +the :doc:`Security guide ` has a lot of information about this. Regardless of your needs, authentication is configured in ``security.yaml``, primarily under the ``firewalls`` key. @@ -30,9 +29,9 @@ site (or maybe nearly *all* sections), use the ``access_control`` area. .. best-practice:: - Use the ``bcrypt`` encoder for encoding your users' passwords. + Use the ``bcrypt`` encoder for hashing your users' passwords. -If your users have a password, then we recommend encoding it using the ``bcrypt`` +If your users have a password, then we recommend hashing it using the ``bcrypt`` encoder, instead of the traditional SHA-512 hashing encoder. The main advantages of ``bcrypt`` are the inclusion of a *salt* value to protect against rainbow table attacks, and its adaptive nature, which allows to make it slower to @@ -83,17 +82,15 @@ service directly. * For protecting broad URL patterns, use ``access_control``; * Whenever possible, use the ``@Security`` annotation; - * Check security directly on the ``security.authorization_checker`` service whenever - you have a more complex situation. + * Check security directly on the ``security.authorization_checker`` service + whenever you have a more complex situation. There are also different ways to centralize your authorization logic, like -with a custom security voter or with ACL. +with a custom security voter: .. best-practice:: - * For fine-grained restrictions, define a custom security voter; - * For restricting access to *any* object by *any* user via an admin - interface, use the Symfony ACL. + Define a custom security voter to implement fine-grained restrictions. .. _best-practices-security-annotation: @@ -253,10 +250,10 @@ more advanced use-case, you can always do the same security check in PHP: Security Voters --------------- -If your security logic is complex and can't be centralized into a method -like ``isAuthor()``, you should leverage custom voters. These are an order -of magnitude easier than :doc:`ACLs ` and will give -you the flexibility you need in almost all cases. +If your security logic is complex and can't be centralized into a method like +``isAuthor()``, you should leverage custom voters. These are much easier than +:doc:`ACLs ` and will give you the flexibility you need in almost +all cases. First, create a voter class. The following example shows a voter that implements the same ``getAuthorEmail()`` logic you used above: @@ -276,9 +273,6 @@ the same ``getAuthorEmail()`` logic you used above: const CREATE = 'create'; const EDIT = 'edit'; - /** - * @var AccessDecisionManagerInterface - */ private $decisionManager; public function __construct(AccessDecisionManagerInterface $decisionManager) @@ -310,15 +304,16 @@ the same ``getAuthorEmail()`` logic you used above: } switch ($attribute) { + // if the user is an admin, allow them to create new posts case self::CREATE: - // if the user is an admin, allow them to create new posts if ($this->decisionManager->decide($token, array('ROLE_ADMIN'))) { return true; } break; + + // if the user is the author of the post, allow them to edit the posts case self::EDIT: - // if the user is the author of the post, allow them to edit the posts if ($user->getEmail() === $post->getAuthorEmail()) { return true; } diff --git a/best_practices/templates.rst b/best_practices/templates.rst index 0a45d7b7351..8be12063059 100644 --- a/best_practices/templates.rst +++ b/best_practices/templates.rst @@ -9,7 +9,7 @@ languages - like `Twig`_ - were created to make templating even better. Use Twig templating format for your templates. -Generally speaking, PHP templates are much more verbose than Twig templates because +Generally speaking, PHP templates are more verbose than Twig templates because they lack native support for lots of modern features needed by templates, like inheritance, automatic escaping and named arguments for filters and functions. @@ -18,10 +18,6 @@ Twig is the default templating format in Symfony and has the largest community support of all non-PHP template engines (it's used in high profile projects such as Drupal 8). -In addition, Twig is the only template format with guaranteed support in Symfony -3.0. As a matter of fact, PHP may be removed from the officially supported -template engines. - Template Locations ------------------ @@ -58,7 +54,7 @@ Twig Extensions .. best-practice:: - Define your Twig extensions in the ``AppBundle/Twig/`` directory. Your + Define your Twig extensions in the ``src/Twig/`` directory. Your application will automatically detect them and configure them. Our application needs a custom ``md2html`` Twig filter so that we can transform @@ -95,16 +91,18 @@ Markdown content into HTML:: } Next, create a new Twig extension and define a new filter called ``md2html`` -using the ``Twig_SimpleFilter`` class. Inject the newly defined ``Markdown`` -class in the constructor of the Twig extension: +using the ``TwigFilter`` class. Inject the newly defined ``Markdown`` class in +the constructor of the Twig extension: .. code-block:: php namespace App\Twig; use App\Utils\Markdown; + use Twig\Extension\AbstractExtension; + use Twig\TwigFilter; - class AppExtension extends \Twig_Extension + class AppExtension extends AbstractExtension { private $parser; @@ -115,29 +113,23 @@ class in the constructor of the Twig extension: public function getFilters() { - return array( - new \Twig_SimpleFilter( - 'md2html', - array($this, 'markdownToHtml'), - array('is_safe' => array('html'), 'pre_escape' => 'html') - ), - ); + return [ + new TwigFilter('md2html', [$this, 'markdownToHtml'], [ + 'is_safe' => ['html'], + 'pre_escape' => 'html', + ]), + ]; } public function markdownToHtml($content) { return $this->parser->toHtml($content); } - - public function getName() - { - return 'app_extension'; - } } And that's it! -If you're using the :ref:`default services.yml configuration `, +If you're using the :ref:`default services.yaml configuration `, you're done! Symfony will automatically know about your new service and tag it to be used as a Twig extension. diff --git a/best_practices/tests.rst b/best_practices/tests.rst index ace92cb5fe5..91e33d02818 100644 --- a/best_practices/tests.rst +++ b/best_practices/tests.rst @@ -1,10 +1,11 @@ Tests ===== -Roughly speaking, there are two types of test. Unit testing allows you to -test the input and output of specific functions. Functional testing allows -you to command a "browser" where you browse to pages on your site, click -links, fill out forms and assert that you see certain things on the page. +Of all the different types of test available, these best practices focus solely +on unit and functional tests. Unit testing allows you to test the input and +output of specific functions. Functional testing allows you to command a +"browser" where you browse to pages on your site, click links, fill out forms +and assert that you see certain things on the page. Unit Tests ---------- @@ -48,14 +49,12 @@ A functional test can be as easy as this:: public function urlProvider() { - return array( - array('/'), - array('/posts'), - array('/post/fixture-post-1'), - array('/blog/category/fixture-category'), - array('/archives'), - // ... - ); + yield ['/']; + yield ['/posts']; + yield ['/post/fixture-post-1']; + yield ['/blog/category/fixture-category']; + yield ['/archives']; + yield [.]; } } @@ -84,10 +83,13 @@ generate the URL of the tested page: .. code-block:: php + // ... + private $router; // consider that this holds the Symfony router service + public function testBlogArchives() { $client = self::createClient(); - $url = $client->getContainer()->get('router')->generate('blog_archives'); + $url = $this->router->generate('blog_archives'); $client->request('GET', $url); // ... @@ -105,7 +107,7 @@ The built-in functional testing client is great, but it can't be used to test any JavaScript behavior on your pages. If you need to test this, consider using the `Mink`_ library from within PHPUnit. -Of course, if you have a heavy JavaScript frontend, you should consider using +Of course, if you have a heavy JavaScript front-end, you should consider using pure JavaScript-based testing tools. Learn More about Functional Tests diff --git a/best_practices/web-assets.rst b/best_practices/web-assets.rst index c7ab18e2114..dbff85d34e6 100644 --- a/best_practices/web-assets.rst +++ b/best_practices/web-assets.rst @@ -2,97 +2,29 @@ Web Assets ========== Web assets are things like CSS, JavaScript and image files that make the -frontend of your site look and work great. Symfony developers have traditionally -stored these assets in the ``Resources/public/`` directory of each bundle. +frontend of your site look and work great. .. best-practice:: - Store your assets in the ``public/`` directory. + Store your assets in the ``assets/`` directory at the root of your project. -Scattering your web assets across tens of different bundles makes it more -difficult to manage them. Your designers' lives will be much easier if all -the application assets are in one location. - -Templates also benefit from centralizing your assets, because the links are -much more concise: - -.. code-block:: html+twig - - - - - {# ... #} - - - - -.. note:: - - Keep in mind that ``public/`` is a public directory and that anything stored - here will be publicly accessible, including all the original asset files - (e.g. Sass, LESS and CoffeeScript files). - -Using Assetic -------------- - -.. include:: /assetic/_standard_edition_warning.rst.inc - -These days, you probably can't simply create static CSS and JavaScript files -and include them in your template. Instead, you'll probably want to combine -and minify these to improve client-side performance. You may also want to -use LESS or Sass (for example), which means you'll need some way to process -these into CSS files. - -A lot of tools exist to solve these problems, including pure-frontend (non-PHP) -tools like GruntJS. +Your designers' and front-end developers' lives will be much easier if all the +application assets are in one central location. .. best-practice:: - Use Assetic to compile, combine and minimize web assets, unless you're - comfortable with frontend tools like GruntJS. - -:doc:`Assetic ` is an asset manager capable -of compiling assets developed with a lot of different frontend technologies -like LESS, Sass and CoffeeScript. Combining all your assets with Assetic is a -matter of wrapping all the assets with a single Twig tag: - -.. code-block:: html+twig - - {% stylesheets - 'css/bootstrap.min.css' - 'css/main.css' - filter='cssrewrite' output='css/compiled/app.css' %} - - {% endstylesheets %} - - {# ... #} - - {% javascripts - 'js/jquery.min.js' - 'js/bootstrap.min.js' - output='js/compiled/app.js' %} - - {% endjavascripts %} - -Frontend-Based Applications ---------------------------- - -Recently, frontend technologies like AngularJS have become pretty popular -for developing frontend web applications that talk to an API. - -If you are developing an application like this, you should use the tools -that are recommended by the technology, such as Bower and GruntJS. You should -develop your frontend application separately from your Symfony backend (even -separating the repositories if you want). + Use `Webpack Encore`_ to compile, combine and minimize web assets. -Learn More about Assetic ------------------------- +`Webpack`_ is the leading JavaScript module bundler that compiles, transforms +and packages assets for usage in a browser. Webpack Encore is a JavaScript +library that gets rid of most of Webpack complexity without hiding any of its +features or distorting its usage and philosophy. -Assetic can also minimize CSS and JavaScript assets -:doc:`using UglifyCSS/UglifyJS ` to speed up your -websites. You can even :doc:`compress images ` -with Assetic to reduce their size before serving them to the user. Check out -the `official Assetic documentation`_ to learn more about all the available +Webpack Encore was designed to bridge the gap between Symfony applications and +the JavaScript-based tools used in modern web applications. Check out the +`official Webpack Encore documentation`_ to learn more about all the available features. -.. _`official Assetic documentation`: https://github.com/kriswallsmith/assetic +.. _`Webpack Encore`: https://github.com/symfony/webpack-encore +.. _`Webpack`: https://webpack.js.org/ +.. _`official Webpack Encore documentation`: https://symfony.com/doc/current/frontend.html From 9794c0b91b1adb16dab978a61c981dae77f8b3d8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 8 Nov 2017 10:24:24 +0100 Subject: [PATCH 0029/2437] Updated more contents --- best_practices/business-logic.rst | 35 ++++++------ best_practices/controllers.rst | 72 ++++++++++++++----------- best_practices/creating-the-project.rst | 13 ++++- best_practices/forms.rst | 27 +++++----- best_practices/security.rst | 16 +++--- best_practices/templates.rst | 64 +++++++--------------- best_practices/tests.rst | 2 +- 7 files changed, 113 insertions(+), 116 deletions(-) diff --git a/best_practices/business-logic.rst b/best_practices/business-logic.rst index 60587fb951e..8694a248511 100644 --- a/best_practices/business-logic.rst +++ b/best_practices/business-logic.rst @@ -25,15 +25,24 @@ Inside here, you can create whatever directories you want to organize things: ├─ var/ └─ vendor/ -Services: Naming and Format ---------------------------- +.. _services-naming-and-format: -The blog application needs a utility that can transform a post title (e.g. -"Hello World") into a slug (e.g. "hello-world"). The slug will be used as -part of the post URL. +Services: Naming and Configuration +---------------------------------- + +.. best-practice:: + + Use autowiring to automate the configuration of application services. -Let's create a new ``Slugger`` class inside ``src/Utils/`` and add the following -``slugify()`` method: +:doc:`Service autowiring ` is a feature provided +by Symfony's Service Container to manage services with minimal configuration. +It reads the type-hints on your constructor (or other methods) and automatically +passes you the correct services. It can also add :doc:`service tags ` +to the services needed them, such as Twig extensions, event subscribers, etc. + +The blog application needs a utility that can transform a post title (e.g. +"Hello World") into a slug (e.g. "hello-world") to include it as part of the +post URL. Let's create a new ``Slugger`` class inside ``src/Utils/``: .. code-block:: php @@ -42,11 +51,9 @@ Let's create a new ``Slugger`` class inside ``src/Utils/`` and add the following class Slugger { - public function slugify($string) + public function slugify(string $value): string { - return preg_replace( - '/[^a-z0-9]/', '-', strtolower(trim(strip_tags($string))) - ); + // ... } } @@ -71,14 +78,10 @@ such as the ``AdminController``: use App\Utils\Slugger; - public function createAction(Request $request, Slugger $slugger) + public function create(Request $request, Slugger $slugger) { // ... - // you can also fetch a public service like this - // but fetching services in this way is not considered a best practice - // $slugger = $this->get(Slugger::class); - if ($form->isSubmitted() && $form->isValid()) { $slug = $slugger->slugify($post->getTitle()); $post->setSlug($slug); diff --git a/best_practices/controllers.rst b/best_practices/controllers.rst index 6eb25d03c4f..bf563380402 100644 --- a/best_practices/controllers.rst +++ b/best_practices/controllers.rst @@ -5,16 +5,15 @@ Symfony follows the philosophy of *"thin controllers and fat models"*. This means that controllers should hold just the thin layer of *glue-code* needed to coordinate the different parts of the application. -As a rule of thumb, you should follow the 5-10-20 rule, where controllers should -only define 5 variables or less, contain 10 actions or less and include 20 lines -of code or less in each action. This isn't an exact science, but it should -help you realize when code should be refactored out of the controller and -into a service. +Your controller methods should just call to other services, trigger some events +if needed and then return a response, but they should not contain any actual +business logic. If they do, refactor it out of the controller and into a service. .. best-practice:: - Make your controller extend the FrameworkBundle base controller and use - annotations to configure routing, caching and security whenever possible. + Make your controller extend the ``AbstractController`` base controller + provided by Symfony and use annotations to configure routing, caching and + security whenever possible. Coupling the controllers to the underlying framework allows you to leverage all of its features and increases your productivity. @@ -33,6 +32,18 @@ Overall, this means you should aggressively decouple your business logic from the framework while, at the same time, aggressively coupling your controllers and routing *to* the framework in order to get the most out of it. +Controller Action Naming +------------------------ + +.. best-practice:: + + Don't add the ``Action`` suffix to the methods of the controller actions. + +The first Symfony versions required that controller method names ended in +``Action`` (e.g. ``newAction()``, ``showAction()``). This suffix became optional +when annotations were introduced for controllers. In modern Symfony applications +this suffix is neither required nor recommended, so you can safely remove it. + Routing Configuration --------------------- @@ -94,32 +105,32 @@ for the homepage of our app: namespace App\Controller; use App\Entity\Post; - use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Routing\Annotation\Route; - class DefaultController extends Controller + class DefaultController extends AbstractController { /** * @Route("/", name="homepage") */ - public function indexAction() + public function index() { $posts = $this->getDoctrine() ->getRepository(Post::class) ->findLatest(); - return $this->render('default/index.html.twig', array( + return $this->render('default/index.html.twig', [ 'posts' => $posts, - )); + ]); } } Fetching Services ----------------- -If you extend the base ``Controller`` class, you can access services directly from -the container via ``$this->container->get()`` or ``$this->get()``. But instead, you -should use dependency injection to fetch services: most easily done by +If you extend the base ``AbstractController`` class, you can't access services +directly from the container via ``$this->container->get()`` or ``$this->get()``. +Instead, you must use dependency injection to fetch services: most easily done by :ref:`type-hinting action method arguments `: .. best-practice:: @@ -153,40 +164,41 @@ For example: /** * @Route("/{id}", name="admin_post_show") */ - public function showAction(Post $post) + public function show(Post $post) { $deleteForm = $this->createDeleteForm($post); - return $this->render('admin/post/show.html.twig', array( + return $this->render('admin/post/show.html.twig', [ 'post' => $post, 'delete_form' => $deleteForm->createView(), - )); + ]); } -Normally, you'd expect a ``$id`` argument to ``showAction()``. Instead, by -creating a new argument (``$post``) and type-hinting it with the ``Post`` -class (which is a Doctrine entity), the ParamConverter automatically queries -for an object whose ``$id`` property matches the ``{id}`` value. It will -also show a 404 page if no ``Post`` can be found. +Normally, you'd expect a ``$id`` argument to ``show()``. Instead, by creating a +new argument (``$post``) and type-hinting it with the ``Post`` class (which is a +Doctrine entity), the ParamConverter automatically queries for an object whose +``$id`` property matches the ``{id}`` value. It will also show a 404 page if no +``Post`` can be found. When Things Get More Advanced ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The above example works without any configuration because the wildcard name ``{id}`` matches -the name of the property on the entity. If this isn't true, or if you have -even more complex logic, the easiest thing to do is just query for the entity -manually. In our application, we have this situation in ``CommentController``: +The above example works without any configuration because the wildcard name +``{id}`` matches the name of the property on the entity. If this isn't true, or +if you have even more complex logic, the easiest thing to do is just query for +the entity manually. In our application, we have this situation in +``CommentController``: .. code-block:: php /** * @Route("/comment/{postSlug}/new", name = "comment_new") */ - public function newAction(Request $request, $postSlug) + public function new(Request $request, $postSlug) { $post = $this->getDoctrine() ->getRepository(Post::class) - ->findOneBy(array('slug' => $postSlug)); + ->findOneBy(['slug' => $postSlug]); if (!$post) { throw $this->createNotFoundException(); @@ -209,7 +221,7 @@ flexible: * @Route("/comment/{postSlug}/new", name = "comment_new") * @ParamConverter("post", options={"mapping": {"postSlug": "slug"}}) */ - public function newAction(Request $request, Post $post) + public function new(Request $request, Post $post) { // ... } diff --git a/best_practices/creating-the-project.rst b/best_practices/creating-the-project.rst index fb35f1f83ef..a054f293938 100644 --- a/best_practices/creating-the-project.rst +++ b/best_practices/creating-the-project.rst @@ -6,9 +6,18 @@ Installing Symfony .. best-practice:: - Use the `Symfony Skeleton`_ and `Composer`_ to create new Symfony-based projects. + Use Composer and Symfony Flex to create and manage Symfony applications. -The **Symfony Skeleton** is a minimal and empty Symfony project which you can +`Composer`_ is the package manager used by modern PHP application to manage their +dependencies. `Symfony Flex`_ is a Composer plugin designed to automatize some +of the most common tasks performed in Symfony applications. Using Flex is optional +but recommended because it improves your productivity significantly. + +.. best-practice:: + + Use the Symfony Skeleton to create new Symfony-based projects. + +The `Symfony Skeleton`_ is a minimal and empty Symfony project which you can base your new projects on. Unlike past Symfony versions, this skeleton installs the absolute bare minimum amount of dependencies to make a fully working Symfony project. Read the :doc:`/setup` article to learn more about installing Symfony. diff --git a/best_practices/forms.rst b/best_practices/forms.rst index 62eb8a45233..17c3a3ebe16 100644 --- a/best_practices/forms.rst +++ b/best_practices/forms.rst @@ -42,9 +42,9 @@ PHP class:: public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( + $resolver->setDefaults([ 'data_class' => Post::class, - )); + ]); } } @@ -59,7 +59,7 @@ To use the class, use ``createForm()`` and pass the fully qualified class name:: use App\Form\PostType; // ... - public function newAction(Request $request) + public function new(Request $request) { $post = new Post(); $form = $this->createForm(PostType::class, $post); @@ -113,14 +113,14 @@ some developers configure form buttons in the controller:: { // ... - public function newAction(Request $request) + public function new(Request $request) { $post = new Post(); $form = $this->createForm(PostType::class, $post); - $form->add('submit', SubmitType::class, array( + $form->add('submit', SubmitType::class, [ 'label' => 'Create', 'attr' => ['class' => 'btn btn-default pull-right'], - )); + ]); // ... } @@ -168,7 +168,7 @@ Handling a form submit usually follows a similar template: .. code-block:: php - public function newAction(Request $request) + public function new(Request $request) { // build the form ... @@ -179,17 +179,16 @@ Handling a form submit usually follows a similar template: $em->persist($post); $em->flush(); - return $this->redirect($this->generateUrl( - 'admin_post_show', - array('id' => $post->getId()) - )); + return $this->redirectToRoute('admin_post_show', [ + 'id' => $post->getId() + ]); } // render the template } We recommend that you use a single action for both rendering the form and -handling the form submit. For example, you *could* have a ``newAction()`` that -*only* renders the form and a ``createAction()`` that *only* processes the form +handling the form submit. For example, you *could* have a ``new()`` action that +*only* renders the form and a ``create()`` action that *only* processes the form submit. Both those actions will be almost identical. So it's much simpler to let -``newAction()`` handle everything. +``new()`` handle everything. diff --git a/best_practices/security.rst b/best_practices/security.rst index a83e5efacaf..6135748fa3e 100644 --- a/best_practices/security.rst +++ b/best_practices/security.rst @@ -116,7 +116,7 @@ Using ``@Security``, this looks like: * @Route("/new", name="admin_post_new") * @Security("has_role('ROLE_ADMIN')") */ - public function newAction() + public function new() { // ... } @@ -139,7 +139,7 @@ method on the ``Post`` object: * @Route("/{id}/edit", name="admin_post_edit") * @Security("user.getEmail() == post.getAuthorEmail()") */ - public function editAction(Post $post) + public function edit(Post $post) { // ... } @@ -194,7 +194,7 @@ Now you can reuse this method both in the template and in the security expressio * @Route("/{id}/edit", name="admin_post_edit") * @Security("post.isAuthor(user)") */ - public function editAction(Post $post) + public function edit(Post $post) { // ... } @@ -222,7 +222,7 @@ more advanced use-case, you can always do the same security check in PHP: /** * @Route("/{id}/edit", name="admin_post_edit") */ - public function editAction($id) + public function edit($id) { $post = $this->getDoctrine() ->getRepository(Post::class) @@ -282,7 +282,7 @@ the same ``getAuthorEmail()`` logic you used above: protected function supports($attribute, $subject) { - if (!in_array($attribute, array(self::CREATE, self::EDIT))) { + if (!in_array($attribute, [self::CREATE, self::EDIT])) { return false; } @@ -306,7 +306,7 @@ the same ``getAuthorEmail()`` logic you used above: switch ($attribute) { // if the user is an admin, allow them to create new posts case self::CREATE: - if ($this->decisionManager->decide($token, array('ROLE_ADMIN'))) { + if ($this->decisionManager->decide($token, ['ROLE_ADMIN'])) { return true; } @@ -338,7 +338,7 @@ Now, you can use the voter with the ``@Security`` annotation: * @Route("/{id}/edit", name="admin_post_edit") * @Security("is_granted('edit', post)") */ - public function editAction(Post $post) + public function edit(Post $post) { // ... } @@ -351,7 +351,7 @@ via the even easier shortcut in a controller: /** * @Route("/{id}/edit", name="admin_post_edit") */ - public function editAction($id) + public function edit($id) { $post = ...; // query for the post diff --git a/best_practices/templates.rst b/best_practices/templates.rst index 8be12063059..9f3d1feaac7 100644 --- a/best_practices/templates.rst +++ b/best_practices/templates.rst @@ -23,32 +23,22 @@ Template Locations .. best-practice:: - Store all your application's templates in ``app/Resources/views/`` directory. + Store the application templates in the ``templates/`` directory at the root + of your project. -Traditionally, Symfony developers stored the application templates in the -``Resources/views/`` directory of each bundle. Then they used the Twig namespaced -path to refer to them (e.g. ``@AcmeDemo/Default/index.html.twig``). - -But for the templates used in your application, it's much more convenient -to store them in the ``app/Resources/views/`` directory. For starters, this -drastically simplifies their logical names: - -============================================ ================================== -Templates Stored inside Bundles Templates Stored in ``app/`` -============================================ ================================== -``@AcmeDemo/index.html.twig`` ``index.html.twig`` -``@AcmeDemo/Default/index.html.twig`` ``default/index.html.twig`` -``@AcmeDemo/Default/subdir/index.html.twig`` ``default/subdir/index.html.twig`` -============================================ ================================== - -Another advantage is that centralizing your templates simplifies the work -of your designers. They don't need to look for templates in lots of directories -scattered through lots of bundles. +Centralizing your templates in a single location simplifies the work of your +designers. In addition, using this directory simplifies the notation used when +referring to templates (e.g. ``$this->render('admin/post/show.html.twig')`` +instead of ``$this->render('@SomeTwigNamespace/Admin/Posts/show.html.twig')``). .. best-practice:: Use lowercased snake_case for directory and template names. +This recommendation aligns with Twig best practices, where variables and template +names use lowercased snake_case too (e.g. ``user_profile`` instead of ``userProfile`` +and ``edit_form.html.twig`` instead of ``EditForm.html.twig``). + Twig Extensions --------------- @@ -58,41 +48,25 @@ Twig Extensions application will automatically detect them and configure them. Our application needs a custom ``md2html`` Twig filter so that we can transform -the Markdown contents of each post into HTML. - -To do this, first, install the excellent `Parsedown`_ Markdown parser as -a new dependency of the project: - -.. code-block:: terminal - - $ composer require erusev/parsedown - -Then, create a new ``Markdown`` class that will be used later by the Twig -extension. It just needs to define one single method to transform -Markdown content into HTML:: +the Markdown contents of each post into HTML. To do this, create a new +``Markdown`` class that will be used later by the Twig extension. It just needs +to define one single method to transform Markdown content into HTML:: namespace App\Utils; class Markdown { - private $parser; - - public function __construct() - { - $this->parser = new \Parsedown(); - } + // ... - public function toHtml($text) + public function toHtml(string $text): string { - $html = $this->parser->text($text); - - return $html; + return $this->parser->text($text); } } -Next, create a new Twig extension and define a new filter called ``md2html`` -using the ``TwigFilter`` class. Inject the newly defined ``Markdown`` class in -the constructor of the Twig extension: +Next, create a new Twig extension and define a filter called ``md2html`` using +the ``TwigFilter`` class. Inject the newly defined ``Markdown`` class in the +constructor of the Twig extension: .. code-block:: php diff --git a/best_practices/tests.rst b/best_practices/tests.rst index 91e33d02818..621ab6171b6 100644 --- a/best_practices/tests.rst +++ b/best_practices/tests.rst @@ -54,7 +54,7 @@ A functional test can be as easy as this:: yield ['/post/fixture-post-1']; yield ['/blog/category/fixture-category']; yield ['/archives']; - yield [.]; + // ... } } From 68b7a18d74e8dde9623236168e58bdbfadf1c522 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 8 Nov 2017 12:39:51 +0100 Subject: [PATCH 0030/2437] Fixed some missing references --- best_practices/creating-the-project.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/best_practices/creating-the-project.rst b/best_practices/creating-the-project.rst index a054f293938..96d40be82d1 100644 --- a/best_practices/creating-the-project.rst +++ b/best_practices/creating-the-project.rst @@ -91,5 +91,6 @@ Symfony applications can still use third-party bundles (installed in ``vendor/`` to add features, but you should use PHP namespaces instead of bundles to organize your own code. -.. _`Symfony Skeleton`: https://github.com/symfony/skeleton .. _`Composer`: https://getcomposer.org/ +.. _`Symfony Flex`: https://github.com/symfony/flex +.. _`Symfony Skeleton`: https://github.com/symfony/skeleton From 335e461fe8800bb6a2c0ae99a8e49ee6e756b11d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 8 Nov 2017 20:52:09 +0100 Subject: [PATCH 0031/2437] Fixed after Fabien's review --- best_practices/business-logic.rst | 13 +++++-------- best_practices/creating-the-project.rst | 8 ++++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/best_practices/business-logic.rst b/best_practices/business-logic.rst index 8694a248511..e59705e34de 100644 --- a/best_practices/business-logic.rst +++ b/best_practices/business-logic.rst @@ -35,10 +35,11 @@ Services: Naming and Configuration Use autowiring to automate the configuration of application services. :doc:`Service autowiring ` is a feature provided -by Symfony's Service Container to manage services with minimal configuration. -It reads the type-hints on your constructor (or other methods) and automatically -passes you the correct services. It can also add :doc:`service tags ` -to the services needed them, such as Twig extensions, event subscribers, etc. +by Symfony's Service Container to manage services with minimal configuration. It +reads the type-hints on your constructor (or other methods) and automatically +passes the correct services to each method. It can also add +:doc:`service tags ` to the services needed them, such +as Twig extensions, event subscribers, etc. The blog application needs a utility that can transform a post title (e.g. "Hello World") into a slug (e.g. "hello-world") to include it as part of the @@ -61,10 +62,6 @@ If you're using the :ref:`default services.yaml configuration Date: Fri, 10 Nov 2017 12:12:40 +0100 Subject: [PATCH 0032/2437] Updated Bundles Best Practices for Symfony 4 --- bundles/best_practices.rst | 96 ++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 39 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index 5381acd5951..e75c4c8d48c 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -4,21 +4,10 @@ Best Practices for Reusable Bundles =================================== -There are two types of bundles: - -* Application-specific bundles: only used to build your application; -* Reusable bundles: meant to be shared across many projects. - 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 guides. - -.. seealso:: - - The best practices for application-specific bundles are discussed in - :doc:`/best_practices/introduction`. +they're easy to configure and extend. Reusable bundles are those meant to be +shared privately across many company projects or publicly so any Symfony project +can install them. .. index:: pair: Bundle; Naming conventions @@ -28,10 +17,10 @@ the guides. Bundle Name ----------- -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 ``Bundle``. +A bundle is also a PHP namespace. The namespace must follow the `PSR-4`_ +interoperability standard 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 ``Bundle``. A namespace becomes a bundle as soon as you add a bundle class to it. The bundle class name must follow these simple rules: @@ -116,21 +105,21 @@ The following classes and files have specific emplacements (some are mandatory and others are just conventions followed by most developers): =================================================== ======================================== -Type Directory +Type Directory =================================================== ======================================== -Commands ``Command/`` -Controllers ``Controller/`` -Service Container Extensions ``DependencyInjection/`` +Commands ``Command/`` +Controllers ``Controller/`` +Service Container Extensions ``DependencyInjection/`` Doctrine ORM entities (when not using annotations) ``Entity/`` Doctrine ODM documents (when not using annotations) ``Document/`` -Event Listeners ``EventListener/`` -Configuration ``Resources/config/`` -Web Resources (CSS, JS, images) ``Resources/public/`` -Translation files ``Resources/translations/`` +Event Listeners ``EventListener/`` +Configuration (routes, services, etc.) ``Resources/config/`` +Web Assets (CSS, JS, images) ``Resources/public/`` +Translation files ``Resources/translations/`` Validation (when not using annotations) ``Resources/config/validation/`` Serialization (when not using annotations) ``Resources/config/serialization/`` -Templates ``Resources/views/`` -Unit and Functional Tests ``Tests/`` +Templates ``Resources/views/`` +Unit and Functional Tests ``Tests/`` =================================================== ======================================== Classes @@ -177,16 +166,23 @@ the ``Tests/`` directory. Tests should follow the following principles: A test suite must not contain ``AllTests.php`` scripts, but must rely on the existence of a ``phpunit.xml.dist`` file. +Installation +------------ + +Bundles must define a `Symfony Flex recipe`_ to automate their integration +in Symfony applications. If some initial configuration is needed to execute +the bundle, including some environment variables, provide them in the recipe. + Documentation ------------- All classes and functions must come with full PHPDoc. -Extensive documentation should also be provided in the ``Resources/doc/`` +Extensive documentation should also be provided in the ``Resources/doc/`` directory. -The index file (for example ``Resources/doc/index.rst`` or -``Resources/doc/index.md``) is the only mandatory file and must be the entry -point for the documentation. The +The index file (for example ``Resources/doc/index.rst`` or +``Resources/doc/index.md``) is the only mandatory file and must be the entry +point for the documentation. The :doc:`reStructuredText (rST) ` is the format used to render the documentation on symfony.com. @@ -203,8 +199,19 @@ following standardized instructions in your ``README.md`` file. Installation ============ - Step 1: Download the Bundle - --------------------------- + Applications that use Symfony Flex + ---------------------------------- + + Open a command console, enter your project directory and execute: + + ```console + $ composer require + ``` + + Applications that don't use Symfony Flex + ---------------------------------------- + + ### 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: @@ -217,8 +224,7 @@ following standardized instructions in your ``README.md`` file. 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: @@ -249,8 +255,20 @@ following standardized instructions in your ``README.md`` file. Installation ============ + Applications that use Symfony Flex + ---------------------------------- + + Open a command console, enter your project directory and execute: + + .. code-block:: terminal + + $ composer require + + Applications that don't use Symfony Flex + ---------------------------------------- + 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: @@ -263,7 +281,7 @@ following standardized instructions in your ``README.md`` file. 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: @@ -450,8 +468,8 @@ Learn more * :doc:`/bundles/extension` * :doc:`/bundles/configuration` -.. _`PSR-0`: http://www.php-fig.org/psr/psr-0/ .. _`PSR-4`: http://www.php-fig.org/psr/psr-4/ +.. _`Symfony Flex recipe`: https://github.com/symfony/recipes .. _`Semantic Versioning Standard`: http://semver.org/ .. _`Packagist`: https://packagist.org/ .. _`choose any license`: http://choosealicense.com/ From 1f433dae6bbb489539330d353600143f7e2a1dc6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 10 Nov 2017 14:51:50 +0100 Subject: [PATCH 0033/2437] Fixed a missing reference --- bundles/best_practices.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index e75c4c8d48c..553523aeacf 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -440,9 +440,8 @@ The ``composer.json`` file should include at least the following metadata: a string (or array of strings) with a `valid license identifier`_, such as ``MIT``. ``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. + This information is used by Symfony to load the classes of the bundle. It's + recommended to use the `PSR-4`_ autoload standard. In order to make it easier for developers to find your bundle, register it on `Packagist`_, the official repository for Composer packages. From 2764076b1efccbaf649ab414bbaee160c875cbe0 Mon Sep 17 00:00:00 2001 From: Clemens Krack Date: Fri, 10 Nov 2017 16:20:34 +0100 Subject: [PATCH 0034/2437] Fix path to requirements-checker --- setup.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.rst b/setup.rst index 9debd159aad..981b4371dcb 100644 --- a/setup.rst +++ b/setup.rst @@ -90,7 +90,7 @@ The ``req-checker`` utility adds two PHP scripts to your application: .. code-block:: terminal - php bin/check.php + php vendor/bin/requirements-checker This will check your CLI environment. Run the second one from a browser (e.g. ``http://localhost:8000/check.php``) to check your web server environment. From 02660464b189383e47e1f5f608ba8a8a44813fbd Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 11 Nov 2017 18:04:57 +0100 Subject: [PATCH 0035/2437] Removed deprecated features and notices --- best_practices/configuration.rst | 5 - bundles/extension.rst | 10 - bundles/inheritance.rst | 107 +------- bundles/override.rst | 4 +- components/cache.rst | 5 +- .../cache/adapters/memcached_adapter.rst | 4 - .../adapters/pdo_doctrine_dbal_adapter.rst | 5 - components/cache/cache_invalidation.rst | 3 - components/config/definition.rst | 9 - components/console/events.rst | 30 +-- components/console/helpers/questionhelper.rst | 12 +- components/console/logger.rst | 3 - components/console/usage.rst | 5 - .../dependency_injection/compilation.rst | 3 - components/dom_crawler.rst | 20 +- components/dotenv.rst | 3 - .../container_aware_dispatcher.rst | 102 +------ components/expression_language/caching.rst | 6 - components/expression_language/extending.rst | 5 +- components/filesystem.rst | 7 - components/finder.rst | 3 - components/http_foundation.rst | 10 - components/phpunit_bridge.rst | 4 - components/process.rst | 7 - components/routing.rst | 11 - components/serializer.rst | 14 - components/stopwatch.rst | 3 - components/translation/usage.rst | 15 -- components/var_dumper.rst | 3 - components/var_dumper/advanced.rst | 23 +- components/workflow.rst | 8 - components/yaml.rst | 7 - components/yaml/yaml_format.rst | 3 - configuration/external_parameters.rst | 9 - configuration/micro_kernel_trait.rst | 6 - console.rst | 6 - console/commands_as_services.rst | 8 - console/lazy_commands.rst | 3 - console/lockable_trait.rst | 3 - controller.rst | 18 -- controller/argument_value_resolver.rst | 3 - form/create_form_type_extension.rst | 15 +- form/form_customization.rst | 3 - form/form_dependencies.rst | 4 - form/type_guesser.rst | 4 - form/unit_testing.rst | 4 - profiler/matchers.rst | 157 +---------- quick_tour/the_controller.rst | 4 - reference/configuration/debug.rst | 3 - reference/configuration/framework.rst | 58 ---- reference/configuration/kernel.rst | 31 --- reference/configuration/security.rst | 18 -- reference/configuration/twig.rst | 9 - reference/configuration/web_profiler.rst | 23 -- reference/constraints/Choice.rst | 8 - reference/constraints/Image.rst | 12 - reference/constraints/UniqueEntity.rst | 3 - reference/dic_tags.rst | 5 - reference/forms/types/choice.rst | 13 +- reference/forms/types/collection.rst | 4 - reference/forms/types/country.rst | 3 +- reference/forms/types/currency.rst | 3 +- reference/forms/types/dateinterval.rst | 6 - reference/forms/types/language.rst | 3 +- reference/forms/types/locale.rst | 3 +- reference/forms/types/timezone.rst | 3 +- routing.rst | 3 - routing/requirements.rst | 11 +- security.rst | 26 +- security/acl.rst | 248 +----------------- security/acl_advanced.rst | 195 +------------- security/guard_authentication.rst | 9 - serializer/encoders.rst | 5 - service_container.rst | 23 -- service_container/3.3-di-changes.rst | 4 +- service_container/autowiring.rst | 9 +- service_container/configurators.rst | 5 - service_container/debug.rst | 6 - service_container/parameters.rst | 7 +- service_container/tags.rst | 8 - session/avoid_session_start.rst | 4 - setup/built_in_web_server.rst | 3 - testing.rst | 8 +- translation/lint.rst | 3 - workflow/usage.rst | 9 +- 85 files changed, 62 insertions(+), 1438 deletions(-) diff --git a/best_practices/configuration.rst b/best_practices/configuration.rst index 5f390f0e6b9..55d3d4c840e 100644 --- a/best_practices/configuration.rst +++ b/best_practices/configuration.rst @@ -210,10 +210,5 @@ through environment variables: # ... password: "%env(DB_PASSWORD)%" -.. versionadded:: 3.2 - Support for runtime environment variables via the ``%env(...)%`` syntax - was added in Symfony 3.2. Prior to version 3.2, you needed to use the - :doc:`special SYMFONY__ variables `. - .. _`feature toggles`: https://en.wikipedia.org/wiki/Feature_toggle .. _`constant() function`: http://twig.sensiolabs.org/doc/functions/constant.html diff --git a/bundles/extension.rst b/bundles/extension.rst index 116f969e357..9492bb0de12 100644 --- a/bundles/extension.rst +++ b/bundles/extension.rst @@ -129,17 +129,10 @@ read more about it, see the ":doc:`/bundles/configuration`" article. Adding Classes to Compile ------------------------- -.. versionadded:: 3.3 - This technique is discouraged and the ``addClassesToCompile()`` method was - deprecated in Symfony 3.3 because modern PHP versions make it unnecessary. - Symfony creates a big ``classes.php`` file in the cache directory to aggregate the contents of the PHP classes that are used in every request. This reduces the I/O operations and increases the application performance. -.. versionadded:: 3.2 - The ``addAnnotatedClassesToCompile()`` method was added in Symfony 3.2. - Your bundles can also add their own classes into this file thanks to the ``addClassesToCompile()`` and ``addAnnotatedClassesToCompile()`` methods (both work in the same way, but the second one is for classes that contain PHP @@ -173,9 +166,6 @@ class names:: If some class extends from other classes, all its parents are automatically included in the list of classes to compile. -.. versionadded:: 3.2 - The option to add classes to compile using patterns was introduced in Symfony 3.2. - The classes to compile can also be added using file path patterns:: // ... diff --git a/bundles/inheritance.rst b/bundles/inheritance.rst index 7a4f720289e..d8ce372adb4 100644 --- a/bundles/inheritance.rst +++ b/bundles/inheritance.rst @@ -6,107 +6,6 @@ How to Use Bundle Inheritance to Override Parts of a Bundle .. caution:: - Bundle inheritance is deprecated since Symfony 3.4 and will be removed in - 4.0. - -When working with third-party bundles, you'll probably come across a situation -where you want to override a file in that third-party bundle with a file -in one of your own bundles. Symfony gives you a very convenient way to override -things like controllers, templates, and other files in a bundle's -``Resources/`` directory. - -For example, suppose that you have installed `FOSUserBundle`_, but you want to -override its base ``layout.html.twig`` template, as well as one of its -controllers. - -First, create a new bundle called UserBundle and enable it in your application. -Then, register the third-party FOSUserBundle as the "parent" of your bundle:: - - // src/UserBundle/UserBundle.php - namespace UserBundle; - - use Symfony\Component\HttpKernel\Bundle\Bundle; - - class UserBundle extends Bundle - { - public function getParent() - { - return 'FOSUserBundle'; - } - } - -By making this simple change, you can now override several parts of the FOSUserBundle -simply by creating a file with the same name. - -.. note:: - - Despite the method name, there is no parent/child relationship between - the bundles, it is just a way to extend and override an existing bundle. - -Overriding Controllers -~~~~~~~~~~~~~~~~~~~~~~ - -Suppose you want to add some functionality to the ``registerAction()`` of a -``RegistrationController`` that lives inside FOSUserBundle. To do so, -just create your own ``RegistrationController.php`` file, override the bundle's -original method, and change its functionality:: - - // src/UserBundle/Controller/RegistrationController.php - namespace UserBundle\Controller; - - use FOS\UserBundle\Controller\RegistrationController as BaseController; - - class RegistrationController extends BaseController - { - public function registerAction() - { - $response = parent::registerAction(); - - // ... do custom stuff - return $response; - } - } - -.. tip:: - - Depending on how severely you need to change the behavior, you might - call ``parent::registerAction()`` or completely replace its logic with - your own. - -.. note:: - - Overriding controllers in this way only works if the bundle refers to - the controller using the standard ``FOSUserBundle:Registration:register`` - syntax in routes and templates. This is the best practice. - -Overriding Resources: Templates, Routing, etc -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Most resources can also be overridden, simply by creating a file in the same -location as your parent bundle. - -For example, it's very common to need to override the FOSUserBundle's -``layout.html.twig`` template so that it uses your application's base layout. -Since the file lives at ``Resources/views/layout.html.twig`` in the FOSUserBundle, -you can create your own file in the same location of UserBundle. Symfony will -ignore the file that lives inside the FOSUserBundle entirely, and use your file -instead. - -The same goes for routing files and some other resources. - -.. note:: - - The overriding of resources only works when you refer to resources with - the ``@FOSUserBundle/Resources/config/routing/security.xml`` method. - You need to use the ``@BundleName`` shortcut when referring to resources - so they can be successfully overridden (except templates, which are - overridden in a different way, as explained in :doc:`/templating/overriding`). - -.. caution:: - - Translation and validation files do not work in the same way as described - above. Read ":ref:`override-translations`" if you want to learn how to - override translations and see ":ref:`override-validation`" for tricks to - override the validation. - -.. _`FOSUserBundle`: https://github.com/friendsofsymfony/fosuserbundle + Bundle inheritance was removed in Symfony 4.0, but you can + :doc:`override any part of a bundle ` without + using bundle inheritance. diff --git a/bundles/override.rst b/bundles/override.rst index 0b1455c5984..bd90df508e8 100644 --- a/bundles/override.rst +++ b/bundles/override.rst @@ -5,8 +5,8 @@ How to Override any Part of a Bundle ==================================== This document is a quick reference for how to override different parts of -third-party bundles without using :doc:`/bundles/inheritance`, which is -deprecated since Symfony 3.4. +third-party bundles without using :doc:`/bundles/inheritance`, which was +removed in Symfony 4.0. .. tip:: diff --git a/components/cache.rst b/components/cache.rst index 4b940850853..79b5b2a6ad9 100644 --- a/components/cache.rst +++ b/components/cache.rst @@ -13,9 +13,6 @@ The Cache Component It is designed to have a low overhead and it ships with ready to use adapters for the most common caching backends. -.. versionadded:: 3.3 - The PSR-16 "Simple Cache" implementation was introduced in Symfony 3.3. - Installation ------------ @@ -78,7 +75,7 @@ Now you can create, retrieve, update and delete items using this object:: // remove the cache key $cache->delete('stats.num_products'); - + // clear *all* cache keys $cache->clear(); diff --git a/components/cache/adapters/memcached_adapter.rst b/components/cache/adapters/memcached_adapter.rst index 413db7d89fa..843a384b2f3 100644 --- a/components/cache/adapters/memcached_adapter.rst +++ b/components/cache/adapters/memcached_adapter.rst @@ -7,10 +7,6 @@ Memcached Cache Adapter ======================= -.. versionadded:: 3.3 - - The Memcached adapter was introduced in Symfony 3.3. - This adapter stores the values in-memory using one (or more) `Memcached server`_ instances. Unlike the :ref:`APCu adapter `, and similarly to the :ref:`Redis adapter `, it is not limited to the current server's diff --git a/components/cache/adapters/pdo_doctrine_dbal_adapter.rst b/components/cache/adapters/pdo_doctrine_dbal_adapter.rst index 76ac5860e89..ab039baae5e 100644 --- a/components/cache/adapters/pdo_doctrine_dbal_adapter.rst +++ b/components/cache/adapters/pdo_doctrine_dbal_adapter.rst @@ -7,11 +7,6 @@ PDO & Doctrine DBAL Cache Adapter ================================= -.. versionadded:: 3.2 - - The PDO & Doctrine DBAL adapter was introduced in Symfony 3.2. - - This adapter stores the cache items in an SQL database. It requires a `PDO`_, `Doctrine DBAL Connection`_, or `Data Source Name (DSN)`_ as its first parameter, and optionally a namespace, default cache lifetime, and options array as its second, diff --git a/components/cache/cache_invalidation.rst b/components/cache/cache_invalidation.rst index 0ec6b8ba02b..367ce906500 100644 --- a/components/cache/cache_invalidation.rst +++ b/components/cache/cache_invalidation.rst @@ -20,9 +20,6 @@ The Symfony Cache component provides two mechanisms to help solving this problem Using Cache Tags ---------------- -.. versionadded:: 3.2 - Tags based invalidation was introduced in Symfony 3.2. - To benefit from tags based invalidation, you need to attach the proper tags to each cached item. Each tag is a plain string identifier that you can use at any time to trigger the removal of all items associated with this tag. diff --git a/components/config/definition.rst b/components/config/definition.rst index 0f28337c2d3..f66a2127298 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -186,20 +186,11 @@ Or you may define a prototype for each node inside an array node:: ->end() ; -.. versionadded:: 3.3 - The ``arrayPrototype()`` method (and the related ``booleanPrototype()`` - ``integerPrototype()``, ``floatPrototype()``, ``scalarPrototype()`` and - ``enumPrototype()``) was introduced in Symfony 3.3. In previous versions, - you needed to use ``prototype('array')``, ``prototype('boolean')``, etc. - A prototype can be used to add a definition which may be repeated many times inside the current node. According to the prototype definition in the example above, it is possible to have multiple connection arrays (containing a ``driver``, ``host``, etc.). -.. versionadded:: 3.3 - The ``castToArray()`` helper was added in Symfony 3.3. - Sometimes, to improve the user experience of your application or bundle, you may allow to use a simple string or numeric value where an array value is required. Use the ``castToArray()`` helper to turn those variables into arrays:: diff --git a/components/console/events.rst b/components/console/events.rst index ad268bba0fd..c8dd7079d65 100644 --- a/components/console/events.rst +++ b/components/console/events.rst @@ -83,19 +83,16 @@ C/C++ standard.:: } }); -The ``ConsoleEvents::EXCEPTION`` Event --------------------------------------- - -.. versionadded:: 3.3 - The ``ConsoleEvents::EXCEPTION`` event was deprecated in Symfony 3.3. Use - the ``ConsoleEvents::ERROR`` event instead. +The ``ConsoleEvents::ERROR`` Event +---------------------------------- **Typical Purposes**: Handle exceptions thrown during the execution of a command. -Whenever an exception is thrown by a command, the ``ConsoleEvents::EXCEPTION`` -event is dispatched. A listener can wrap or change the exception or do -anything useful before the exception is thrown by the application. +Whenever an exception is thrown by a command, including those triggered from +event listeners, the ``ConsoleEvents::ERROR`` event is dispatched. A listener +can wrap or change the exception or do anything useful before the exception is +thrown by the application. Listeners receive a :class:`Symfony\\Component\\Console\\Event\\ConsoleExceptionEvent` event:: @@ -103,7 +100,7 @@ Listeners receive a use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\ConsoleEvents; - $dispatcher->addListener(ConsoleEvents::EXCEPTION, function (ConsoleExceptionEvent $event) { + $dispatcher->addListener(ConsoleEvents::ERROR, function (ConsoleExceptionEvent $event) { $output = $event->getOutput(); $command = $event->getCommand(); @@ -117,19 +114,6 @@ Listeners receive a $event->setException(new \LogicException('Caught exception', $exitCode, $event->getException())); }); -The ``ConsoleEvents::ERROR`` Event ----------------------------------- - -.. versionadded:: 3.3 - The ``ConsoleEvents::ERROR`` event was introduced in Symfony 3.3. - -**Typical Purposes**: Handle exceptions thrown during the execution of a -command. - -This event is an improved version of the ``ConsoleEvents::EXCEPTION`` event, -because it can handle every exception thrown during the execution of a command, -including those triggered from event listeners. - The ``ConsoleEvents::TERMINATE`` Event -------------------------------------- diff --git a/components/console/helpers/questionhelper.rst b/components/console/helpers/questionhelper.rst index 9b9a9187f5c..69b6ee74ac8 100644 --- a/components/console/helpers/questionhelper.rst +++ b/components/console/helpers/questionhelper.rst @@ -170,7 +170,7 @@ will be autocompleted as the user types:: { // ... $helper = $this->getHelper('question'); - + $bundles = array('AcmeDemoBundle', 'AcmeBlogBundle', 'AcmeStoreBundle'); $question = new Question('Please enter the name of a bundle', 'FooBundle'); $question->setAutocompleterValues($bundles); @@ -191,7 +191,7 @@ convenient for passwords:: { // ... $helper = $this->getHelper('question'); - + $question = new Question('What is the database password?'); $question->setHidden(true); $question->setHiddenFallback(false); @@ -229,9 +229,6 @@ convenient for passwords:: // ... } - .. versionadded:: 3.3 - The ``QuestionHelper::disableStty()`` method was introduced in Symfony 3.3. - Normalizing the Answer ---------------------- @@ -249,7 +246,7 @@ method:: { // ... $helper = $this->getHelper('question'); - + $question = new Question('Please enter the name of the bundle', 'AppBundle'); $question->setNormalizer(function ($value) { // $value can be null here @@ -369,9 +366,6 @@ from the command line, you need to set the inputs that the command expects:: // $this->assertRegExp('/.../', $commandTester->getDisplay()); } -.. versionadded:: 3.2 - The ``CommandTester::setInputs()`` method was introduced in Symfony 3.2. - By calling :method:`Symfony\\Component\\Console\\Tester\\CommandTester::setInputs`, you imitate what the console would do internally with all user input through the CLI. This method takes an array as only argument with, for each input that the command expects, diff --git a/components/console/logger.rst b/components/console/logger.rst index 0a1386c52ef..6d8f345e33f 100644 --- a/components/console/logger.rst +++ b/components/console/logger.rst @@ -106,9 +106,6 @@ constructor:: Errors ------ -.. versionadded:: 3.2 - The ``hasErrored()`` method was introduced in Symfony 3.2. - The Console logger includes a ``hasErrored()`` method which returns ``true`` as soon as any error message has been logged during the execution of the command. This is useful to decide which status code to return as the result of executing diff --git a/components/console/usage.rst b/components/console/usage.rst index bf77b3d6e91..f8a7c0283df 100644 --- a/components/console/usage.rst +++ b/components/console/usage.rst @@ -156,8 +156,3 @@ can run it with: If you enter a short command that's ambiguous (i.e. there are more than one command that match), then no command will be run and some suggestions of the possible commands to choose from will be output. - -.. versionadded:: 3.4 - Case-insensitivity of command shortcuts was introduced in Symfony 3.4. In - previous Symfony versions, shortcuts had to match the case of the original - command name (e.g. ``d:g`` was not the same shortcut as ``D:G``). diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index e1af120adce..d2b494ab4ca 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -423,9 +423,6 @@ been run, use:: PassConfig::TYPE_AFTER_REMOVING ); -.. versionadded:: 3.2 - The option to prioritize compiler passes was added in Symfony 3.2. - You can also control the order in which compiler passes are run for each compilation phase. Use the optional third argument of ``addCompilerPass()`` to set the priority as an integer number. The default priority is ``0`` and the higher diff --git a/components/dom_crawler.rst b/components/dom_crawler.rst index 8a85cdb8e68..e4848d01b02 100644 --- a/components/dom_crawler.rst +++ b/components/dom_crawler.rst @@ -246,11 +246,6 @@ The crawler supports multiple ways of adding the content:: guesses the best charset according to the given contents and defaults to ``ISO-8859-1`` in case no charset can be guessed. - .. versionadded:: 3.4 - The charset guessing mechanism of the ``addContent()`` method was - introduced in Symfony 3.4. In previous Symfony versions, the ``ISO-8859-1`` - charset was always used. - As the Crawler's implementation is based on the DOM extension, it is also able to interact with native :phpclass:`DOMDocument`, :phpclass:`DOMNodeList` and :phpclass:`DOMNode` objects: @@ -294,10 +289,6 @@ and :phpclass:`DOMNode` objects: Expression Evaluation ~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 3.2 - The :method:`Symfony\\Component\\DomCrawler\\Crawler::evaluate` method was - introduced in Symfony 3.2. - The ``evaluate()`` method evaluates the given XPath expression. The return value depends on the XPath expression. If the expression evaluates to a scalar value (e.g. HTML attributes), an array of results will be returned. If the @@ -433,11 +424,12 @@ than just return the ``action`` attribute of the form. If the form method is GET, then it mimics the browser's behavior and returns the ``action`` attribute followed by a query string of all of the form's values. -.. versionadded:: 3.3 - Starting from Symfony 3.3, the optional ``formaction`` and ``formmethod`` - button attributes are supported. The ``getUri()`` and ``getMethod()`` - methods take into account those attributes to always return the right action - and method depending on the button used to get the form. +.. note:: + + The optional ``formaction`` and ``formmethod`` button attributes are + supported. The ``getUri()`` and ``getMethod()`` methods take into account + those attributes to always return the right action and method depending on + the button used to get the form. You can virtually set and get values on the form:: diff --git a/components/dotenv.rst b/components/dotenv.rst index 6d7a4adffba..2b71e0f0606 100644 --- a/components/dotenv.rst +++ b/components/dotenv.rst @@ -8,9 +8,6 @@ The Dotenv Component The Dotenv Component parses ``.env`` files to make environment variables stored in them accessible via ``getenv()``, ``$_ENV`` or ``$_SERVER``. -.. versionadded:: 3.3 - The Dotenv component was introduced in Symfony 3.3. - Installation ------------ diff --git a/components/event_dispatcher/container_aware_dispatcher.rst b/components/event_dispatcher/container_aware_dispatcher.rst index fd04a73daf3..659a94cee7a 100644 --- a/components/event_dispatcher/container_aware_dispatcher.rst +++ b/components/event_dispatcher/container_aware_dispatcher.rst @@ -4,103 +4,7 @@ The Container Aware Event Dispatcher ==================================== -.. versionadded:: 3.3 - The ``ContainerAwareEventDispatcher`` class has been deprecated in Symfony 3.3 - and it will be removed in Symfony 4.0. Use ``EventDispatcher`` with - closure-proxy injection instead. +.. caution:: -Introduction ------------- - -The :class:`Symfony\\Component\\EventDispatcher\\ContainerAwareEventDispatcher` -is a special ``EventDispatcher`` implementation which is coupled to the -service container that is part of -:doc:`the DependencyInjection component `. -It allows services to be specified as event listeners making the ``EventDispatcher`` -extremely powerful. - -Services are lazy loaded meaning the services attached as listeners will -only be created if an event is dispatched that requires those listeners. - -Setup ------ - -Setup is straightforward by injecting a :class:`Symfony\\Component\\DependencyInjection\\ContainerInterface` -into the :class:`Symfony\\Component\\EventDispatcher\\ContainerAwareEventDispatcher`:: - - use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; - - $container = new ContainerBuilder(); - $dispatcher = new ContainerAwareEventDispatcher($container); - -Adding Listeners ----------------- - -The ``ContainerAwareEventDispatcher`` can either load specified services -directly or services that implement :class:`Symfony\\Component\\EventDispatcher\\EventSubscriberInterface`. - -The following examples assume the service container has been loaded with -any services that are mentioned. - -.. note:: - - Services must be marked as public in the container. - -Adding Services -~~~~~~~~~~~~~~~ - -To connect existing service definitions, use the -:method:`Symfony\\Component\\EventDispatcher\\ContainerAwareEventDispatcher::addListenerService` -method where the ``$callback`` is an array of ``array($serviceId, $methodName)``:: - - $dispatcher->addListenerService($eventName, array('foo', 'logListener')); - -Adding Subscriber Services -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Event subscribers can be added using the -:method:`Symfony\\Component\\EventDispatcher\\ContainerAwareEventDispatcher::addSubscriberService` -method where the first argument is the service ID of the subscriber service, -and the second argument is the service's class name (which must implement -:class:`Symfony\\Component\\EventDispatcher\\EventSubscriberInterface`) as follows:: - - $dispatcher->addSubscriberService( - 'kernel.store_subscriber', - 'StoreSubscriber' - ); - -The ``EventSubscriberInterface`` is exactly as you would expect:: - - use Symfony\Component\EventDispatcher\EventSubscriberInterface; - use Symfony\Component\HttpKernel\KernelEvents; - // ... - - class StoreSubscriber implements EventSubscriberInterface - { - public static function getSubscribedEvents() - { - return array( - KernelEvents::RESPONSE => array( - array('onKernelResponsePre', 10), - array('onKernelResponsePost', 0), - ), - 'store.order' => array('onStoreOrder', 0), - ); - } - - public function onKernelResponsePre(FilterResponseEvent $event) - { - // ... - } - - public function onKernelResponsePost(FilterResponseEvent $event) - { - // ... - } - - public function onStoreOrder(FilterOrderEvent $event) - { - // ... - } - } + The ``ContainerAwareEventDispatcher`` was removed in Symfony 4.0. Use + ``EventDispatcher`` with closure-proxy injection instead. diff --git a/components/expression_language/caching.rst b/components/expression_language/caching.rst index ac504a26534..cd60c3c4e36 100644 --- a/components/expression_language/caching.rst +++ b/components/expression_language/caching.rst @@ -37,12 +37,6 @@ ones and injecting this using the constructor:: $cache = new RedisAdapter(...); $language = new ExpressionLanguage($cache); -.. versionadded:: 3.2 - PSR-6 caching support was introduced in Symfony 3.2. Prior to version 3.2, - a - :class:`Symfony\\Component\\ExpressionLanguage\\ParserCache\\ParserCacheInterface` - instance had to be injected. - .. seealso:: See the :doc:`/components/cache` documentation for more information about diff --git a/components/expression_language/extending.rst b/components/expression_language/extending.rst index 20a6aa9e188..eecf556e75b 100644 --- a/components/expression_language/extending.rst +++ b/components/expression_language/extending.rst @@ -61,7 +61,7 @@ to add custom functions. To do so, you can create a new expression provider by creating a class that implements :class:`Symfony\\Component\\ExpressionLanguage\\ExpressionFunctionProviderInterface`. -This interface requires one method: +This interface requires one method: :method:`Symfony\\Component\\ExpressionLanguage\\ExpressionFunctionProviderInterface::getFunctions`, which returns an array of expression functions (instances of :class:`Symfony\\Component\\ExpressionLanguage\\ExpressionFunction`) to @@ -102,9 +102,6 @@ register. ExpressionFunction::fromPhp('My\strtoupper', 'my_strtoupper'); - .. versionadded:: 3.3 - The ``ExpressionFunction::fromPhp()`` method was introduced in Symfony 3.3. - You can register providers using :method:`Symfony\\Component\\ExpressionLanguage\\ExpressionLanguage::registerProvider` or by using the second argument of the constructor:: diff --git a/components/filesystem.rst b/components/filesystem.rst index 1445a48cc7d..0cc1c20669d 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -211,9 +211,6 @@ support symbolic links, a third boolean argument is available:: readlink ~~~~~~~~ -.. versionadded:: 3.2 - The :method:`Symfony\\Component\\Filesystem\\Filesystem::readlink` method was introduced in Symfony 3.2. - :method:`Symfony\\Component\\Filesystem\\Filesystem::readlink` read links targets. PHP's ``readlink()`` function returns the target of a symbolic link. However, its behavior @@ -297,10 +294,6 @@ The ``file.txt`` file contains ``Hello World`` now. appendToFile ~~~~~~~~~~~~ -.. versionadded:: 3.3 - The :method:`Symfony\\Component\\Filesystem\\Filesystem::appendToFile` - method was introduced in Symfony 3.3. - :method:`Symfony\\Component\\Filesystem\\Filesystem::appendToFile` adds new contents at the end of some file:: diff --git a/components/finder.rst b/components/finder.rst index 6662f3f0a0a..4786c025d3e 100644 --- a/components/finder.rst +++ b/components/finder.rst @@ -79,9 +79,6 @@ There are lots of ways to filter and sort your results. You can also use the :method:`Symfony\\Component\\Finder\\Finder::hasResults` method to check if there's any file or directory matching the search criteria. -.. versionadded:: 3.4 - The ``hasResults()`` method was introduced in Symfony 3.4. - Location ~~~~~~~~ diff --git a/components/http_foundation.rst b/components/http_foundation.rst index 88f7b336b58..7b56d953981 100644 --- a/components/http_foundation.rst +++ b/components/http_foundation.rst @@ -382,9 +382,6 @@ Note you can create a :class:`Symfony\\Component\\HttpFoundation\\Cookie` object from a raw header value using :method:`Symfony\\Component\\HttpFoundation\\Cookie::fromString`. -.. versionadded:: 3.3 - The ``Cookie::fromString()`` method was introduced in Symfony 3.3. - Managing the HTTP Cache ~~~~~~~~~~~~~~~~~~~~~~~ @@ -530,9 +527,6 @@ It is possible to delete the file after the request is sent with the :method:`Symfony\\Component\\HttpFoundation\\BinaryFileResponse::deleteFileAfterSend` method. Please note that this will not work when the ``X-Sendfile`` header is set. -.. versionadded:: 3.3 - The ``Stream`` class was introduced in Symfony 3.3. - If the size of the served file is unknown (e.g. because it's being generated on the fly, or because a PHP stream filter is registered on it, etc.), you can pass a ``Stream`` instance to ``BinaryFileResponse``. This will disable ``Range`` and ``Content-Length`` @@ -584,10 +578,6 @@ class, which can make this even easier:: // if the data to send is already encoded in JSON $response = JsonResponse::fromJsonString('{ "data": 123 }'); -.. versionadded:: 3.2 - The :method:`Symfony\\Component\\HttpFoundation\\JsonResponse::fromJsonString` - method was added in Symfony 3.2. - The ``JsonResponse`` class sets the ``Content-Type`` header to ``application/json`` and encodes your data to JSON when needed. diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 0b2539efe7d..1a62e472b7f 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -414,10 +414,6 @@ namespaces in the ``phpunit.xml`` file, as done for example in the Modified PHPUnit script ----------------------- -.. versionadded:: 3.2 - This modified PHPUnit script was introduced in the 3.2 version of - this component. - This bridge provides a modified version of PHPUnit that you can call by using its ``bin/simple-phpunit`` command. It has the following features: diff --git a/components/process.rst b/components/process.rst index 69bb6ddeb49..44fa8a26216 100644 --- a/components/process.rst +++ b/components/process.rst @@ -78,9 +78,6 @@ for new output before going to the next iteration:: echo $data."\n"; } - .. versionadded:: 3.2 - The ``getIterator()`` method was introduced in Symfony 3.2. - The ``mustRun()`` method is identical to ``run()``, except that it will throw a :class:`Symfony\\Component\\Process\\Exception\\ProcessFailedException` if the process couldn't be executed successfully (i.e. the process exited @@ -410,10 +407,6 @@ Use :method:`Symfony\\Component\\Process\\Process::disableOutput` and However, it is possible to pass a callback to the ``start``, ``run`` or ``mustRun`` methods to handle process output in a streaming fashion. - .. versionadded:: 3.1 - The ability to pass a callback to these methods when output is disabled - was added in Symfony 3.1. - .. _`Symfony Issue#5759`: https://github.com/symfony/symfony/issues/5759 .. _`PHP Bug#39992`: https://bugs.php.net/bug.php?id=39992 .. _`exec`: https://en.wikipedia.org/wiki/Exec_(operating_system) diff --git a/components/routing.rst b/components/routing.rst index 03a2ed62c17..4afb1c663c5 100644 --- a/components/routing.rst +++ b/components/routing.rst @@ -352,10 +352,6 @@ automatically in the background if you want to use it. A basic example of the Unicode Routing Support ~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 3.2 - UTF-8 support for route paths and requirements was introduced in - Symfony 3.2. - The Routing component supports UTF-8 characters in route paths and requirements. Thanks to the ``utf8`` route option, you can make Symfony match and generate routes with UTF-8 characters: @@ -509,13 +505,6 @@ You can also include UTF-8 strings as routing requirements: character in any language, ``\p{Greek}`` matches any Greek character, ``\P{Han}`` matches any character not included in the Chinese Han script. -.. note:: - - In Symfony 3.2, there is no need to explicitly set the ``utf8`` option. - As soon as Symfony finds a UTF-8 character in the route path or requirements, - it will automatically turn on the UTF-8 support. However, this behavior - is deprecated and setting the option will be required in Symfony 4.0. - Learn more ---------- diff --git a/components/serializer.rst b/components/serializer.rst index d9011365a8a..8d53069e3fd 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -152,10 +152,6 @@ needs three parameters: #. The name of the class this information will be decoded to #. The encoder used to convert that information into an array -.. versionadded:: 3.3 - Support for the ``allow_extra_attributes`` key in the context was introduced - in Symfony 3.3. - By default, additional attributes that are not mapped to the denormalized object will be ignored by the Serializer component. Set the ``allow_extra_attributes`` key of the deserialization context to ``false`` to let the serializer throw @@ -555,10 +551,6 @@ There are several types of normalizers available: :phpclass:`DateTime` and :phpclass:`DateTimeImmutable`) into strings. By default it uses the RFC3339_ format. - .. versionadded:: 3.2 - Support for specifying datetime format during denormalization was - introduced in the ``DateTimeNormalizer`` in Symfony 3.2. - :class:`Symfony\\Component\\Serializer\\Normalizer\\DataUriNormalizer` This normalizer converts :phpclass:`SplFileInfo` objects into a data URI string (``data:...``) such that files can be embedded into serialized data. @@ -567,9 +559,6 @@ There are several types of normalizers available: This normalizer converts :phpclass:`DateInterval` objects into strings. By default it uses the ``P%yY%mM%dDT%hH%iM%sS`` format. - .. versionadded:: 3.4 - The ``DateIntervalNormalizer`` normalizer was added in Symfony 3.4. - Encoders -------- @@ -591,9 +580,6 @@ The Serializer component supports many formats out of the box: All these encoders are enabled by default when using the Symfony Standard Edition with the serializer enabled. -.. versionadded:: 3.2 - The ``YamlEncoder`` and ``CsvEncoder`` encoders were introduced in Symfony 3.2 - .. _component-serializer-handling-circular-references: Handling Circular References diff --git a/components/stopwatch.rst b/components/stopwatch.rst index 190b19e04bc..325cc4ceffd 100644 --- a/components/stopwatch.rst +++ b/components/stopwatch.rst @@ -49,9 +49,6 @@ while it is still running. $stopwatch = new Stopwatch(true); - .. versionadded:: 3.4 - Full precision support was introduced in Symfony 3.4. - The stopwatch can be reset to its original state at any given time with the :method:`Symfony\\Component\\Stopwatch\\Stopwatch::reset` method, which deletes all the data measured so far. diff --git a/components/translation/usage.rst b/components/translation/usage.rst index b85ca5773a0..d7069d4b050 100644 --- a/components/translation/usage.rst +++ b/components/translation/usage.rst @@ -271,21 +271,6 @@ The second argument (``10`` in this example) is the *number* of objects being described and is used to determine which translation to use and also to populate the ``%count%`` placeholder. -.. versionadded:: 3.2 - - Before Symfony 3.2, the placeholder used to select the plural (``%count%`` - in this example) must be included in the third optional argument of the - ``transChoice()`` method:: - - $translator->transChoice( - 'There is one apple|There are %count% apples', - 10, - array('%count%' => 10) - ); - - Starting from Symfony 3.2, when the only placeholder is ``%count%``, you - don't have to pass this third argument. - Based on the given number, the translator chooses the right plural form. In English, most words have a singular form when there is exactly one object and a plural form for all other numbers (0, 2, 3...). So, if ``count`` is diff --git a/components/var_dumper.rst b/components/var_dumper.rst index 189beb980c6..98b0a35b68d 100644 --- a/components/var_dumper.rst +++ b/components/var_dumper.rst @@ -107,9 +107,6 @@ option. Read more about this and other options in .. tip:: - .. versionadded:: 3.3 - The local search box was introduced in Symfony 3.3. - If the dumped contents are complex, consider using the local search box to look for specific variables or values. First, click anywhere on the dumped contents and then press :kbd:`Ctrl. + F` or :kbd:`Cmd. + F` to make the local diff --git a/components/var_dumper/advanced.rst b/components/var_dumper/advanced.rst index b54eed95bfa..05bc55c74e7 100644 --- a/components/var_dumper/advanced.rst +++ b/components/var_dumper/advanced.rst @@ -77,9 +77,6 @@ Before dumping it, you can further limit the resulting Removes internal objects' handles for sparser output (useful for tests). :method:`Symfony\\Component\\VarDumper\\Cloner\\Data::seek` - .. versionadded:: 3.2 - The ``seek()`` method was introduced in Symfony 3.2. - Selects only subparts of already cloned arrays, objects or resources. Unlike the previous limits on cloners that remove data on purpose, these can @@ -170,9 +167,6 @@ Another option for doing the same could be:: $output = $dumper->dump($cloner->cloneVar($variable), true); - .. versionadded:: 3.2 - The ability to return a string was introduced in Symfony 3.2. - Dumpers implement the :class:`Symfony\\Component\\VarDumper\\Dumper\\DataDumperInterface` interface that specifies the :method:`dump(Data $data) ` @@ -198,21 +192,13 @@ method:: 'maxStringLength' => 160 )); -.. versionadded:: 3.2 - Support for passing display options to the ``dump()`` method was introduced - in Symfony 3.2. - -The output format of a dumper can be fine tuned by the two flags +The output format of a dumper can be fine tuned by the two flags ``DUMP_STRING_LENGTH`` and ``DUMP_LIGHT_ARRAY`` which are passed as a bitmap -in the third constructor argument. They can also be set via environment +in the third constructor argument. They can also be set via environment variables when using :method:`assertDumpEquals($dump, $data, $message) ` during unit testing. -.. versionadded:: 3.1 - The ``DUMP_STRING_LENGTH`` and ``DUMP_LIGHT_ARRAY`` flags were introduced - in Symfony 3.1. - If ``DUMP_STRING_LENGTH`` is set, then the length of a string is displayed next to its content: @@ -363,11 +349,6 @@ properties not in the class declaration). Adding Semantics with Metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 3.2 - As of Symfony 3.2, casters can attach metadata attributes to - :class:`Symfony\\Component\\VarDumper\\Cloner\\Stub` objects to inform - dumpers about the precise type of the dumped values. - Since casters are hooked on specific classes or interfaces, they know about the objects they manipulate. By altering the ``$stub`` object (the third argument of any caster), one can transfer this knowledge to the resulting ``Data`` object, diff --git a/components/workflow.rst b/components/workflow.rst index f6af36e6d96..bfb5f857230 100644 --- a/components/workflow.rst +++ b/components/workflow.rst @@ -8,9 +8,6 @@ The Workflow Component The Workflow component provides tools for managing a workflow or finite state machine. -.. versionadded:: 3.2 - The Workflow component was introduced in Symfony 3.2. - Installation ------------ @@ -56,11 +53,6 @@ these statuses are called **places**. You can define the workflow like this:: $marking = new SingleStateMarkingStore('currentState'); $workflow = new Workflow($definition, $marking); -.. versionadded:: 3.3 - The fluent interface for the ``DefinitionBuilder`` class was introduced in - Symfony 3.3. Before you had to call the ``addPlaces()``, ``addTransition()`` - and ``build()`` methods separately. - The ``Workflow`` can now help you to decide what actions are allowed on a blog post depending on what *place* it is in. This will keep your domain logic in one place and not spread all over your application. diff --git a/components/yaml.rst b/components/yaml.rst index e8ed85e123f..6dc5be378cd 100644 --- a/components/yaml.rst +++ b/components/yaml.rst @@ -130,9 +130,6 @@ contents of the given file path and converts them to a PHP value:: $value = Yaml::parseFile('/path/to/file.yml'); -.. versionadded:: 3.4 - The ``parseFile()`` method was introduced in Symfony 3.4. - If an error occurs during parsing, the parser throws a ``ParseException`` exception. .. _components-yaml-dump: @@ -216,10 +213,6 @@ changed using the third argument as follows:: Numeric Literals ................ -.. versionadded:: 3.2 - Support for parsing integers grouped by underscores was introduced in - Symfony 3.2. - Long numeric literals, being integer, float or hexadecimal, are known for their poor readability in code and configuration files. That's why YAML files allow to add underscores to improve their readability: diff --git a/components/yaml/yaml_format.rst b/components/yaml/yaml_format.rst index 01b601360b9..69bed7e2a5e 100644 --- a/components/yaml/yaml_format.rst +++ b/components/yaml/yaml_format.rst @@ -316,9 +316,6 @@ The YAML specification defines some tags to set the type of any data explicitly: Pz7Y6OjuDg4J+fn5OTk6enp 56enmleECcgggoBADs= -.. versionadded:: 3.4 - Support for the ``!!str`` tag was introduced in Symfony 3.4. - .. _YAML: http://yaml.org/ Unsupported YAML Features diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 248404dd242..8788cb4c47c 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -13,9 +13,6 @@ do this. Environment Variables --------------------- -.. versionadded:: 3.2 - ``env()`` parameters were introduced in Symfony 3.2. - You can reference environment variables by using special parameters named after the variables you want to use enclosed between ``env()``. Their actual values will be resolved at runtime (once per request), so that dumped containers can be @@ -122,12 +119,6 @@ of the following: .. tip:: - .. versionadded:: 3.3 - The support of the special ``SYMFONY__`` environment variables was - deprecated in Symfony 3.3 and it will be removed in 4.0. Instead of - using those variables, define regular environment variables and get - their values using the ``%env(...)%`` syntax in your config files. - You can also define the default value of any existing parameters using special environment variables named after their corresponding parameter prefixed with ``SYMFONY__`` after replacing dots by double underscores diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 8e834079271..4ca338def85 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -201,12 +201,6 @@ hold the kernel. Now it looks like this:: } } - -.. versionadded:: 3.4 - Support for annotation routing without an external bundle was added in - Symfony 3.4. Prior to version 3.4, you needed to install the - SensioFrameworkExtraBundle. - Unlike the previous kernel, this loads an external ``app/config/config.yml`` file, because the configuration started to get bigger: diff --git a/console.rst b/console.rst index 0c8a3f92706..8086b0e45fd 100644 --- a/console.rst +++ b/console.rst @@ -78,12 +78,6 @@ terminal: You can also manually register your command as a service by configuring the service and :doc:`tagging it ` with ``console.command``. -.. caution:: - - Symfony also looks in the ``Command/`` directory of bundles for commands - that are not registered as a service. But this auto discovery is deprecated - since Symfony 3.4 and won't be supported anymore in Symfony 4.0. - As you might expect, this command will do nothing as you didn't write any logic yet. Add your own logic inside the ``execute()`` method, which has access to the input stream (e.g. options and arguments) and the output stream (to write diff --git a/console/commands_as_services.rst b/console/commands_as_services.rst index a5e01ddb3da..217698bced8 100644 --- a/console/commands_as_services.rst +++ b/console/commands_as_services.rst @@ -8,11 +8,6 @@ If you're using the :ref:`default services.yaml configuration ` class that eases the diff --git a/controller.rst b/controller.rst index d0eb709837a..3418956d9ef 100644 --- a/controller.rst +++ b/controller.rst @@ -152,9 +152,6 @@ and many others that you'll learn about next. more robust code to access services. But if you *do* need direct access to the container, using ``Controller`` is fine. -.. versionadded:: 3.3 - The ``AbstractController`` class was added in Symfony 3.3. - .. index:: single: Controller; Redirecting @@ -243,10 +240,6 @@ The Symfony templating system and Twig are explained more in the Fetching Services as Controller Arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 3.3 - The ability to type-hint a controller argument in order to receive a service - was added in Symfony 3.3. - Symfony comes *packed* with a lot of useful objects, called :doc:`services `. These are used for rendering templates, sending emails, querying the database and any other "work" you can think of. @@ -457,10 +450,6 @@ Symfony provides a nice session object that you can use to store information about the user between requests. By default, Symfony stores the token in a cookie and writes the attributes to a file by using native PHP sessions. -.. versionadded:: 3.3 - The ability to request a ``Session`` instance in controllers was introduced - in Symfony 3.3. - To retrieve the session, add the :class:`Symfony\\Component\\HttpFoundation\\Session\\SessionInterface` type-hint to your argument and Symfony will provide you with a session:: @@ -568,10 +557,6 @@ read any flash messages from the session using ``app.flashes()``: -.. versionadded:: 3.3 - The ``app.flashes()`` Twig function was introduced in Symfony 3.3. Prior, - you had to use ``app.session.flashBag()``. - .. note:: It's common to use ``notice``, ``warning`` and ``error`` as the keys of the @@ -683,9 +668,6 @@ the :phpfunction:`json_encode` function is used. File helper ~~~~~~~~~~~ -.. versionadded:: 3.2 - The ``file()`` helper was introduced in Symfony 3.2. - You can use the :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::file` helper to serve a file from inside a controller:: diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index c69c81b4bbd..8ca6af7179d 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -15,9 +15,6 @@ functionality. Functionality Shipped with the HttpKernel ----------------------------------------- -.. versionadded:: 3.3 - The ``SessionValueResolver`` and ``ServiceValueResolver`` were both added in Symfony 3.3. - Symfony ships with five value resolvers in the HttpKernel component: :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver\\RequestAttributeValueResolver` diff --git a/form/create_form_type_extension.rst b/form/create_form_type_extension.rst index d2ef0bea408..cc2eefd8fa5 100644 --- a/form/create_form_type_extension.rst +++ b/form/create_form_type_extension.rst @@ -109,21 +109,14 @@ the ``getExtendedType()`` method. As *soon* as you do this, any method that you' overridden (e.g. ``buildForm()``) will be called whenever *any* field of the given type (``FileType``) is built. Let's see an example next. -.. versionadded:: 3.3 - Prior to Symfony 3.3, you needed to define type extension services as ``public``. - Starting from Symfony 3.3, you can also define them as ``private``. - .. tip:: - There is an optional tag attribute called ``priority``, which - defaults to ``0`` and controls the order in which the form - type extensions are loaded (the higher the priority, the earlier - an extension is loaded). This is useful when you need to guarantee + There is an optional tag attribute called ``priority``, which + defaults to ``0`` and controls the order in which the form + type extensions are loaded (the higher the priority, the earlier + an extension is loaded). This is useful when you need to guarantee that one extension is loaded before or after another extension. - .. versionadded:: 3.2 - The ``priority`` attribute was introduced in Symfony 3.2. - Adding the extension Business Logic ----------------------------------- diff --git a/form/form_customization.rst b/form/form_customization.rst index 3578b4c3df5..a80de5f7f50 100644 --- a/form/form_customization.rst +++ b/form/form_customization.rst @@ -121,9 +121,6 @@ fragment needed to render every part of a form: with the appropriate CSS classes to apply the default `Foundation CSS framework`_ styles. -.. versionadded:: 3.4 - The Bootstrap 4 form themes were introduced in Symfony 3.4. - .. caution:: When you use the Bootstrap form themes and render the fields manually, diff --git a/form/form_dependencies.rst b/form/form_dependencies.rst index 0a01af74553..b953156923f 100644 --- a/form/form_dependencies.rst +++ b/form/form_dependencies.rst @@ -139,10 +139,6 @@ manually and tag it with ``form.type``: ->addTag('form.type') ; -.. versionadded:: 3.3 - Prior to Symfony 3.3, you needed to define form type services as ``public``. - Starting from Symfony 3.3, you can also define them as ``private``. - That's it! Your controller - where you create the form - doesn't need to change at all: Symfony is smart enough to load the ``TaskType`` from the container. diff --git a/form/type_guesser.rst b/form/type_guesser.rst index 4ec50fc9712..073183d9c0f 100644 --- a/form/type_guesser.rst +++ b/form/type_guesser.rst @@ -216,10 +216,6 @@ and tag it with ``form.type_guesser``: ->addTag('form.type_guesser') ; -.. versionadded:: 3.3 - Prior to Symfony 3.3, you needed to define type guesser services as ``public``. - Starting from Symfony 3.3, you can also define them as ``private``. - .. sidebar:: Registering a Type Guesser in the Component If you're using the Form component standalone in your PHP project, use diff --git a/form/unit_testing.rst b/form/unit_testing.rst index b869eea2c26..5adf754b6eb 100644 --- a/form/unit_testing.rst +++ b/form/unit_testing.rst @@ -209,10 +209,6 @@ guessers using the :method:`Symfony\\Component\\Form\\Test\\FormIntegrationTestC and :method:`Symfony\\Component\\Form\\Test\\FormIntegrationTestCase::getTypeGuessers` methods. -.. versionadded:: 3.3 - The ``getTypes()``, ``getTypeExtensions()`` and ``getTypeGuessers()`` - methods were introduced in Symfony 3.3. - Testing against Different Sets of Data -------------------------------------- diff --git a/profiler/matchers.rst b/profiler/matchers.rst index 2e92a52a440..cb88c6021bd 100644 --- a/profiler/matchers.rst +++ b/profiler/matchers.rst @@ -6,158 +6,5 @@ How to Use Matchers to Enable the Profiler Conditionally .. caution:: - The possibility to use a matcher to enable the profiler conditionally is - deprecated since Symfony 3.4 and will be removed in 4.0. - -The Symfony profiler is only activated in the development environment to not hurt -your application performance. However, sometimes it may be useful to conditionally -enable the profiler in the production environment to assist you in debugging -issues. This behavior is implemented with the **Request Matchers**. - -Using the built-in Matcher --------------------------- - -A request matcher is a class that checks whether a given ``Request`` instance -matches a set of conditions. Symfony provides a -:class:`built-in matcher ` -which matches paths and IPs. For example, if you want to only show the profiler -when accessing the page with the ``168.0.0.1`` IP, then you can use this -configuration: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - # ... - profiler: - matcher: - ip: 168.0.0.1 - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('framework', array( - // ... - 'profiler' => array( - 'matcher' => array( - 'ip' => '168.0.0.1', - ) - ), - )); - -You can also set a ``path`` option to define the path on which the profiler -should be enabled. For instance, setting it to ``^/admin/`` will enable the -profiler only for the URLs which start with ``/admin/``. - -Creating a Custom Matcher -------------------------- - -Leveraging the concept of Request Matchers you can define a custom matcher to -enable the profiler conditionally in your application. To do so, create a class -which implements -:class:`Symfony\\Component\\HttpFoundation\\RequestMatcherInterface`. This -interface requires one method: -:method:`Symfony\\Component\\HttpFoundation\\RequestMatcherInterface::matches`. -This method returns ``false`` when the request doesn't match the conditions and -``true`` otherwise. Therefore, the custom matcher must return ``false`` to -disable the profiler and ``true`` to enable it. - -Suppose that the profiler must be enabled whenever a user with a -``ROLE_SUPER_ADMIN`` is logged in. This is the only code needed for that custom -matcher:: - - // src/Profiler/SuperAdminMatcher.php - namespace App\Profiler; - - use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; - use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpFoundation\RequestMatcherInterface; - - class SuperAdminMatcher implements RequestMatcherInterface - { - protected $authorizationChecker; - - public function __construct(AuthorizationCheckerInterface $authorizationChecker) - { - $this->authorizationChecker = $authorizationChecker; - } - - public function matches(Request $request) - { - return $this->authorizationChecker->isGranted('ROLE_SUPER_ADMIN'); - } - } - -Then, you'll need to make sure your class is defined as as service. If you're using -the :ref:`default services.yaml configuration `, -you don't need to do anything! - -Once the service is registered, the only thing left to do is configure the -profiler to use this service as the matcher: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - # ... - profiler: - matcher: - service: App\Profiler\SuperAdminMatcher - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - use App\Profiler\SuperAdminMatcher; - - $container->loadFromExtension('framework', array( - // ... - 'profiler' => array( - 'matcher' => array( - 'service' => SuperAdminMatcher::class, - ) - ), - )); + The possibility to use a matcher to enable the profiler conditionally was + removed in Symfony 4.0. diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index edd21d87aa2..a91929a2f03 100644 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -334,10 +334,6 @@ And you can display the flash message in the template like this: {% endfor %} -.. versionadded:: 3.3 - The ``app.flashes()`` Twig function was introduced in Symfony 3.3. Prior, - you had to use ``app.session.flashBag()``. - Final Thoughts -------------- diff --git a/reference/configuration/debug.rst b/reference/configuration/debug.rst index 223879b486a..b9185488a68 100644 --- a/reference/configuration/debug.rst +++ b/reference/configuration/debug.rst @@ -41,9 +41,6 @@ be cloned. After this depth is reached, only ``max_items`` items will be cloned. The default value is ``1``, which is consistent with older Symfony versions. -.. versionadded:: 3.4 - The ``min_depth`` option was introduced in Symfony 3.4. - max_string_length ~~~~~~~~~~~~~~~~~ diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 2ed76242b59..ed31f8f4dce 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -46,10 +46,6 @@ Configuration * `only_exceptions`_ * `only_master_requests`_ * `dsn`_ - * `matcher`_ - * `ip`_ - * :ref:`path ` - * `service`_ * `request`_: * `formats`_ * `router`_ @@ -277,9 +273,6 @@ need to escape the percent signs (``%``) by doubling them. // and /foo/.../file as /bar/.../file also 'myide://%f:%l&/path/to/guest/>/path/to/host/&/foo/>/bar/&...' - .. versionadded:: 3.2 - Guest to host mappings were introduced in Symfony 3.2. - .. _reference-framework-test: test @@ -576,44 +569,6 @@ The DSN where to store the profiling information. See :doc:`/profiler/storage` for more information about the profiler storage. -matcher -....... - -.. caution:: - - This option is deprecated since Symfony 3.4 and will be removed in 4.0. - -Matcher options are configured to dynamically enable the profiler. For -instance, based on the `ip`_ or :ref:`path `. - -.. seealso:: - - See :doc:`/profiler/matchers` for more information about using - matchers to enable/disable the profiler. - -ip -"" - -**type**: ``string`` - -If set, the profiler will only be enabled when the current IP address matches. - -.. _reference-profiler-matcher-path: - -path -"""" - -**type**: ``string`` - -If set, the profiler will only be enabled when the current path matches. - -service -""""""" - -**type**: ``string`` - -This setting contains the service id of a custom matcher. - request ~~~~~~~ @@ -1300,10 +1255,6 @@ json_manifest_path **type**: ``string`` **default**: ``null`` -.. versionadded:: 3.3 - - The ``json_manifest_path`` option was introduced in Symfony 3.3. - The file path to a ``manifest.json`` file containing an associative array of asset names and their respective compiled names. A common cache-busting technique using a "manifest" file works by writing out assets with a "hash" appended to their @@ -1772,9 +1723,6 @@ php_errors log ... -.. versionadded:: 3.2 - The ``log`` option was introduced in Symfony 3.2. - **type**: ``boolean`` **default**: ``false`` Use the application logger instead of the PHP logger for logging PHP errors. @@ -1782,9 +1730,6 @@ Use the application logger instead of the PHP logger for logging PHP errors. throw ..... -.. versionadded:: 3.2 - The ``throw`` option was introduced in Symfony 3.2. - **type**: ``boolean`` **default**: ``%kernel.debug%`` Throw PHP errors as ``\ErrorException`` instances. The parameter @@ -1854,9 +1799,6 @@ service. default_memcached_provider .......................... -.. versionadded:: 3.3 - The ``default_memcached_provider`` option was introduced in Symfony 3.3. - **type**: ``string`` **default**: ``memcached://localhost`` The DSN to use by the Memcached provider. The provider is available as the ``cache.memcached`` diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 3a0e51fbda3..592da9ab03d 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -53,40 +53,9 @@ generation of cache files. If you have an application with multiple kernels, the easiest way to make each have a unique name is to duplicate the ``app`` directory and rename it to something else (e.g. ``foo``). -Root Directory -~~~~~~~~~~~~~~ - -.. versionadded:: 3.3 - The ``getRootDir()`` method is deprecated since Symfony 3.3. Use the new - ``getProjectDir()`` method instead. - -**type**: ``string`` **default**: the directory of ``AppKernel`` - -This returns the root directory of your kernel. If you use the Symfony Standard -edition, the root directory refers to the ``app`` directory. - -To change this setting, override the -:method:`Symfony\\Component\\HttpKernel\\Kernel::getRootDir` method:: - - // app/AppKernel.php - - // ... - class AppKernel extends Kernel - { - // ... - - public function getRootDir() - { - return realpath(parent::getRootDir().'/../'); - } - } - Project Directory ~~~~~~~~~~~~~~~~~ -.. versionadded:: 3.3 - The ``getProjectDir()`` method was introduced in Symfony 3.3. - **type**: ``string`` **default**: the directory of the project ``composer.json`` This returns the root directory of your Symfony project. It's calculated as diff --git a/reference/configuration/security.rst b/reference/configuration/security.rst index 9e2fd48bb88..b533460fd94 100644 --- a/reference/configuration/security.rst +++ b/reference/configuration/security.rst @@ -31,24 +31,6 @@ Each part will be explained in the next section. allow_if_all_abstain: false allow_if_equal_granted_denied: true - # ACL support was deprecated in Symfony 3.4 and removed in Symfony 4.0 - # Use https://github.com/symfony/acl-bundle instead - acl: - # any name configured in doctrine.dbal section - connection: ~ - cache: - id: ~ - prefix: sf2_acl_ - provider: ~ - tables: - class: acl_classes - entry: acl_entries - object_identity: acl_object_identities - object_identity_ancestors: acl_object_identity_ancestors - security_identity: acl_security_identities - voter: - allow_if_object_identity_unavailable: true - encoders: # Examples: Acme\DemoBundle\Entity\User1: sha512 diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index f0338e68857..c5c2a0acf54 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -141,12 +141,6 @@ TwigBundle Configuration ("twig") 'default_path' => '%kernel.project_dir%/templates', )); -.. caution:: - - The ``twig.form`` (```` tag for xml) configuration key - has been deprecated and will be removed in 3.0. Instead, use the ``twig.form_themes`` - option. - Configuration ------------- @@ -346,9 +340,6 @@ default_path **type**: ``string`` **default**: ``'%kernel.project_dir%/templates'`` -.. versionadded:: 3.4 - The ``default_path`` option was introduced in Symfony 3.4. - The default directory where Symfony will look for Twig templates. .. _config-twig-paths: diff --git a/reference/configuration/web_profiler.rst b/reference/configuration/web_profiler.rst index 2512142b239..2943b476cb6 100644 --- a/reference/configuration/web_profiler.rst +++ b/reference/configuration/web_profiler.rst @@ -15,10 +15,8 @@ Configuration ------------- * `toolbar`_ -* `position`_ * `intercept_redirects`_ * `excluded_ajax_paths`_ -* `verbose`_ toolbar ~~~~~~~ @@ -29,14 +27,6 @@ It enables and disables the toolbar entirely. Usually you set this to ``true`` in the ``dev`` and ``test`` environments and to ``false`` in the ``prod`` environment. -position -~~~~~~~~ - -**type**: ``string`` **default**: ``bottom`` - -It defines the location of the browser window where the toolbar is displayed. -the only allowed values are ``bottom`` and ``top``. - intercept_redirects ~~~~~~~~~~~~~~~~~~~ @@ -61,14 +51,6 @@ expression. If the URL matches, the request is not displayed in the toolbar. Thi is useful when the application makes lots of Ajax requests or they are heavy and you want to exclude some of them. -verbose -~~~~~~~ - -**type**: ``boolean`` **default**: ``true`` - -This option is **deprecated** and has no effect on the toolbar or the profiler, -so you can safely remove it from your configuration. - Full Default Configuration -------------------------- @@ -79,13 +61,9 @@ Full Default Configuration # app/config/config.yml web_profiler: toolbar: false - position: bottom intercept_redirects: false excluded_ajax_paths: ^/bundles|^/_wdt - # DEPRECATED, it can be removed safely from your configuration - verbose: true - .. code-block:: xml @@ -100,7 +78,6 @@ Full Default Configuration diff --git a/reference/constraints/Choice.rst b/reference/constraints/Choice.rst index c4b4931f8ef..777b174fb80 100644 --- a/reference/constraints/Choice.rst +++ b/reference/constraints/Choice.rst @@ -144,9 +144,6 @@ form element. } } -.. versionadded:: 3.2 - As of Symfony 3.2 the callback no longer needs to be static. - You can pass the name of this method to the `callback`_ option of the ``Choice`` constraint. @@ -374,9 +371,4 @@ The validator will also check the type of the input value. Specifically, this value is passed to as the third argument to the PHP :phpfunction:`in_array` method when checking to see if a value is in the valid choices array. -.. caution:: - - Setting the strict option of the Choice Constraint to ``false`` has been - deprecated as of Symfony 3.2 and the option will be changed to ``true`` as of 4.0. - .. include:: /reference/constraints/_payload-option.rst.inc diff --git a/reference/constraints/Image.rst b/reference/constraints/Image.rst index df968e316ef..5fe3c57c3a2 100644 --- a/reference/constraints/Image.rst +++ b/reference/constraints/Image.rst @@ -277,9 +277,6 @@ value in pixels. minPixels ~~~~~~~~~ -.. versionadded:: 3.4 - The ``minPixels`` option has been introduced in Symfony 3.4. - **type**: ``integer`` If set, the amount of pixels of the image file must be greater than or equal to this @@ -288,9 +285,6 @@ value. maxPixels ~~~~~~~~~ -.. versionadded:: 3.4 - The ``maxPixels`` option has been introduced in Symfony 3.4. - **type**: ``integer`` If set, the amount of pixels of the image file must be less than or equal to this @@ -388,9 +382,6 @@ The error message if the height of the image is less than `minHeight`_. maxPixelsMessage ~~~~~~~~~~~~~~~~ -.. versionadded:: 3.4 - The ``maxPixelsMessage`` option has been introduced in Symfony 3.4. - **type**: ``string`` **default**: ``The image has to many pixels ({{ pixels }} pixels). Maximum amount expected is {{ max_pixels }} pixels.`` @@ -399,9 +390,6 @@ The error message if the amount of pixels of the image exceeds `maxPixels`_. minPixelsMessage ~~~~~~~~~~~~~~~~ -.. versionadded:: 3.4 - The ``minPixelsMessage`` option has been introduced in Symfony 3.4. - **type**: ``string`` **default**: ``The image has to few pixels ({{ pixels }} pixels). Minimum amount expected is {{ min_pixels }} pixels.`` diff --git a/reference/constraints/UniqueEntity.rst b/reference/constraints/UniqueEntity.rst index d95547d9275..b56025be2aa 100644 --- a/reference/constraints/UniqueEntity.rst +++ b/reference/constraints/UniqueEntity.rst @@ -164,9 +164,6 @@ This method should return a countable result. entityClass ~~~~~~~~~~~ -.. versionadded:: 3.2 - The ``entityClass`` option was introduced in Symfony 3.2. - **type**: ``string`` By default, the query performed to ensure the uniqueness uses the repository of diff --git a/reference/dic_tags.rst b/reference/dic_tags.rst index 162fa9d0282..b979da368f9 100644 --- a/reference/dic_tags.rst +++ b/reference/dic_tags.rst @@ -506,11 +506,6 @@ Cache warming occurs whenever you run the ``cache:warmup`` or ``cache:clear`` command (unless you pass ``--no-warmup`` to ``cache:clear``). It is also run when handling the request, if it wasn't done by one of the commands yet. -.. versionadded:: 3.3 - Starting from Symfony 3.3, the warm-up part of the ``cache:clear`` command - is deprecated. You must always pass the ``--no-warmup`` option to - ``cache:clear`` and use ``cache:warmup`` instead to warm-up the cache. - The purpose is to initialize any cache that will be needed by the application and prevent the first user from any significant "cache hit" where the cache is generated dynamically. diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index e59f0b56a5c..fe5e2b8d6da 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -19,7 +19,6 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | | - `choice_name`_ | | | - `choice_translation_domain`_ | | | - `choice_value`_ | -| | - `choices_as_values`_ (deprecated) | | | - `expanded`_ | | | - `group_by`_ | | | - `multiple`_ | @@ -184,11 +183,7 @@ The ``choice_loader`` can be used to only partially load the choices in cases wh a fully-loaded list is not necessary. This is only needed in advanced cases and would replace the ``choices`` option. -.. versionadded:: 3.2 - The :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\CallbackChoiceLoader` - was introduced in Symfony 3.2. - -You can use an instance of :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\CallbackChoiceLoader` +You can use an instance of :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\CallbackChoiceLoader` if you want to take advantage of lazy loading:: use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; @@ -211,12 +206,6 @@ the choice options would need to be resolved thus triggering the callback. .. include:: /reference/forms/types/options/choice_value.rst.inc -choices_as_values -~~~~~~~~~~~~~~~~~ - -This option is deprecated and you should remove it from your 3.x projects (removing -it will have *no* effect). For its purpose in 2.x, see the 2.7 documentation. - .. include:: /reference/forms/types/options/expanded.rst.inc .. include:: /reference/forms/types/options/group_by.rst.inc diff --git a/reference/forms/types/collection.rst b/reference/forms/types/collection.rst index 8b5d2cbb4dc..6887093ab3d 100644 --- a/reference/forms/types/collection.rst +++ b/reference/forms/types/collection.rst @@ -304,10 +304,6 @@ the value is removed from the collection. For example:: Using a callable is particularly useful in case of compound form types, which may define complex conditions for considering them empty. -.. versionadded:: 3.4 - Support for using a callable for the ``delete_empty`` option was introduced - in Symfony 3.4. - entry_options ~~~~~~~~~~~~~ diff --git a/reference/forms/types/country.rst b/reference/forms/types/country.rst index 49d9d121f01..cbb052716e7 100644 --- a/reference/forms/types/country.rst +++ b/reference/forms/types/country.rst @@ -63,8 +63,7 @@ The locale is used to translate the countries names. .. caution:: If you want to override the built-in choices of the country type, you - will also have to set the ``choice_loader`` option to ``null``. Not doing - so is deprecated since Symfony 3.3. + will also have to set the ``choice_loader`` option to ``null``. Inherited Options ----------------- diff --git a/reference/forms/types/currency.rst b/reference/forms/types/currency.rst index 2dc15904105..af0f623a3b7 100644 --- a/reference/forms/types/currency.rst +++ b/reference/forms/types/currency.rst @@ -54,8 +54,7 @@ The choices option defaults to all currencies. .. caution:: If you want to override the built-in choices of the currency type, you - will also have to set the ``choice_loader`` option to ``null``. Not doing - so is deprecated since Symfony 3.3. + will also have to set the ``choice_loader`` option to ``null``. Inherited Options ----------------- diff --git a/reference/forms/types/dateinterval.rst b/reference/forms/types/dateinterval.rst index 6cb573cc3da..fdd6a6f19ac 100644 --- a/reference/forms/types/dateinterval.rst +++ b/reference/forms/types/dateinterval.rst @@ -4,9 +4,6 @@ DateIntervalType Field ====================== -.. versionadded:: 3.2 - The DateIntervalType field type was introduced in Symfony 3.2. - This field allows the user to select an *interval* of time. For example, if you want to allow the user to choose *how often* they receive a status email, they could use this field to choose intervals like every "10 minutes" or "3 days". @@ -132,9 +129,6 @@ this format. labels ~~~~~~ -.. versionadded:: 3.3 - The ``labels`` option was introduced in Symfony 3.3. - **type**: ``array`` **default**: (see below) The labels displayed for each of the elements of this type. The default values diff --git a/reference/forms/types/language.rst b/reference/forms/types/language.rst index 2d221738b46..5d4a281eb6a 100644 --- a/reference/forms/types/language.rst +++ b/reference/forms/types/language.rst @@ -65,8 +65,7 @@ The default locale is used to translate the languages names. .. caution:: If you want to override the built-in choices of the language type, you - will also have to set the ``choice_loader`` option to ``null``. Not doing - so is deprecated since Symfony 3.3. + will also have to set the ``choice_loader`` option to ``null``. Inherited Options ----------------- diff --git a/reference/forms/types/locale.rst b/reference/forms/types/locale.rst index ca9c02e55f7..af77364e79d 100644 --- a/reference/forms/types/locale.rst +++ b/reference/forms/types/locale.rst @@ -66,8 +66,7 @@ specify the language. .. caution:: If you want to override the built-in choices of the locale type, you - will also have to set the ``choice_loader`` option to ``null``. Not doing - so is deprecated since Symfony 3.3. + will also have to set the ``choice_loader`` option to ``null``. Inherited Options ----------------- diff --git a/reference/forms/types/timezone.rst b/reference/forms/types/timezone.rst index b3fbfb2ff29..9c99f6c5c82 100644 --- a/reference/forms/types/timezone.rst +++ b/reference/forms/types/timezone.rst @@ -59,8 +59,7 @@ The Timezone type defaults the choices to all timezones returned by .. caution:: If you want to override the built-in choices of the timezone type, you - will also have to set the ``choice_loader`` option to ``null``. Not doing - so is deprecated since Symfony 3.3. + will also have to set the ``choice_loader`` option to ``null``. Inherited Options ----------------- diff --git a/routing.rst b/routing.rst index d6bcbc65637..843cd507808 100644 --- a/routing.rst +++ b/routing.rst @@ -488,9 +488,6 @@ that are special: each adds a unique piece of functionality inside your applicat Used to set the fragment identifier, the optional last part of a URL that starts with a ``#`` character and is used to identify a portion of a document. - .. versionadded:: 3.2 - The ``_fragment`` parameter was introduced in Symfony 3.2. - ``_locale`` Used to set the locale on the request (:ref:`read more `). diff --git a/routing/requirements.rst b/routing/requirements.rst index 78383d28c1b..4a6dd5a8592 100644 --- a/routing/requirements.rst +++ b/routing/requirements.rst @@ -161,14 +161,9 @@ Path Parameters .. note:: - Since Symfony 3.2, you can enable UTF-8 route matching by setting the ``utf8`` - option when declaring or importing routes. This will make e.g. a ``.`` in - requirements match any UTF-8 characters instead of just a single byte. - The option is automatically enabled whenever a route or a requirement uses any - non-ASCII UTF-8 characters or a `PCRE Unicode property`_ (``\p{xx}``, - ``\P{xx}`` or ``\X``). Note that this behavior is deprecated and a - ``LogicException`` will be thrown instead in 4.0 unless you explicitly turn - on the ``utf8`` option. + You can enable UTF-8 route matching by setting the ``utf8`` option when + declaring or importing routes. This will make e.g. a ``.`` in requirements + match any UTF-8 characters instead of just a single byte. .. tip:: diff --git a/security.rst b/security.rst index 4038d031d3f..9a2b607f63e 100644 --- a/security.rst +++ b/security.rst @@ -969,29 +969,17 @@ For more details on expressions and security, see :doc:`/security/expressions`. Access Control Lists (ACLs): Securing individual Database Objects ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 3.4 - ACL support was deprecated in Symfony 3.4 and will be removed in 4.0. Install - the `Symfony ACL bundle`_ if you want to keep using ACL. - Imagine you are designing a blog where users can comment on your posts. You also want a user to be able to edit their own comments, but not those of other users. Also, as the admin user, you yourself want to be able to edit *all* comments. -To accomplish this you have 2 options: - -* :doc:`Voters ` allow you to write own business logic - (e.g. the user can edit this post because they were the creator) to determine - access. You'll probably want this option - it's flexible enough to solve the - above situation. +:doc:`Voters ` allow you to write own business logic (e.g. the +user can edit this post because they were the creator) to determine access. +That's why voters are officially recommended by Symfony to create ACL-like +security systems. -* :doc:`ACLs ` allow you to create a database structure - where you can assign *any* arbitrary user *any* access (e.g. EDIT, VIEW) - to *any* object in your system. Use this if you need an admin user to be - able to grant customized access across your system via some admin interface. - -In both cases, you'll still deny access using methods similar to what was -shown above. +If you still prefer to use traditional ACLs, refer to the `Symfony ACL bundle`_. 3) Retrieving the User Object ----------------------------- @@ -1015,10 +1003,6 @@ look like:: The user will be an object and the class of that object will depend on your :ref:`user provider `. -.. versionadded:: 3.2 - The ability to get the user by type-hinting an argument with UserInterface - was introduced in Symfony 3.2. - Now you can call whatever methods are on *your* User object. For example, if your User object has a ``getFirstName()`` method, you could use that:: diff --git a/security/acl.rst b/security/acl.rst index 8f06329fc39..b09c6364b46 100644 --- a/security/acl.rst +++ b/security/acl.rst @@ -4,251 +4,9 @@ How to Use Access Control Lists (ACLs) ====================================== -.. versionadded:: 3.4 - ACL support was deprecated in Symfony 3.4 and will be removed in 4.0. Install - the `Symfony ACL bundle`_ if you wan to keep using ACL. +.. caution:: -In complex applications, you will often face the problem that access decisions -cannot only be based on the person (``Token``) who is requesting access, but -also involve a domain object that access is being requested for. This is where -the ACL system comes in. - -.. sidebar:: Alternatives to ACLs - - Using ACL's isn't trivial, and for simpler use cases, it may be overkill. - If your permission logic could be described by just writing some code (e.g. - to check if a Blog is owned by the current User), then consider using - :doc:`voters `. A voter is passed the object - being voted on, which you can use to make complex decisions and effectively - implement your own ACL. Enforcing authorization (e.g. the ``isGranted()`` - part) will look similar to what you see in this entry, but your voter - class will handle the logic behind the scenes, instead of the ACL system. - -Imagine you are designing a blog system where your users can comment on your -posts. Now, you want a user to be able to edit their own comments, but not those -of other users; besides, you want to be able to edit all comments. In -this scenario, ``Comment`` would be the domain object that you want to -restrict access to. You could take several approaches to accomplish this using -Symfony, two basic approaches are (non-exhaustive): - -- *Enforce security in your business methods*: Basically, that means keeping a - reference inside each ``Comment`` to all users who have access, and then - compare these users to the provided ``Token``. -- *Enforce security with roles*: In this approach, you would add a role for - each ``Comment`` object, i.e. ``ROLE_COMMENT_1``, ``ROLE_COMMENT_2``, etc. - -Both approaches are perfectly valid. However, they couple your authorization -logic to your business code which makes it less reusable elsewhere, and also -increases the difficulty of unit testing. Besides, you could run into -performance issues if many users would have access to a single domain object. - -Fortunately, there is a better way, which you will find out about now. - -Bootstrapping -------------- - -Now, before you can finally get into action, you need to do some bootstrapping. -First, you need to configure the connection the ACL system is supposed to use: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/security.yml - security: - # ... - - acl: - connection: default - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // app/config/security.php - $container->loadFromExtension('security', array( - // ... - - 'acl' => array( - 'connection' => 'default', - ), - )); - -.. note:: - - The ACL system requires a connection from either Doctrine DBAL (usable by - default) or Doctrine MongoDB (usable with `MongoDBAclBundle`_). However, - that does not mean that you have to use Doctrine ORM or ODM for mapping your - domain objects. You can use whatever mapper you like for your objects, be it - Doctrine ORM, MongoDB ODM, Propel, raw SQL, etc. The choice is yours. - -After the connection is configured, you have to import the database structure -running the following command: - -.. code-block:: terminal - - $ php bin/console init:acl - -Getting Started ---------------- - -Coming back to the small example from the beginning, you can now implement -ACL for it. - -Once the ACL is created, you can grant access to objects by creating an -Access Control Entry (ACE) to solidify the relationship between the entity -and your user. - -Creating an ACL and Adding an ACE -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: php - - // src/Controller/BlogController.php - namespace App\Controller; - - use Symfony\Bundle\FrameworkBundle\Controller\Controller; - use Symfony\Component\Security\Core\Exception\AccessDeniedException; - use Symfony\Component\Security\Acl\Domain\ObjectIdentity; - use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; - use Symfony\Component\Security\Acl\Permission\MaskBuilder; - - class BlogController extends Controller - { - // ... - - public function addCommentAction(Post $post) - { - $comment = new Comment(); - - // ... setup $form, and submit data - - if ($form->isSubmitted() && $form->isValid()) { - $entityManager = $this->getDoctrine()->getManager(); - $entityManager->persist($comment); - $entityManager->flush(); - - // creating the ACL - $aclProvider = $this->get('security.acl.provider'); - $objectIdentity = ObjectIdentity::fromDomainObject($comment); - $acl = $aclProvider->createAcl($objectIdentity); - - // retrieving the security identity of the currently logged-in user - $tokenStorage = $this->get('security.token_storage'); - $user = $tokenStorage->getToken()->getUser(); - $securityIdentity = UserSecurityIdentity::fromAccount($user); - - // grant owner access - $acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_OWNER); - $aclProvider->updateAcl($acl); - } - } - } - -There are a couple of important implementation decisions in this code snippet. -For now, I only want to highlight two: - -First, you may have noticed that ``->createAcl()`` does not accept domain -objects directly, but only implementations of the ``ObjectIdentityInterface``. -This additional step of indirection allows you to work with ACLs even when you -have no actual domain object instance at hand. This will be extremely helpful -if you want to check permissions for a large number of objects without -actually hydrating these objects. - -The other interesting part is the ``->insertObjectAce()`` call. In the -example, you are granting the user who is currently logged in owner access to -the Comment. The ``MaskBuilder::MASK_OWNER`` is a pre-defined integer bitmask; -don't worry the mask builder will abstract away most of the technical details, -but using this technique you can store many different permissions in one -database row which gives a considerable boost in performance. - -.. tip:: - - The order in which ACEs are checked is significant. As a general rule, you - should place more specific entries at the beginning. - -Checking Access -~~~~~~~~~~~~~~~ - -.. code-block:: php - - // src/Controller/BlogController.php - - // ... - - class BlogController - { - // ... - - public function editCommentAction(Comment $comment) - { - $authorizationChecker = $this->get('security.authorization_checker'); - - // check for edit access - if (false === $authorizationChecker->isGranted('EDIT', $comment)) { - throw new AccessDeniedException(); - } - - // ... retrieve actual comment object, and do your editing here - } - } - -In this example, you check whether the user has the ``EDIT`` permission. -Internally, Symfony maps the permission to several integer bitmasks, and -checks whether the user has any of them. - -.. note:: - - You can define up to 32 base permissions (depending on your OS PHP might - vary between 30 to 32). In addition, you can also define cumulative - permissions. - -Cumulative Permissions ----------------------- - -In the first example above, you only granted the user the ``OWNER`` base -permission. While this effectively also allows the user to perform any -operation such as view, edit, etc. on the domain object, there are cases where -you may want to grant these permissions explicitly. - -The ``MaskBuilder`` can be used for creating bit masks easily by combining -several base permissions: - -.. code-block:: php - - $builder = new MaskBuilder(); - $builder - ->add('view') - ->add('edit') - ->add('delete') - ->add('undelete') - ; - $mask = $builder->get(); // int(29) - -This integer bitmask can then be used to grant a user the base permissions you -added above: - -.. code-block:: php - - $identity = new UserSecurityIdentity('johannes', 'App\Entity\User'); - $acl->insertObjectAce($identity, $mask); - -The user is now allowed to view, edit, delete, and un-delete objects. + ACL support was removed in Symfony 4.0. Install the `Symfony ACL bundle`_ + and refer to its documentation if you want to keep using ACL. .. _`Symfony ACL bundle`: https://github.com/symfony/acl-bundle -.. _`MongoDBAclBundle`: https://github.com/IamPersistent/MongoDBAclBundle diff --git a/security/acl_advanced.rst b/security/acl_advanced.rst index ca88be07c31..062d69a8b8a 100644 --- a/security/acl_advanced.rst +++ b/security/acl_advanced.rst @@ -4,200 +4,9 @@ How to Use advanced ACL Concepts ================================ -.. versionadded:: 3.4 - ACL support was deprecated in Symfony 3.4 and will be removed in 4.0. Install - the `Symfony ACL bundle`_ if you wan to keep using ACL. - -The aim of this article is to give a more in-depth view of the ACL system, and -also explain some of the design decisions behind it. - -Design Concepts ---------------- - -Symfony's object instance security capabilities are based on the concept of -an Access Control List. Every domain object **instance** has its own ACL. The -ACL instance holds a detailed list of Access Control Entries (ACEs) which are -used to make access decisions. Symfony's ACL system focuses on two main -objectives: - -- providing a way to efficiently retrieve a large amount of ACLs/ACEs for your - domain objects, and to modify them; -- providing a way to easily make decisions of whether a person is allowed to - perform an action on a domain object or not. - -As indicated by the first point, one of the main capabilities of Symfony's -ACL system is a high-performance way of retrieving ACLs/ACEs. This is -extremely important since each ACL might have several ACEs, and inherit from -another ACL in a tree-like fashion. Therefore, no ORM is leveraged, instead -the default implementation interacts with your connection directly using Doctrine's -DBAL. - -Object Identities -~~~~~~~~~~~~~~~~~ - -The ACL system is completely decoupled from your domain objects. They don't -even have to be stored in the same database, or on the same server. In order -to achieve this decoupling, in the ACL system your objects are represented -through object identity objects. Every time you want to retrieve the ACL for a -domain object, the ACL system will first create an object identity from your -domain object, and then pass this object identity to the ACL provider for -further processing. - -Security Identities -~~~~~~~~~~~~~~~~~~~ - -This is analog to the object identity, but represents a user, or a role in -your application. Each role, or user has its own security identity. - .. caution:: - For users, the security identity is based on the username. This means that, - if for any reason, a user's username was to change, you must ensure its - security identity is updated too. The - :method:`MutableAclProvider::updateUserSecurityIdentity() ` - method is there to handle the update. - -Database Table Structure ------------------------- - -The default implementation uses five database tables as listed below. The -tables are ordered from least rows to most rows in a typical application: - -- *acl_security_identities*: This table records all security identities (SID) - which hold ACEs. The default implementation ships with two security - identities: - :class:`Symfony\\Component\\Security\\Acl\\Domain\\RoleSecurityIdentity` and - :class:`Symfony\\Component\\Security\\Acl\\Domain\\UserSecurityIdentity`. -- *acl_classes*: This table maps class names to a unique ID which can be - referenced from other tables. -- *acl_object_identities*: Each row in this table represents a single domain - object instance. -- *acl_object_identity_ancestors*: This table allows all the ancestors of - an ACL to be determined in a very efficient way. -- *acl_entries*: This table contains all ACEs. This is typically the table - with the most rows. It can contain tens of millions without significantly - impacting performance. - -.. _security-acl-field_scope: - -Scope of Access Control Entries -------------------------------- - -Access control entries can have different scopes in which they apply. In -Symfony, there are basically two different scopes: - -- Class-Scope: These entries apply to all objects with the same class. -- Object-Scope: This was the scope solely used in the previous article, and - it only applies to one specific object. - -Sometimes, you will find the need to apply an ACE only to a specific field of -the object. Suppose you want the ID only to be viewable by an administrator, -but not by your customer service. To solve this common problem, two more sub-scopes -have been added: - -- Class-Field-Scope: These entries apply to all objects with the same class, - but only to a specific field of the objects. -- Object-Field-Scope: These entries apply to a specific object, and only to a - specific field of that object. - -Pre-Authorization Decisions ---------------------------- - -For pre-authorization decisions, that is decisions made before any secure method (or -secure action) is invoked, the proven AccessDecisionManager service is used. -The AccessDecisionManager is also used for reaching authorization decisions based -on roles. Just like roles, the ACL system adds several new attributes which may be -used to check for different permissions. - -Built-in Permission Map -~~~~~~~~~~~~~~~~~~~~~~~ - -+------------------+----------------------------+-----------------------------+ -| Attribute | Intended Meaning | Integer Bitmasks | -+==================+============================+=============================+ -| VIEW | Whether someone is allowed | VIEW, EDIT, OPERATOR, | -| | to view the domain object. | MASTER, or OWNER | -+------------------+----------------------------+-----------------------------+ -| EDIT | Whether someone is allowed | EDIT, OPERATOR, MASTER, | -| | to make changes to the | or OWNER | -| | domain object. | | -+------------------+----------------------------+-----------------------------+ -| CREATE | Whether someone is allowed | CREATE, OPERATOR, MASTER, | -| | to create the domain | or OWNER | -| | object. | | -+------------------+----------------------------+-----------------------------+ -| DELETE | Whether someone is allowed | DELETE, OPERATOR, MASTER, | -| | to delete the domain | or OWNER | -| | object. | | -+------------------+----------------------------+-----------------------------+ -| UNDELETE | Whether someone is allowed | UNDELETE, OPERATOR, MASTER, | -| | to restore a previously | or OWNER | -| | deleted domain object. | | -+------------------+----------------------------+-----------------------------+ -| OPERATOR | Whether someone is allowed | OPERATOR, MASTER, or OWNER | -| | to perform all of the above| | -| | actions. | | -+------------------+----------------------------+-----------------------------+ -| MASTER | Whether someone is allowed | MASTER, or OWNER | -| | to perform all of the above| | -| | actions, and in addition is| | -| | allowed to grant | | -| | any of the above | | -| | permissions to others. | | -+------------------+----------------------------+-----------------------------+ -| OWNER | Whether someone owns the | OWNER | -| | domain object. An owner can| | -| | perform any of the above | | -| | actions *and* grant master | | -| | and owner permissions. | | -+------------------+----------------------------+-----------------------------+ - -Permission Attributes vs. Permission Bitmasks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Attributes are used by the AccessDecisionManager, just like roles. Often, these -attributes represent in fact an aggregate of integer bitmasks. Integer bitmasks on -the other hand, are used by the ACL system internally to efficiently store your -users' permissions in the database, and perform access checks using extremely -fast bitmask operations. - -Extensibility -~~~~~~~~~~~~~ - -The above permission map is by no means static, and theoretically could be -completely replaced at will. However, it should cover most problems you -encounter, and for interoperability with other bundles, you are encouraged to -stick to the meaning envisaged for them. - -Post Authorization Decisions ----------------------------- - -Post authorization decisions are made after a secure method has been invoked, -and typically involve the domain object which is returned by such a method. -After invocation providers also allow to modify, or filter the domain object -before it is returned. - -Due to current limitations of the PHP language, there are no -post-authorization capabilities build into the core Security component. -However, there is an experimental JMSSecurityExtraBundle_ which adds these -capabilities. See its documentation for further information on how this is -accomplished. - -Process for Reaching Authorization Decisions --------------------------------------------- - -The ACL class provides two methods for determining whether a security identity -has the required bitmasks, ``isGranted()`` and ``isFieldGranted()``. When the ACL -receives an authorization request through one of these methods, it delegates -this request to an implementation of -:class:`Symfony\\Component\\Security\\Acl\\Domain\\PermissionGrantingStrategy`. -This allows you to replace the way access decisions are reached without actually -modifying the ACL class itself. - -The ``PermissionGrantingStrategy`` first checks all your object-scope ACEs. If one -is applicable, the class-scope ACEs will be checked. If none is applicable, -then the process will be repeated with the ACEs of the parent ACL. If no -parent ACL exists, an exception will be thrown. + ACL support was removed in Symfony 4.0. Install the `Symfony ACL bundle`_ + and refer to its documentation if you want to keep using ACL. .. _`Symfony ACL bundle`: https://github.com/symfony/acl-bundle -.. _JMSSecurityExtraBundle: https://github.com/schmittjoh/JMSSecurityExtraBundle diff --git a/security/guard_authentication.rst b/security/guard_authentication.rst index ac5ebf7d6ee..b09dbfbcd46 100644 --- a/security/guard_authentication.rst +++ b/security/guard_authentication.rst @@ -249,10 +249,6 @@ This requires you to implement several methods:: } } -.. versionadded:: 3.4 - ``AuthenticatorInterface`` was introduced in Symfony 3.4. In previous Symfony - versions, authenticators needed to implement ``GuardAuthenticatorInterface``. - Nice work! Each method is explained below: :ref:`The Guard Authenticator Methods`. Step 2) Configure the Authenticator @@ -370,11 +366,6 @@ Each authenticator needs the following methods: authenticator should be used for this request (return ``true``) or if it should be skipped (return ``false``). - .. versionadded:: 3.4 - The ``supports()`` method was introduced in Symfony 3.4. In previous Symfony - versions, the authenticator could be skipped returning ``null`` in the - ``getCredentials()`` method. - **getCredentials(Request $request)** This will be called on *every* request and your job is to read the token (or whatever your "authentication" information is) from the request and return it. diff --git a/serializer/encoders.rst b/serializer/encoders.rst index f205efec5c0..0675378aecc 100644 --- a/serializer/encoders.rst +++ b/serializer/encoders.rst @@ -30,11 +30,6 @@ The Serializer component provides built-in encoders: * :class:`Symfony\\Component\\Serializer\\Encoder\\XmlEncoder` to encode/decode XML * :class:`Symfony\\Component\\Serializer\\Encoder\\YamlEncoder` to encode/decode Yaml -.. versionadded:: 3.2 - The :class:`Symfony\\Component\\Serializer\\Encoder\\CsvEncoder` and the - :class:`Symfony\\Component\\Serializer\\Encoder\\YamlEncoder` were introduced in - Symfony 3.2. - The ``JsonEncoder`` ~~~~~~~~~~~~~~~~~~~ diff --git a/service_container.rst b/service_container.rst index cb203e6068c..95812ec3930 100644 --- a/service_container.rst +++ b/service_container.rst @@ -43,11 +43,6 @@ service's class or interface name. Want to :doc:`log ` something? No p // ... } -.. versionadded:: 3.3 - The ability to type-hint a service in order to receive it was added in Symfony 3.3. - See the :ref:`controller chapter ` for more - details. - .. _container-debug-container: What other services are available? Find out by running: @@ -242,10 +237,6 @@ each time you ask for it. If you'd prefer to manually wire your service, that's totally possible: see :ref:`services-explicitly-configure-wire-services`. - .. versionadded:: 3.3 - The ``_defaults`` key *and* ability to load services from a directory were added - in Symfony 3.3. - You can also fetch a service directly from the container via its "id", which will be its class name in this case:: @@ -267,12 +258,6 @@ be its class name in this case:: However, this only works if you make your service :ref:`public `. -.. caution:: - - Service ids are case-insensitive (e.g. ``App\Service\MessageGenerator`` - and ``App\service\messagegenerator`` refer to the same service). But this - was deprecated in Symfony 3.3. Starting in 4.0, service ids will be case sensitive. - .. _services-constructor-injection: Injecting Services/Config into a Service @@ -504,11 +489,6 @@ pass here. No problem! In your configuration, you can explicitly set this argume $container->getDefinition(SiteUpdateManager::class) ->setArgument('$adminEmail', 'manager@example.com'); -.. versionadded:: 3.3 - The ability to configure an argument by its name (``$adminEmail``) was added - in Symfony 3.3. Previously, you could configure it only by its index (``2`` in - this case) or by using empty quotes for the other arguments. - Thanks to this, the container will pass ``manager@example.com`` as the third argument to ``__construct`` when creating the ``SiteUpdateManager`` service. The other arguments will still be autowired. @@ -715,9 +695,6 @@ For more details about autowiring, check out :doc:`/service_container/autowiring The autoconfigure Option ------------------------ -.. versionadded:: 3.3 - The ``autoconfigure`` option was added in Symfony 3.3. - Above, the ``services.yaml`` file has ``autoconfigure: true`` in the ``_defaults`` section so that it applies to all services defined in that file. With this setting, the container will automatically apply certain configuration to your services, based diff --git a/service_container/3.3-di-changes.rst b/service_container/3.3-di-changes.rst index 1b6b2335ff5..b5ba004db6c 100644 --- a/service_container/3.3-di-changes.rst +++ b/service_container/3.3-di-changes.rst @@ -325,9 +325,7 @@ was designed with that in mind. Specifically: * The container determines *which* service to pass in an explicit way: it looks for a service whose id matches the type-hint exactly. It does *not* scan all services - looking for objects that have that class/interface (actually, it *does* do this - in Symfony 3.3, but has been deprecated. If you rely on this, you will see a clear - deprecation warning). + looking for objects that have that class/interface. Autowiring aims to *automate* configuration without magic. diff --git a/service_container/autowiring.rst b/service_container/autowiring.rst index a96cabb2f4d..eafb2682898 100644 --- a/service_container/autowiring.rst +++ b/service_container/autowiring.rst @@ -180,9 +180,8 @@ If there are **0** services in the container that have the type, then: .. _autowiring-single-matching-service: If there is exactly **1** service in the container that has the type, then: - (deprecated) This service is used for the argument. In Symfony 4.0, this - will be removed. The proper solution is to create an :ref:`alias ` - from the type to the service id so that normal autowiring works. + Create an :ref:`alias ` from the type to the + service id so that normal autowiring works. If there are **2 or more** services in the container that have the type, then: A clear exception is thrown. You need to *choose* which service should @@ -435,10 +434,6 @@ with this interface will be passed the ``App\Util\Rot13Transformer`` service. But, you can also manually wire the *other* service by specifying the argument under the arguments key. -.. versionadded:: 3.3 - Using FQCN aliases to fix autowiring ambiguities was introduced in Symfony - 3.3. Prior to version 3.3, you needed to use the ``autowiring_types`` key. - Fixing Non-Autowireable Arguments --------------------------------- diff --git a/service_container/configurators.rst b/service_container/configurators.rst index 637fc0633d3..20ceaeed18c 100644 --- a/service_container/configurators.rst +++ b/service_container/configurators.rst @@ -184,11 +184,6 @@ all the classes are already loaded as services. All you need to do is specify th $container->getDefinition(GreetingCardManager::class) ->setConfigurator(array(new Reference(EmailConfigurator::class), 'configure')); - -.. versionadded:: 3.2 - The ``service_id:method_name`` syntax for the YAML configuration format - was introduced in Symfony 3.2. - The traditional configurator syntax in YAML files used an array to define the service id and the method name: diff --git a/service_container/debug.rst b/service_container/debug.rst index 0838cb5ed7f..9e00b322981 100644 --- a/service_container/debug.rst +++ b/service_container/debug.rst @@ -24,9 +24,6 @@ To see a list of all of the available types that can be used for autowiring, run $ php bin/console debug:autowiring -.. versionadded:: 3.4 - The ``debug:autowiring`` command was introduced in Symfony 3.3. - Detailed Info about a Single Service ------------------------------------ @@ -39,6 +36,3 @@ its id: # to show the service arguments: $ php bin/console debug:container 'App\Service\Mailer' --show-arguments - -.. versionadded:: 3.3 - The ``--show-arguments`` option was introduced in Symfony 3.3. diff --git a/service_container/parameters.rst b/service_container/parameters.rst index 27dda5e6519..224684e84b9 100644 --- a/service_container/parameters.rst +++ b/service_container/parameters.rst @@ -148,7 +148,7 @@ Getting and Setting Container Parameters in PHP Working with container parameters is straightforward using the container's accessor methods for parameters:: - // check if a parameter is defined + // check if a parameter is defined (parameter names are case-sensitive) $container->hasParameter('mailer.transport'); // get value of a parameter @@ -170,11 +170,6 @@ accessor methods for parameters:: To learn more about compiling the container see :doc:`/components/dependency_injection/compilation`. -.. versionadded:: 3.4 - Container parameters are case sensitive starting from Symfony 3.4. In - previous Symfony versions, parameters were case insensitive, meaning that - ``mailer.transport`` and ``Mailer.Transport`` were considered the same parameter. - .. _component-di-parameters-array: Array Parameters diff --git a/service_container/tags.rst b/service_container/tags.rst index fd0276fc818..34d6c852de9 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -371,10 +371,6 @@ To answer this, change the service declaration: tags: - { name: app.mail_transport } - .. versionadded:: 3.3 - Support for the compact tag notation in the YAML format was introduced - in Symfony 3.3. - Notice that you've added a generic ``alias`` key to the tag. To actually use this, update the compiler:: @@ -409,10 +405,6 @@ tags set for the current service and gives you the attributes. Reference Tagged Services ~~~~~~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 3.4 - Support for the tagged service notation in YAML, XML and PHP was introduced - in Symfony 3.4. - Symfony provides a shortcut to inject all services tagged with a specific tag, which is a common need in some applications, so you don't have to write a compiler pass just for that. diff --git a/session/avoid_session_start.rst b/session/avoid_session_start.rst index 57cc3226ff4..e19498184cf 100644 --- a/session/avoid_session_start.rst +++ b/session/avoid_session_start.rst @@ -36,7 +36,3 @@ access the flash messages: {% endfor %} {% endif %} - -.. versionadded:: 3.3 - The ``app.flashes()`` Twig function was introduced in Symfony 3.3. Prior, - you had to use ``app.session.flashBag()``. diff --git a/setup/built_in_web_server.rst b/setup/built_in_web_server.rst index 220d25c6d40..3f22bdbc3d7 100644 --- a/setup/built_in_web_server.rst +++ b/setup/built_in_web_server.rst @@ -75,9 +75,6 @@ can change the socket passing an IP address and a port as a command-line argumen # passing '*' as the IP means to use 0.0.0.0 (i.e. any local IP address) $ php bin/console server:start *:8080 -.. versionadded:: 3.4 - The support of ``*`` as a valid IP address was introduced in Symfony 3.4. - .. note:: You can use the ``server:status`` command to check if a web server is diff --git a/testing.rst b/testing.rst index 3aab9e737bc..96bc16cdc1b 100644 --- a/testing.rst +++ b/testing.rst @@ -421,10 +421,10 @@ The Client supports many operations that can be done in a real browser:: // Clears all cookies and the history $client->restart(); -.. versionadded:: 3.4 - Starting from Symfony 3.4, the ``back()`` and ``forward()`` methods skip the - redirects that may have occurred when requesting a URL, as normal browsers - do. In previous Symfony versions they weren't skipped. +.. note:: + + The ``back()`` and ``forward()`` methods skip the redirects that may have + occurred when requesting a URL, as normal browsers do. Accessing Internal Objects ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/translation/lint.rst b/translation/lint.rst index dd2bc1c7228..0c64e4a427e 100644 --- a/translation/lint.rst +++ b/translation/lint.rst @@ -26,9 +26,6 @@ translation file using the ``lint:yaml`` and ``lint:xliff`` commands: $ ./bin/console lint:yaml @AppBundle $ ./bin/console lint:xliff @AppBundle -.. versionadded:: 3.3 - The ``lint:xliff`` command was introduced in Symfony 3.3. - The linter results can be exported to JSON using the ``--format`` option: .. code-block:: terminal diff --git a/workflow/usage.rst b/workflow/usage.rst index e949d279cff..9e0124d904a 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -233,7 +233,7 @@ order: ``workflow.entered`` Similar to ``workflow.enter``, except the marking store is updated before this - event (making it a good place to flush data in Doctrine). + event (making it a good place to flush data in Doctrine). The three events being dispatched are: @@ -343,9 +343,6 @@ This means that each event has access to the following information: :method:`Symfony\\Component\\Workflow\\Event\\Event::getWorkflowName` Returns a string with the name of the workflow that triggered the event. - .. versionadded:: 3.3 - The ``getWorkflowName()`` method was introduced in Symfony 3.3. - For Guard Events, there is an extended class :class:`Symfony\\Component\\Workflow\\Event\\GuardEvent`. This class has two more methods: @@ -373,10 +370,6 @@ of domain logic in your templates: ``workflow_has_marked_place()`` Returns ``true`` if the marking of the given object has the given state. -.. versionadded:: 3.3 - The ``workflow_marked_places()`` and ``workflow_has_marked_place()`` - functions were introduced in Symfony 3.3. - The following example shows these functions in action: .. code-block:: twig From 597b75bb9dc042d10f84b957f919f1033e0093ca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sun, 12 Nov 2017 11:57:50 +0100 Subject: [PATCH 0036/2437] Removed more references about profiler.matcher option --- reference/configuration/framework.rst | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index ed31f8f4dce..374edd23263 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -533,11 +533,10 @@ collect **type**: ``boolean`` **default**: ``true`` -This option configures the way the profiler behaves when it is enabled. -If set to ``true``, the profiler collects data for all requests (unless -you configure otherwise, like a custom `matcher`_). If you want to only -collect information on-demand, you can set the ``collect`` flag to ``false`` -and activate the data collectors manually:: +This option configures the way the profiler behaves when it is enabled. If set +to ``true``, the profiler collects data for all requests. If you want to only +collect information on-demand, you can set the ``collect`` flag to ``false`` and +activate the data collectors manually:: $profiler->enable(); @@ -1930,12 +1929,6 @@ Full Default Configuration only_exceptions: false only_master_requests: false dsn: file:%kernel.cache_dir%/profiler - matcher: - ip: ~ - - # use the urldecoded format - path: ~ # Example: ^/path to resource/ - service: ~ # router configuration router: From ec2d05a2a05f9e63d887241427025b1051a9e575 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Sun, 12 Nov 2017 13:06:46 +0100 Subject: [PATCH 0037/2437] [#8618] Fixed path in text as well --- setup.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.rst b/setup.rst index 981b4371dcb..7f7447c2a73 100644 --- a/setup.rst +++ b/setup.rst @@ -86,7 +86,8 @@ directory and install it: $ composer require req-checker The ``req-checker`` utility adds two PHP scripts to your application: -``bin/check.php`` and ``public/check.php``. Run the first one from your terminal: +``vendor/bin/requirements-checker`` and ``public/check.php``. Run the first one +from your terminal: .. code-block:: terminal From 47a224a9e5d6e38ac4976c2fcfc19cddb3211ce4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sun, 12 Nov 2017 17:54:36 +0100 Subject: [PATCH 0038/2437] Fixed ater Wouter's review --- bundles/override.rst | 6 +++--- components/console/events.rst | 6 +++--- profiler/matchers.rst | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/bundles/override.rst b/bundles/override.rst index bd90df508e8..a4f6aea787e 100644 --- a/bundles/override.rst +++ b/bundles/override.rst @@ -4,9 +4,9 @@ How to Override any Part of a Bundle ==================================== -This document is a quick reference for how to override different parts of -third-party bundles without using :doc:`/bundles/inheritance`, which was -removed in Symfony 4.0. +When using a third-party bundle, you might want to customize or override some of +its features. This document describes ways of overriding the most common +features of a bundle. .. tip:: diff --git a/components/console/events.rst b/components/console/events.rst index c8dd7079d65..cc358aca2eb 100644 --- a/components/console/events.rst +++ b/components/console/events.rst @@ -97,10 +97,10 @@ thrown by the application. Listeners receive a :class:`Symfony\\Component\\Console\\Event\\ConsoleExceptionEvent` event:: - use Symfony\Component\Console\Event\ConsoleExceptionEvent; + use Symfony\Component\Console\Event\ConsoleErrorEvent; use Symfony\Component\Console\ConsoleEvents; - $dispatcher->addListener(ConsoleEvents::ERROR, function (ConsoleExceptionEvent $event) { + $dispatcher->addListener(ConsoleEvents::ERROR, function (ConsoleErrorEvent $event) { $output = $event->getOutput(); $command = $event->getCommand(); @@ -111,7 +111,7 @@ Listeners receive a $exitCode = $event->getExitCode(); // change the exception to another one - $event->setException(new \LogicException('Caught exception', $exitCode, $event->getException())); + $event->setException(new \LogicException('Caught exception', $exitCode, $event->getError())); }); The ``ConsoleEvents::TERMINATE`` Event diff --git a/profiler/matchers.rst b/profiler/matchers.rst index cb88c6021bd..6c4a2c0974e 100644 --- a/profiler/matchers.rst +++ b/profiler/matchers.rst @@ -8,3 +8,24 @@ How to Use Matchers to Enable the Profiler Conditionally The possibility to use a matcher to enable the profiler conditionally was removed in Symfony 4.0. + +Symfony Profiler cannot be enabled/disabled conditionally using matchers, because +that feature was removed in Symfony 4.0. However, you can use the ``enable()`` +and ``disable()`` methods of the :class:`Symfony\\Component\\HttpKernel\\Profiler\\Profiler` +class in your controllers to manage the profiler programmatically:: + + use Symfony\Component\HttpKernel\Profiler\Profiler; + // ... + + class DefaultController + { + // ... + + public function someMethod(Profiler $profiler) + { + // for this particular controller action, the profiler is disabled + $profiler->disable(); + + // ... + } + } From a37886af64d080d09a4ae1bd2f86a4a706b5343f Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 12 Nov 2017 14:10:26 -0600 Subject: [PATCH 0039/2437] Proposing unstable upgrade changes --- setup/unstable_versions.rst | 46 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/setup/unstable_versions.rst b/setup/unstable_versions.rst index 9616ff7685e..c1a57f4b6b1 100644 --- a/setup/unstable_versions.rst +++ b/setup/unstable_versions.rst @@ -7,54 +7,52 @@ they are released as stable versions. Creating a New Project Based on an Unstable Symfony Version ----------------------------------------------------------- -Suppose that Symfony 2.7 version hasn't been released yet and you want to create +Suppose that the Symfony 4.0 version hasn't been released yet and you want to create a new project to test its features. First, :doc:`install the Composer ` package manager. Then, open a command console, enter your project's directory and execute the following command: .. code-block:: terminal - $ composer create-project symfony/framework-standard-edition my_project "2.7.*" --stability=dev + # Download the latest beta version + $ composer create-project symfony/skeleton my_project "4.0.*" -s=beta + + # Download the absolute latest commit + $ composer create-project symfony/skeleton my_project "4.0.*" -s=dev Once the command finishes its execution, you'll have a new Symfony project created -in the ``my_project/`` directory and based on the most recent code found in the -``2.7`` branch. - -If you want to test a beta version, use ``beta`` as the value of the ``stability`` -option: - -.. code-block:: terminal - - $ composer create-project symfony/framework-standard-edition my_project "2.7.*" --stability=beta +in the ``my_project/`` directory. Upgrading your Project to an Unstable Symfony Version ----------------------------------------------------- -Suppose again that Symfony 2.7 hasn't been released yet and you want to upgrade +Suppose again that Symfony 4.0 hasn't been released yet and you want to upgrade an existing application to test that your project works with it. First, open the ``composer.json`` file located in the root directory of your -project. Then, edit the value of the version defined for the ``symfony/symfony`` -dependency as follows: +project. Then, edit the value of all of the ``symfony/*`` libraries to the +new version and change your `minimum-stability` to `beta`. -.. code-block:: json +.. code-block:: diff { "require": { - "symfony/symfony" : "2.7.*@dev" - } + + "symfony/framework-bundle": "^4.0", + + "symfony/finder": "^4.0", + "...": "..." + }, + + "minimum-stability": "beta" } -Finally, open a command console, enter your project directory and execute the -following command to update your project dependencies: +You can also use set ``minimum-stability`` to ``dev``, or omit this line +entirely, and opt into your stability on each package by using constraints +like ``4.0.*@beta``. -.. code-block:: terminal +Finally, from a terminal, update your project's dependencies: - $ composer update symfony/symfony +.. code-block:: terminal -If you prefer to test a Symfony beta version, replace the ``"2.7.*@dev"`` constraint -by ``"2.7.0-beta1"`` to install a specific beta number or ``2.7.*@beta`` to get -the most recent beta version. + $ composer update After upgrading the Symfony version, read the :ref:`Symfony Upgrading Guide ` to learn how you should proceed to update your application's code in case the new From 357826f53fc8cded89f35391db9a0574f56084a9 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 12 Nov 2017 14:12:23 -0600 Subject: [PATCH 0040/2437] fixing --- setup/unstable_versions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/unstable_versions.rst b/setup/unstable_versions.rst index c1a57f4b6b1..e816627416d 100644 --- a/setup/unstable_versions.rst +++ b/setup/unstable_versions.rst @@ -31,7 +31,7 @@ an existing application to test that your project works with it. First, open the ``composer.json`` file located in the root directory of your project. Then, edit the value of all of the ``symfony/*`` libraries to the -new version and change your `minimum-stability` to `beta`. +new version and change your ``minimum-stability`` to ``beta``: .. code-block:: diff From eb53f14251b96dde8cecfcdc308ed1dbb0d9636b Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 12 Nov 2017 15:29:33 -0500 Subject: [PATCH 0041/2437] Fixing test failure --- reference/configuration/kernel.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 592da9ab03d..63d4ee42af6 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -13,7 +13,7 @@ Configuration * `Charset`_ * `Kernel Name`_ -* `Root Directory`_ +* `Project Directory`_ * `Cache Directory`_ * `Log Directory`_ From 02c676a32550de4617d9b88a7b8bc5c5c65132d0 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 12 Nov 2017 15:35:18 -0500 Subject: [PATCH 0042/2437] fixing old reference --- reference/twig_reference.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 54fd4369cfd..0d802775b01 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -293,11 +293,6 @@ Returns ``true`` if the current user has the required role. Optionally, an object can be pasted to be used by the voter. More information can be found in :ref:`security-template`. -.. note:: - - You can also pass in the field to use ACE for a specific field. Read - more about this in :ref:`security-acl-field_scope`. - logout_path ~~~~~~~~~~~ From 658632df146536ba9faf7fce0692df2e154492d8 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 12 Nov 2017 15:56:01 -0500 Subject: [PATCH 0043/2437] Removing bundle installation page --- _build/redirection_map | 2 +- bundles/installation.rst | 160 --------------------------------------- 2 files changed, 1 insertion(+), 161 deletions(-) delete mode 100644 bundles/installation.rst diff --git a/_build/redirection_map b/_build/redirection_map index 96bc361b032..33f907fb299 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -96,7 +96,7 @@ /cookbook/bundles/extension /bundles/extension /cookbook/bundles/index /bundles /cookbook/bundles/inheritance /bundles/inheritance -/cookbook/bundles/installation /bundles/installation +/cookbook/bundles/installation /bundles /cookbook/bundles/override /bundles/override /cookbook/bundles/prepend_extension /bundles/prepend_extension /cookbook/bundles/remove /bundles/remove diff --git a/bundles/installation.rst b/bundles/installation.rst deleted file mode 100644 index c37752b8388..00000000000 --- a/bundles/installation.rst +++ /dev/null @@ -1,160 +0,0 @@ -.. index:: - single: Bundle; Installation - -How to Install 3rd Party Bundles -================================ - -Most bundles provide their own installation instructions. However, the -basic steps for installing a bundle are the same: - -* `A) Add Composer Dependencies`_ -* `B) Enable the Bundle`_ -* `C) Configure the Bundle`_ - -A) Add Composer Dependencies ----------------------------- - -Dependencies are managed with Composer, so if Composer is new to you, learn -some basics in `their documentation`_. This involves two steps: - -1) Find out the Name of the Bundle on Packagist -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The README for a bundle (e.g. `FOSUserBundle`_) usually tells you its name -(e.g. ``friendsofsymfony/user-bundle``). If it doesn't, you can search for -the bundle on the `Packagist.org`_ site. - -.. tip:: - - Looking for bundles? Try searching for `symfony-bundle topic on GitHub`_. - -2) Install the Bundle via Composer -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now that you know the package name, you can install it via Composer: - -.. code-block:: terminal - - $ composer require friendsofsymfony/user-bundle - -This will choose the best version for your project, add it to ``composer.json`` -and download its code into the ``vendor/`` directory. If you need a specific -version, include it as the second argument of the `composer require`_ command: - -.. code-block:: terminal - - $ composer require friendsofsymfony/user-bundle "~2.0" - -B) Enable the Bundle --------------------- - -At this point, the bundle is installed in your Symfony project (e.g. -``vendor/friendsofsymfony/``) and the autoloader recognizes its classes. -The only thing you need to do now is register the bundle in ``AppKernel``:: - - // app/AppKernel.php - - // ... - class AppKernel extends Kernel - { - // ... - - public function registerBundles() - { - $bundles = array( - // ... - new FOS\UserBundle\FOSUserBundle(), - ); - - // ... - } - } - -In a few rare cases, you may want a bundle to be *only* enabled in the development -:doc:`environment `. For example, -the DoctrineFixturesBundle helps to load dummy data - something you probably -only want to do while developing. To only load this bundle in the ``dev`` -and ``test`` environments, register the bundle in this way:: - - // app/AppKernel.php - - // ... - class AppKernel extends Kernel - { - // ... - - public function registerBundles() - { - $bundles = array( - // ... - ); - - if (in_array($this->getEnvironment(), array('dev', 'test'))) { - $bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(); - } - - // ... - } - } - -C) Configure the Bundle ------------------------ - -It's pretty common for a bundle to need some additional setup or configuration -in ``app/config/config.yml``. The bundle's documentation will tell you about -the configuration, but you can also get a reference of the bundle's configuration -via the ``config:dump-reference`` command: - -.. code-block:: terminal - - $ bin/console config:dump-reference AsseticBundle - -Instead of the full bundle name, you can also pass the short name used as the root -of the bundle's configuration: - -.. code-block:: terminal - - $ bin/console config:dump-reference assetic - -The output will look like this: - -.. code-block:: yaml - - assetic: - debug: '%kernel.debug%' - use_controller: - enabled: '%kernel.debug%' - profiler: false - read_from: '%kernel.project_dir%/web' - write_to: '%assetic.read_from%' - java: /usr/bin/java - node: /usr/local/bin/node - node_paths: [] - # ... - -.. tip:: - - For complex bundles that define lots of configuration options, you can pass - a second optional argument to the ``config:dump-reference`` command to only - display a section of the entire configuration: - - .. code-block:: terminal - - $ bin/console config:dump-reference AsseticBundle use_controller - - # Default configuration for "AsseticBundle" at path "use_controller" - use_controller: - enabled: '%kernel.debug%' - profiler: false - -Other Setup ------------ - -At this point, check the ``README`` file of your brand new bundle to see -what to do next. Have fun! - -.. _their documentation: https://getcomposer.org/doc/00-intro.md -.. _Packagist.org: https://packagist.org -.. _FOSUserBundle: https://github.com/FriendsOfSymfony/FOSUserBundle -.. _`composer require`: https://getcomposer.org/doc/03-cli.md#require -.. _`symfony-bundle topic on GitHub`: https://github.com/search?q=topic%3Asymfony-bundle&type=Repositories From 24b8c598eb3e973998d7ddb1f9d4ad25dd2dde05 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Sun, 12 Nov 2017 23:39:16 -0500 Subject: [PATCH 0044/2437] Remove AppBundle approach --- doctrine/associations.rst | 6 ++--- doctrine/repository.rst | 2 +- http_cache/esi.rst | 2 +- introduction/from_flat_php_to_symfony2.rst | 2 +- security/entity_provider.rst | 28 ++++++++++++---------- security/guard_authentication.rst | 14 ++++++----- service_container.rst | 12 +++++----- 7 files changed, 35 insertions(+), 31 deletions(-) diff --git a/doctrine/associations.rst b/doctrine/associations.rst index 517eacf2735..80f305fffff 100644 --- a/doctrine/associations.rst +++ b/doctrine/associations.rst @@ -15,7 +15,7 @@ the class for you. .. code-block:: terminal $ php bin/console doctrine:generate:entity --no-interaction \ - --entity="AppBundle:Category" \ + --entity="App:Category" \ --fields="name:string(255)" This command generates the ``Category`` entity for you, with an ``id`` field, @@ -332,7 +332,7 @@ to the given ``Category`` object via their ``category_id`` value. $category = $product->getCategory(); - // prints "Proxies\AppBundleEntityCategoryProxy" + // prints "Proxies\AppEntityCategoryProxy" dump(get_class($category)); die(); @@ -370,7 +370,7 @@ following method to the ``ProductRepository`` class:: { $query = $this->getEntityManager() ->createQuery( - 'SELECT p, c FROM AppBundle:Product p + 'SELECT p, c FROM App:Product p JOIN p.category c WHERE p.id = :id' )->setParameter('id', $productId); diff --git a/doctrine/repository.rst b/doctrine/repository.rst index d92d0885c62..49acae61c96 100644 --- a/doctrine/repository.rst +++ b/doctrine/repository.rst @@ -73,7 +73,7 @@ entities, ordered alphabetically by name. { return $this->getEntityManager() ->createQuery( - 'SELECT p FROM AppBundle:Product p ORDER BY p.name ASC' + 'SELECT p FROM App:Product p ORDER BY p.name ASC' ) ->getResult(); } diff --git a/http_cache/esi.rst b/http_cache/esi.rst index 512411ca57b..6276bf5110e 100644 --- a/http_cache/esi.rst +++ b/http_cache/esi.rst @@ -129,7 +129,7 @@ matter), Symfony uses the standard ``render`` helper to configure ESI tags: {# templates/static/about.html.twig #} {# you can use a controller reference #} - {{ render_esi(controller('AppBundle:News:latest', { 'maxPerPage': 5 })) }} + {{ render_esi(controller('App\Controller\NewsController::latest', { 'maxPerPage': 5 })) }} {# ... or a URL #} {{ render_esi(url('latest_news', { 'maxPerPage': 5 })) }} diff --git a/introduction/from_flat_php_to_symfony2.rst b/introduction/from_flat_php_to_symfony2.rst index 23a541ea46e..2fa6fef5c8e 100644 --- a/introduction/from_flat_php_to_symfony2.rst +++ b/introduction/from_flat_php_to_symfony2.rst @@ -553,7 +553,7 @@ them for you. Here's the same sample application, now built in Symfony:: { $posts = $this->getDoctrine() ->getManager() - ->createQuery('SELECT p FROM AppBundle:Post p') + ->createQuery('SELECT p FROM App:Post p') ->execute(); return $this->render('Blog/list.html.php', array('posts' => $posts)); diff --git a/security/entity_provider.rst b/security/entity_provider.rst index 033f8da9ec1..a14c07efcfd 100644 --- a/security/entity_provider.rst +++ b/security/entity_provider.rst @@ -199,7 +199,7 @@ the username and then check the password (more on passwords in a moment): .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: encoders: App\Entity\User: @@ -210,7 +210,7 @@ the username and then check the password (more on passwords in a moment): providers: our_db_provider: entity: - class: AppBundle:User + class: App\Entity\User property: username # if you're using multiple entity managers # manager_name: customer @@ -225,7 +225,7 @@ the username and then check the password (more on passwords in a moment): .. code-block:: xml - + - + @@ -254,7 +254,7 @@ the username and then check the password (more on passwords in a moment): .. code-block:: php - // app/config/security.php + // config/packages/security.php use App\Entity\User; $container->loadFromExtension('security', array( @@ -269,7 +269,7 @@ the username and then check the password (more on passwords in a moment): 'providers' => array( 'our_db_provider' => array( 'entity' => array( - 'class' => 'AppBundle:User', + 'class' => User::class, 'property' => 'username', ), ), @@ -288,7 +288,7 @@ the username and then check the password (more on passwords in a moment): First, the ``encoders`` section tells Symfony to expect that the passwords in the database will be encoded using ``bcrypt``. Second, the ``providers`` section creates a "user provider" called ``our_db_provider`` that knows to -query from your ``AppBundle:User`` entity by the ``username`` property. The +query from your ``App\Entity\User`` entity by the ``username`` property. The name ``our_db_provider`` isn't important: it just needs to match the value of the ``provider`` key under your firewall. Or, if you don't set the ``provider`` key under your firewall, the first "user provider" is automatically used. @@ -458,18 +458,18 @@ To finish this, just remove the ``property`` key from the user provider in .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... providers: our_db_provider: entity: - class: AppBundle:User + class: App\Entity\User .. code-block:: xml - + - + .. code-block:: php - // app/config/security.php + // config/packages/security.php + use App\Entity\User; + $container->loadFromExtension('security', array( // ... 'providers' => array( 'our_db_provider' => array( 'entity' => array( - 'class' => 'AppBundle:User', + 'class' => User::class, ), ), ), diff --git a/security/guard_authentication.rst b/security/guard_authentication.rst index b09dbfbcd46..f197cb7797a 100644 --- a/security/guard_authentication.rst +++ b/security/guard_authentication.rst @@ -83,21 +83,21 @@ Next, make sure you've configured a "user provider" for the user: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... providers: your_db_provider: entity: - class: AppBundle:User + class: App\Entity\User property: apiKey # ... .. code-block:: xml - + - + @@ -118,14 +118,16 @@ Next, make sure you've configured a "user provider" for the user: .. code-block:: php - // app/config/security.php + // config/packages/security.php + use App\Entity\User; + $container->loadFromExtension('security', array( // ... 'providers' => array( 'your_db_provider' => array( 'entity' => array( - 'class' => 'AppBundle:User', + 'class' => User::class, ), ), ), diff --git a/service_container.rst b/service_container.rst index 95812ec3930..12e0705ae32 100644 --- a/service_container.rst +++ b/service_container.rst @@ -183,7 +183,7 @@ each time you ask for it. autoconfigure: true public: false - # makes classes in src/AppBundle available to be used as services + # makes classes in src/ available to be used as services App\: resource: '../../src/*' # you can exclude directories or files @@ -231,7 +231,7 @@ each time you ask for it. `glob pattern`_. Thanks to this configuration, you can automatically use any classes from the - ``src/AppBundle`` directory as a service, without needing to manually configure + ``src/`` directory as a service, without needing to manually configure it. Later, you'll learn more about this in :ref:`service-psr4-loader`. If you'd prefer to manually wire your service, that's totally possible: see @@ -363,7 +363,7 @@ made. To do that, you create a new class:: } This uses the ``MessageGenerator`` *and* the ``Swift_Mailer`` service. As long as -you're :ref:`loading all services from src/AppBundle `, +you're :ref:`loading all services from src/ `, you can use the service immediately:: use App\Updates\SiteUpdateManager; @@ -922,11 +922,11 @@ them will not cause the container to be rebuilt. .. note:: - Wait, does this mean that *every* class in ``src/AppBundle`` is registered as + Wait, does this mean that *every* class in ``src/`` is registered as a service? Even model or entity classes? Actually, no. As long as you have ``public: false`` under your ``_defaults`` key (or you can add it under the specific import), all the imported services are *private*. Thanks to this, all - classes in ``src/AppBundle`` that are *not* explicitly used as services are + classes in ``src/`` that are *not* explicitly used as services are automatically removed from the final container. In reality, the import simply means that all classes are "available to be *used* as services" without needing to be manually configured. @@ -1036,7 +1036,7 @@ If you want to pass the second, you'll need to :ref:`manually wire the service < .. caution:: - If you do *not* create the alias and are :ref:`loading all services from src/AppBundle `, + If you do *not* create the alias and are :ref:`loading all services from src/ `, then *three* services have been created (the automatic service + your two services) and the automatically loaded service will be passed - by default - when you type-hint ``SiteUpdateManager``. That's why creating the alias is a good idea. From 3b27a3dd2ba5a06818edd236fc0db2a518e0098c Mon Sep 17 00:00:00 2001 From: Iltar van der Berg Date: Mon, 13 Nov 2017 09:22:11 +0100 Subject: [PATCH 0045/2437] Removed deprecations for argument/controller resolvers --- components/http_kernel.rst | 19 ++------------- .../http_kernel_controller_resolver.rst | 23 ++++++++++--------- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/components/http_kernel.rst b/components/http_kernel.rst index 945364107d6..b72152ec13c 100644 --- a/components/http_kernel.rst +++ b/components/http_kernel.rst @@ -220,8 +220,8 @@ and is one of the constructor arguments to ``HttpKernel``. :align: center Your job is to create a class that implements the interface and fill in its -two methods: ``getController()`` and ``getArguments()``. In fact, one default -implementation already exists, which you can use directly or learn from: +method: ``getController()``. In fact, one default implementation already +exists, which you can use directly or learn from: :class:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver`. This implementation is explained more in the sidebar below:: @@ -232,20 +232,8 @@ This implementation is explained more in the sidebar below:: interface ControllerResolverInterface { public function getController(Request $request); - - public function getArguments(Request $request, $controller); } -.. caution:: - - The ``getArguments()`` method in the - :class:`Symfony\\Component\\Httpkernel\\Controller\\ControllerResolver` and - respective interface - :class:`Symfony\\Component\\Httpkernel\\Controller\\ControllerResolverInterface` - are deprecated as of 3.1 and will be removed in 4.0. You can use the - :class:`Symfony\\Component\\Httpkernel\\Controller\\ArgumentResolver` which - uses the :class:`Symfony\\Component\\Httpkernel\\Controller\\ArgumentResolverInterface` - instead. Internally, the ``HttpKernel::handle()`` method first calls :method:`Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface::getController` @@ -253,9 +241,6 @@ on the controller resolver. This method is passed the ``Request`` and is respons for somehow determining and returning a PHP callable (the controller) based on the request's information. -The second method, :method:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface::getArguments`, -will be called after another event - ``kernel.controller`` - is dispatched. - .. sidebar:: Resolving the Controller in the Symfony Framework The Symfony Framework uses the built-in diff --git a/create_framework/http_kernel_controller_resolver.rst b/create_framework/http_kernel_controller_resolver.rst index b89e981142f..65748c05212 100644 --- a/create_framework/http_kernel_controller_resolver.rst +++ b/create_framework/http_kernel_controller_resolver.rst @@ -53,18 +53,9 @@ based on a Request object. All controller resolvers implement the following inte // ... interface ControllerResolverInterface { - function getController(Request $request); - - function getArguments(Request $request, $controller); + public function getController(Request $request); } -.. caution:: - - The ``getArguments()`` method is deprecated as of Symfony 3.1. and will be - removed in 4.0. You can use the - :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolver` which - uses the :class:`Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface` - instead. The ``getController()`` method relies on the same convention as the one we have defined earlier: the ``_controller`` request attribute must contain the @@ -98,7 +89,17 @@ resolver from HttpKernel:: Now, let's see how the controller arguments are guessed. ``getArguments()`` introspects the controller signature to determine which arguments to pass to -it by using the native PHP `reflection`_. +it by using the native PHP `reflection`_. This method is defined in the +following interface:: + + namespace Symfony\Component\HttpKernel\Controller; + + // ... + interface ArgumentResolverInterface + { + public function getArguments(Request $request, $controller); + } + The ``indexAction()`` method needs the Request object as an argument. ``getArguments()`` knows when to inject it properly if it is type-hinted From 37acb46f3e74f735b711cc53c2b87774a08138fd Mon Sep 17 00:00:00 2001 From: Olivier Dolbeau Date: Mon, 13 Nov 2017 11:40:42 +0100 Subject: [PATCH 0046/2437] Correct composer option syntax --- setup/unstable_versions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup/unstable_versions.rst b/setup/unstable_versions.rst index e816627416d..702a4246f5e 100644 --- a/setup/unstable_versions.rst +++ b/setup/unstable_versions.rst @@ -15,10 +15,10 @@ execute the following command: .. code-block:: terminal # Download the latest beta version - $ composer create-project symfony/skeleton my_project "4.0.*" -s=beta + $ composer create-project symfony/skeleton my_project "4.0.*" -s beta # Download the absolute latest commit - $ composer create-project symfony/skeleton my_project "4.0.*" -s=dev + $ composer create-project symfony/skeleton my_project "4.0.*" -s dev Once the command finishes its execution, you'll have a new Symfony project created in the ``my_project/`` directory. From 04fde8ca4ed44f52250a384ebaa92feb8f67dff6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 10 Nov 2017 10:58:57 +0100 Subject: [PATCH 0047/2437] Updated the main bundles article for Symfony 4 --- bundles.rst | 204 +++++++++------------------------------------- bundles/index.rst | 10 ++- 2 files changed, 43 insertions(+), 171 deletions(-) diff --git a/bundles.rst b/bundles.rst index 7391ffe9d25..30bacddd925 100644 --- a/bundles.rst +++ b/bundles.rst @@ -6,179 +6,49 @@ The Bundle System ================= -A bundle is similar to a plugin in other software, but even better. The key -difference is that *everything* is a bundle in Symfony, including both the -core framework functionality and the code written for your application. -Bundles are first-class citizens in Symfony. This gives you the flexibility -to use pre-built features packaged in `third-party bundles`_ or to distribute -your own bundles. It makes it easy to pick and choose which features to enable -in your application and to optimize them the way you want. - -.. note:: - - While you'll learn the basics here, an entire article is devoted to the - organization and best practices of :doc:`bundles `. - -A bundle is simply a structured set of files within a directory that implement -a single feature. You might create a BlogBundle, a ForumBundle or -a bundle for user management (many of these exist already as open source -bundles). Each directory contains everything related to that feature, including -PHP files, templates, stylesheets, JavaScript files, tests and anything else. -Every aspect of a feature exists in a bundle and every feature lives in a -bundle. - -Bundles used in your applications must be enabled by registering them in -the ``registerBundles()`` method of the ``AppKernel`` class:: - - // app/AppKernel.php - public function registerBundles() - { - $bundles = array( - new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), - new Symfony\Bundle\SecurityBundle\SecurityBundle(), - new Symfony\Bundle\TwigBundle\TwigBundle(), - new Symfony\Bundle\MonologBundle\MonologBundle(), - new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), - new Symfony\Bundle\DoctrineBundle\DoctrineBundle(), - new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), - new AppBundle\AppBundle(), - ); - - if (in_array($this->getEnvironment(), array('dev', 'test'))) { - $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); - $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); - $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); - } - - return $bundles; - } - -With the ``registerBundles()`` method, you have total control over which bundles -are used by your application (including the core Symfony bundles). +.. caution:: + + In Symfony versions prior to 4.0, it was recommended to organize your own + application code using bundles. This is no longer recommended and bundles + should only be used to share code and features between multiple applications. + +A bundle is similar to a plugin in other software, but even better. The core +features of Symfony framework are implemented with bundles (FrameworkBundle, +SecurityBundle, DebugBundle, etc.) They are also used to add new features in +your application via `third-party bundles`_. + +Bundles used in your applications must be enabled per +:doc:`environment ` in the ``config/bundles.php`` +file:: + + // config/bundles.php + return [ + // 'all' means that the bundle is enabled for any Symfony environment + Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], + Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], + Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], + Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], + Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true], + Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], + Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], + // this bundle is enabled only in 'dev' and 'test', so you can't use it in 'prod' + Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], + ]; .. tip:: - A bundle can live *anywhere* as long as it can be autoloaded (via the - autoloader configured at ``app/autoload.php``). - -Creating a Bundle ------------------ - -The Symfony Standard Edition comes with a handy task that creates a fully-functional -bundle for you. Of course, creating a bundle by hand is pretty easy as well. - -To show you how simple the bundle system is, create a new bundle called -AcmeTestBundle and enable it. - -.. tip:: - - The ``Acme`` portion is just a dummy name that should be replaced by - some "vendor" name that represents you or your organization (e.g. - ABCTestBundle for some company named ``ABC``). - -Start by creating a ``src/Acme/TestBundle/`` directory and adding a new file -called ``AcmeTestBundle.php``:: - - // src/Acme/TestBundle/AcmeTestBundle.php - namespace Acme\TestBundle; - - use Symfony\Component\HttpKernel\Bundle\Bundle; - - class AcmeTestBundle extends Bundle - { - } - -.. tip:: - - The name AcmeTestBundle follows the standard - :ref:`Bundle naming conventions `. You could - also choose to shorten the name of the bundle to simply TestBundle by naming - this class TestBundle (and naming the file ``TestBundle.php``). - -This empty class is the only piece you need to create the new bundle. Though -commonly empty, this class is powerful and can be used to customize the behavior -of the bundle. - -Now that you've created the bundle, enable it via the ``AppKernel`` class:: - - // app/AppKernel.php - public function registerBundles() - { - $bundles = array( - // ... - - // register your bundle - new Acme\TestBundle\AcmeTestBundle(), - ); - // ... - - return $bundles; - } - -And while it doesn't do anything yet, AcmeTestBundle is now ready to be used. - -And as easy as this is, Symfony also provides a command-line interface for -generating a basic bundle skeleton: - -.. code-block:: terminal - - $ php bin/console generate:bundle --namespace=Acme/TestBundle - -The bundle skeleton generates a basic controller, template and routing -resource that can be customized. You'll learn more about Symfony's command-line -tools later. - -.. tip:: - - Whenever creating a new bundle or using a third-party bundle, always make - sure the bundle has been enabled in ``registerBundles()``. When using - the ``generate:bundle`` command, this is done for you. - -Bundle Directory Structure --------------------------- - -The directory structure of a bundle is simple and flexible. By default, the -bundle system follows a set of conventions that help to keep code consistent -between all Symfony bundles. Take a look at AcmeDemoBundle, as it contains some -of the most common elements of a bundle: - -``Controller/`` - Contains the controllers of the bundle (e.g. ``RandomController.php``). - -``DependencyInjection/`` - Holds certain Dependency Injection Extension classes, which may import service - configuration, register compiler passes or more (this directory is not - necessary). - -``Resources/config/`` - Houses configuration, including routing configuration (e.g. ``routes.yaml``). - -``Resources/views/`` - Holds templates organized by controller name (e.g. ``Random/index.html.twig``). - -``Resources/public/`` - Contains web assets (images, stylesheets, etc) and is copied or symbolically - linked into the project ``public/`` directory via the ``assets:install`` console - command. - -``Tests/`` - Holds all tests for the bundle. - -A bundle can be as small or large as the feature it implements. It contains -only the files you need and nothing else. - -As you move through the guides, you'll learn how to persist objects to a -database, create and validate forms, create translations for your application, -write tests and much more. Each of these has their own place and role within -the bundle. + In a default Symfony application that uses :doc:`Symfony Flex `, + bundles are enabled/disabled automatically for you when installing/removing + them, so you don't need to look at or edit this ``bundles.php`` file. Learn more ---------- -.. toctree:: - :maxdepth: 1 - :glob: - - bundles/* +* :doc:`/bundles/remove` +* :doc:`/bundles/override` +* :doc:`/bundles/best_practices` +* :doc:`/bundles/configuration` +* :doc:`/bundles/extension` +* :doc:`/bundles/prepend_extension` _`third-party bundles`: https://github.com/search?q=topic%3Asymfony-bundle&type=Repositories diff --git a/bundles/index.rst b/bundles/index.rst index 87641de5e23..d5349f6353c 100644 --- a/bundles/index.rst +++ b/bundles/index.rst @@ -1,3 +1,5 @@ +:orphan: + Bundles ======= @@ -5,10 +7,10 @@ Bundles :maxdepth: 2 installation - best_practices - inheritance - override remove - extension + override + inheritance + best_practices configuration + extension prepend_extension From a953fc0bcd872a92e622efd2d92b837c7ae95516 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Mon, 13 Nov 2017 01:00:49 -0500 Subject: [PATCH 0048/2437] Add new validator config & translations path --- validation.rst | 32 ++++++++++++++++---------------- validation/translations.rst | 12 ++++++------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/validation.rst b/validation.rst index 30de658c959..ebb13a90868 100644 --- a/validation.rst +++ b/validation.rst @@ -59,7 +59,7 @@ following: .. code-block:: yaml - # src/Resources/config/validation.yml + # config/validator/validation.yaml App\Entity\Author: properties: name: @@ -67,7 +67,7 @@ following: .. code-block:: xml - + + loadFromExtension('framework', array( 'validation' => array( 'enabled' => true, @@ -250,13 +250,13 @@ previous configuration by the following: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yml framework: validation: { enable_annotations: true } .. code-block:: xml - + loadFromExtension('framework', array( 'validation' => array( 'enable_annotations' => true, @@ -346,7 +346,7 @@ literature genre mostly associated with the author, which can be set to either .. code-block:: yaml - # src/Resources/config/validation.yml + # config/validator/validation.yaml App\Entity\Author: properties: genre: @@ -355,7 +355,7 @@ literature genre mostly associated with the author, which can be set to either .. code-block:: xml - + + + + + + @@ -105,12 +105,12 @@ Now, create a ``validators`` catalog file in the ``app/Resources/translations`` .. code-block:: yaml - # app/Resources/translations/validators.en.yml + # config/translations/validators.en.yaml author.name.not_blank: Please enter an author name. .. code-block:: php - // app/Resources/translations/validators.en.php + // config/translations/validators.en.php return array( 'author.name.not_blank' => 'Please enter an author name.', ); From 2a3660eb904b717dfcb304cd931a647dbd8e2798 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Thu, 22 Jun 2017 14:30:54 -0500 Subject: [PATCH 0049/2437] Add new symfony4 site type to homestead documentation --- setup/homestead.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/setup/homestead.rst b/setup/homestead.rst index d56ddab31ce..fd07201de49 100644 --- a/setup/homestead.rst +++ b/setup/homestead.rst @@ -50,9 +50,11 @@ configuration: sites: - map: symfony-demo.test to: /home/vagrant/projects/symfony_demo/web - type: symfony + type: symfony4 -The ``type`` option tells Homestead to use the Symfony nginx configuration. +The ``type`` option tells Homestead to use the Symfony nginx configuration. +Homestead now supports a Symfony2 web layout with app.php and app_dev.php when +using type: symfony2 and an index.php layout when using type: symfony4. At last, edit the hosts file on your local machine to map ``symfony-demo.test`` to ``192.168.10.10`` (which is the IP used by Homestead):: From 70291d73ab16f7717547433140ac48d8b87c67d7 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Mon, 13 Nov 2017 14:19:42 +0100 Subject: [PATCH 0050/2437] [#8078] Added some inline code blocks --- setup/homestead.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/setup/homestead.rst b/setup/homestead.rst index fd07201de49..664f0bc613b 100644 --- a/setup/homestead.rst +++ b/setup/homestead.rst @@ -49,12 +49,13 @@ configuration: # ... sites: - map: symfony-demo.test - to: /home/vagrant/projects/symfony_demo/web + to: /home/vagrant/projects/symfony_demo/public type: symfony4 -The ``type`` option tells Homestead to use the Symfony nginx configuration. -Homestead now supports a Symfony2 web layout with app.php and app_dev.php when -using type: symfony2 and an index.php layout when using type: symfony4. +The ``type`` option tells Homestead to use the Symfony nginx configuration. +Homestead now supports a Symfony 2 and 3 web layout with ``app.php`` and +``app_dev.php`` when using type ``symfony2`` and an ``index.php`` layout when +using type ``symfony4``. At last, edit the hosts file on your local machine to map ``symfony-demo.test`` to ``192.168.10.10`` (which is the IP used by Homestead):: From 7d33abbd08338f72f0bea5c0d8e6d09d97456035 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 13 Nov 2017 08:19:13 +0100 Subject: [PATCH 0051/2437] clarify allowed property path value types --- reference/forms/types/options/property_path.rst.inc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/reference/forms/types/options/property_path.rst.inc b/reference/forms/types/options/property_path.rst.inc index 49fa503bef1..54505dc0a3a 100644 --- a/reference/forms/types/options/property_path.rst.inc +++ b/reference/forms/types/options/property_path.rst.inc @@ -1,17 +1,12 @@ property_path ~~~~~~~~~~~~~ -**type**: ``any`` **default**: ``the field's name`` +**type**: ``PropertyPathInterface|string|null`` **default**: ``null`` Fields display a property value of the form's domain object by default. When the form is submitted, the submitted value is written back into the object. If you want to override the property that a field reads from and writes -to, you can set the ``property_path`` option. Its default value is the field's -name. - -If you wish the field to be ignored when reading or writing to the object -you can set the ``property_path`` option to ``false``, but using -``property_path`` for this purpose is deprecated, you should use the -``mapped`` option. +to, you can set the ``property_path`` option. Its default value (``null``) +will use the field's name as the property. From da6710574bc893502d573960f55e5ec53d985878 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 13 Nov 2017 20:36:27 +0100 Subject: [PATCH 0052/2437] Updated reference articles to Symfony 4 --- reference/configuration/assetic.rst | 119 +----------- reference/configuration/debug.rst | 6 +- reference/configuration/doctrine.rst | 52 +++--- reference/configuration/framework.rst | 80 ++++---- reference/configuration/kernel.rst | 31 ++-- reference/configuration/monolog.rst | 4 +- reference/configuration/security.rst | 28 +-- reference/configuration/swiftmailer.rst | 9 +- reference/configuration/twig.rst | 18 +- reference/configuration/web_profiler.rst | 4 +- reference/constraints/All.rst | 2 +- reference/constraints/Bic.rst | 2 +- reference/constraints/Blank.rst | 2 +- reference/constraints/Callback.rst | 4 +- reference/constraints/CardScheme.rst | 2 +- reference/constraints/Choice.rst | 6 +- reference/constraints/Collection.rst | 4 +- reference/constraints/Count.rst | 2 +- reference/constraints/Country.rst | 2 +- reference/constraints/Currency.rst | 2 +- reference/constraints/Date.rst | 2 +- reference/constraints/DateTime.rst | 2 +- reference/constraints/Email.rst | 2 +- reference/constraints/EqualTo.rst | 2 +- reference/constraints/Expression.rst | 4 +- reference/constraints/File.rst | 2 +- reference/constraints/GreaterThan.rst | 8 +- reference/constraints/GreaterThanOrEqual.rst | 8 +- reference/constraints/Iban.rst | 2 +- reference/constraints/IdenticalTo.rst | 2 +- reference/constraints/Image.rst | 4 +- reference/constraints/Ip.rst | 2 +- reference/constraints/IsFalse.rst | 2 +- reference/constraints/IsNull.rst | 2 +- reference/constraints/IsTrue.rst | 2 +- reference/constraints/Isbn.rst | 2 +- reference/constraints/Issn.rst | 2 +- reference/constraints/Language.rst | 2 +- reference/constraints/Length.rst | 2 +- reference/constraints/LessThan.rst | 8 +- reference/constraints/LessThanOrEqual.rst | 8 +- reference/constraints/Locale.rst | 2 +- reference/constraints/Luhn.rst | 2 +- reference/constraints/NotBlank.rst | 2 +- reference/constraints/NotEqualTo.rst | 2 +- reference/constraints/NotIdenticalTo.rst | 2 +- reference/constraints/NotNull.rst | 2 +- reference/constraints/Range.rst | 8 +- reference/constraints/Regex.rst | 6 +- reference/constraints/Time.rst | 2 +- reference/constraints/Type.rst | 2 +- reference/constraints/UniqueEntity.rst | 11 +- reference/constraints/Url.rst | 10 +- reference/constraints/UserPassword.rst | 2 +- reference/constraints/Uuid.rst | 2 +- reference/constraints/Valid.rst | 4 +- reference/dic_tags.rst | 185 +------------------ reference/forms/types/entity.rst | 2 +- reference/map.rst.inc | 2 +- 59 files changed, 202 insertions(+), 495 deletions(-) diff --git a/reference/configuration/assetic.rst b/reference/configuration/assetic.rst index 4331d8117a7..a30ba7ef450 100644 --- a/reference/configuration/assetic.rst +++ b/reference/configuration/assetic.rst @@ -4,119 +4,8 @@ AsseticBundle Configuration ("assetic") ======================================= -.. include:: /assetic/_standard_edition_warning.rst.inc +.. caution:: -Full Default Configuration --------------------------- - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - assetic: - debug: '%kernel.debug%' - use_controller: - enabled: '%kernel.debug%' - profiler: false - read_from: '%assetic.read_from%' - write_to: '%kernel.project_dir%/web' - java: /usr/bin/java - node: /usr/bin/node - ruby: /usr/bin/ruby - sass: /usr/bin/sass - # An key-value pair of any number of named elements - variables: - some_name: [] - bundles: - - # Defaults (all currently registered bundles): - - FrameworkBundle - - SecurityBundle - - TwigBundle - - MonologBundle - - SwiftmailerBundle - - DoctrineBundle - - AsseticBundle - - ... - assets: - # An array of named assets (e.g. some_asset, some_other_asset) - some_asset: - inputs: [] - filters: [] - options: - # A key-value array of options and values - some_option_name: [] - filters: - - # An array of named filters (e.g. some_filter, some_other_filter) - some_filter: [] - workers: - # see https://github.com/symfony/AsseticBundle/pull/119 - # Cache can also be busted via the framework.assets.version - # setting - see the "framework" configuration section - cache_busting: - enabled: false - twig: - functions: - # An array of named functions (e.g. some_function, some_other_function) - some_function: [] - - .. code-block:: xml - - - - - - - - - FrameworkBundle - SecurityBundle - TwigBundle - MonologBundle - SwiftmailerBundle - DoctrineBundle - AsseticBundle - ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Assetic is no longer recommended to manage web assets in Symfony + applications. Instead, use :doc:`Webpack Encore `, which bridges + Symfony applications with modern JavaScript tools used to manage web assets. diff --git a/reference/configuration/debug.rst b/reference/configuration/debug.rst index b9185488a68..3eb822cd62a 100644 --- a/reference/configuration/debug.rst +++ b/reference/configuration/debug.rst @@ -64,13 +64,13 @@ destination for dumps. Typically, you would set this to ``php://stderr``: .. code-block:: yaml - # app/config/config.yml + # config/packages/debug.yaml debug: dump_destination: php://stderr .. code-block:: xml - + loadFromExtension('debug', array( 'dump_destination' => 'php://stderr', )); diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index d7e32a282a4..d5d8efd97e8 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -12,7 +12,7 @@ Full Default Configuration .. code-block:: yaml - # app/config/config.yml + # config/packages/doctrine.yaml doctrine: dbal: default_connection: default @@ -20,9 +20,9 @@ Full Default Configuration # A collection of custom types # Example some_custom_type: - class: Acme\HelloBundle\MyCustomType + class: App\Bridge\Doctrine\DBAL\MyCustomType commented: true - + connections: # A collection of different named connections (e.g. default, conn2, etc) @@ -75,11 +75,11 @@ Full Default Configuration mapping_types: # an array of mapping types name: [] - + # If defined, only the tables whose names match this regular expression are managed # by the schema tool (in this example, any table name not starting with `wp_`) #schema_filter: '/^(?!wp_)/' - + slaves: # a collection of named slave connections (e.g. slave1, slave2) @@ -163,17 +163,17 @@ Full Default Configuration # a collection of string functions string_functions: # example - # test_string: Acme\HelloBundle\DQL\StringFunction + # test_string: App\Bridge\Doctrine\DQL\StringFunction # a collection of numeric functions numeric_functions: # example - # test_numeric: Acme\HelloBundle\DQL\NumericFunction + # test_numeric: App\Bridge\Doctrine\DQL\NumericFunction # a collection of datetime functions datetime_functions: # example - # test_datetime: Acme\HelloBundle\DQL\DatetimeFunction + # test_datetime: App\Bridge\Doctrine\DQL\DatetimeFunction # Register SQL Filters in the entity manager filters: @@ -184,7 +184,7 @@ Full Default Configuration .. code-block:: xml - + @@ -219,7 +219,7 @@ Full Default Configuration string - Acme\HelloBundle\MyCustomType + App\Bridge\Doctrine\DBAL\MyCustomType - Acme\HelloBundle\DQL\StringFunction + App\Bridge\Doctrine\DQL\StringFunction - Acme\HelloBundle\DQL\NumericFunction + App\Bridge\Doctrine\DQL\NumericFunction - Acme\HelloBundle\DQL\DatetimeFunction + App\Bridge\Doctrine\DQL\DatetimeFunction @@ -301,7 +301,7 @@ The following block shows all possible configuration keys: password: secret driver: pdo_mysql # the DBAL driverClass option - driver_class: MyNamespace\MyDriverImpl + driver_class: App\Bridge\Doctrine\DBAL\MyDatabaseDriver # the DBAL driverOptions option options: foo: bar @@ -309,15 +309,15 @@ The following block shows all possible configuration keys: memory: true unix_socket: /tmp/mysql.sock # the DBAL wrapperClass option - wrapper_class: MyDoctrineDbalConnectionWrapper + wrapper_class: App\Bridge\Doctrine\DBAL\MyConnectionWrapper charset: UTF8 logging: '%kernel.debug%' - platform_service: MyOwnDatabasePlatformService + platform_service: App\Bridge\Doctrine\DBAL\MyDatabasePlatformService server_version: 5.6 mapping_types: enum: string types: - custom: Acme\HelloBundle\MyCustomType + custom: App\Bridge\Doctrine\DBAL\MyCustomType .. code-block:: xml @@ -339,19 +339,19 @@ The following block shows all possible configuration keys: user="user" password="secret" driver="pdo_mysql" - driver-class="MyNamespace\MyDriverImpl" + driver-class="App\Bridge\Doctrine\DBAL\MyDatabaseDriver" path="%kernel.project_dir%/var/data/data.sqlite" memory="true" unix-socket="/tmp/mysql.sock" - wrapper-class="MyDoctrineDbalConnectionWrapper" + wrapper-class="App\Bridge\Doctrine\DBAL\MyConnectionWrapper" charset="UTF8" logging="%kernel.debug%" - platform-service="MyOwnDatabasePlatformService" + platform-service="App\Bridge\Doctrine\DBAL\MyDatabasePlatformService" server-version="5.6"> bar string - Acme\HelloBundle\MyCustomType + App\Bridge\Doctrine\DBAL\MyCustomType @@ -480,7 +480,7 @@ The following example shows an overview of the caching configurations: # the 'service' type requires to define the 'id' option too query_cache_driver: type: service - id: my_doctrine_common_cache_service + id: App\Bridge\Doctrine\ORM\MyCacheService Mapping Configuration ~~~~~~~~~~~~~~~~~~~~~ @@ -662,7 +662,7 @@ If the ``type`` on the bundle configuration isn't set, the DoctrineBundle will try to detect the correct mapping configuration format for the bundle. DoctrineBundle will look for files matching ``*.orm.[FORMAT]`` (e.g. -``Post.orm.yml``) in the configured ``dir`` of your mapping (if you're mapping +``Post.orm.yaml``) in the configured ``dir`` of your mapping (if you're mapping a bundle, then ``dir`` is relative to the bundle's directory). The bundle looks for (in this order) XML, YAML and PHP files. diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 374edd23263..af484a46ea1 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -180,7 +180,7 @@ named ``kernel.http_method_override``. To fix this, invoke the ``enableHttpMethodParameterOverride()`` method before creating the ``Request`` object:: - // web/app.php + // public/index.php // ... $kernel = new AppCache($kernel); @@ -220,13 +220,13 @@ doubling them to prevent Symfony from interpreting them as container parameters) .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: ide: 'myide://open?url=file://%%f&line=%%l' .. code-block:: xml - + loadFromExtension('framework', array( 'ide' => 'myide://open?url=file://%%f&line=%%l', )); @@ -283,7 +283,7 @@ test If this configuration setting is present (and not ``false``), then the services related to testing your application (e.g. ``test.client``) are loaded. This setting should be present in your ``test`` environment (usually via -``app/config/config_test.yml``). +``config/packages/test/framework.yaml``). .. seealso:: @@ -334,13 +334,13 @@ respond and the user will receive a 400 response. .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: trusted_hosts: ['example.com', 'example.org'] .. code-block:: xml - + loadFromExtension('framework', array( 'trusted_hosts' => array('example.com', 'example.org'), )); @@ -369,7 +369,7 @@ which make it easier to respond to any subdomain. In addition, you can also set the trusted hosts in the front controller using the ``Request::setTrustedHosts()`` method:: - // web/app.php + // public/index.php Request::setTrustedHosts(array('^(.+\.)?example.com$', '^(.+\.)?example.org$')); The default value for this option is an empty array, meaning that the application @@ -450,13 +450,13 @@ You can also set ``esi`` to ``true`` to enable it: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: esi: true .. code-block:: xml - + loadFromExtension('framework', array( 'esi' => true, )); @@ -592,7 +592,7 @@ To configure a ``jsonp`` format: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: request: formats: @@ -600,7 +600,7 @@ To configure a ``jsonp`` format: .. code-block:: xml - + loadFromExtension('framework', array( 'request' => array( 'formats' => array( @@ -824,14 +824,14 @@ setting the value to ``null``: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: session: save_path: ~ .. code-block:: xml - + loadFromExtension('framework', array( 'session' => array( 'save_path' => null, @@ -883,7 +883,7 @@ This option allows you to define a base path to be used for assets: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... assets: @@ -891,7 +891,7 @@ This option allows you to define a base path to be used for assets: .. code-block:: xml - + loadFromExtension('framework', array( // ... 'assets' => array( @@ -931,7 +931,7 @@ collection each time it generates an asset's path: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... assets: @@ -940,7 +940,7 @@ collection each time it generates an asset's path: .. code-block:: xml - + loadFromExtension('framework', array( // ... 'assets' => array( @@ -975,7 +975,7 @@ You can group assets into packages, to specify different base URLs for them: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... assets: @@ -985,7 +985,7 @@ You can group assets into packages, to specify different base URLs for them: .. code-block:: xml - + loadFromExtension('framework', array( // ... 'assets' => array( @@ -1070,7 +1070,7 @@ Now, activate the ``version`` option: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... assets: @@ -1078,7 +1078,7 @@ Now, activate the ``version`` option: .. code-block:: xml - + loadFromExtension('framework', array( // ... 'assets' => array( @@ -1175,7 +1175,7 @@ individually for each asset package: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: assets: # this strategy is applied to every asset (including packages) @@ -1193,7 +1193,7 @@ individually for each asset package: .. code-block:: xml - + loadFromExtension('framework', array( 'assets' => array( 'version_strategy' => 'app.asset.my_versioning_strategy', @@ -1273,7 +1273,7 @@ package: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: assets: # this manifest is applied to every asset (including packages) @@ -1288,7 +1288,7 @@ package: .. code-block:: xml - + loadFromExtension('framework', array( 'assets' => array( // this manifest is applied to every asset (including packages) @@ -1372,13 +1372,13 @@ if you're using the Twig format for your templates, in that case refer to :ref:`the form article `. Assume you have custom global form themes in -``src/WebsiteBundle/Resources/views/Form``, you can configure this like: +``src/Resources/views/Form``, you can configure this like: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: templating: form: @@ -1387,7 +1387,7 @@ Assume you have custom global form themes in .. code-block:: xml - + loadFromExtension('framework', array( 'templating' => array( 'form' => array( diff --git a/reference/configuration/kernel.rst b/reference/configuration/kernel.rst index 63d4ee42af6..3a1adc0c594 100644 --- a/reference/configuration/kernel.rst +++ b/reference/configuration/kernel.rst @@ -1,11 +1,11 @@ .. index:: single: Configuration reference; Kernel class -Configuring in the Kernel (e.g. AppKernel) -========================================== +Configuring in the Kernel +========================= -Some configuration can be done on the kernel class itself (usually called -``app/AppKernel.php``). You can do this by overriding specific methods in +Some configuration can be done on the kernel class itself (located by default at +``src/Kernel.php``). You can do this by overriding specific methods in the parent :class:`Symfony\\Component\\HttpKernel\\Kernel` class. Configuration @@ -26,10 +26,11 @@ This returns the charset that is used in the application. To change it, override the :method:`Symfony\\Component\\HttpKernel\\Kernel::getCharset` method and return another charset, for instance:: - // app/AppKernel.php - + // src/Kernel.php + use Symfony\Component\HttpKernel\Kernel as BaseKernel; // ... - class AppKernel extends Kernel + + class Kernel extends BaseKernel { public function getCharset() { @@ -40,18 +41,17 @@ method and return another charset, for instance:: Kernel Name ~~~~~~~~~~~ -**type**: ``string`` **default**: ``app`` (i.e. the directory name holding +**type**: ``string`` **default**: ``src`` (i.e. the directory name holding the kernel class) To change this setting, override the :method:`Symfony\\Component\\HttpKernel\\Kernel::getName` method. Alternatively, move your kernel into a different directory. For -example, if you moved the kernel into a ``foo`` directory (instead of ``app``), +example, if you moved the kernel into a ``foo/`` directory (instead of ``src/``), the kernel name will be ``foo``. The name of the kernel isn't usually directly important - it's used in the -generation of cache files. If you have an application with multiple kernels, -the easiest way to make each have a unique name is to duplicate the ``app`` -directory and rename it to something else (e.g. ``foo``). +generation of cache files - and you probably will only change it when +:doc:`using applications with multiple kernels `. Project Directory ~~~~~~~~~~~~~~~~~ @@ -65,10 +65,11 @@ If for some reason the ``composer.json`` file is not stored at the root of your project, you can override the :method:`Symfony\\Component\\HttpKernel\\Kernel::getProjectDir` method to return the right project directory:: - // app/AppKernel.php - + // src/Kernel.php + use Symfony\Component\HttpKernel\Kernel as BaseKernel; // ... - class AppKernel extends Kernel + + class Kernel extends BaseKernel { // ... diff --git a/reference/configuration/monolog.rst b/reference/configuration/monolog.rst index a067d95bc10..c2db56b574d 100644 --- a/reference/configuration/monolog.rst +++ b/reference/configuration/monolog.rst @@ -14,7 +14,7 @@ Full Default Configuration .. code-block:: yaml - # app/config/config.yml + # config/packages/monolog.yaml monolog: handlers: @@ -77,7 +77,7 @@ Full Default Configuration .. code-block:: xml - + + loadFromExtension('security', array( 'firewalls' => array( 'somename' => array( diff --git a/reference/configuration/swiftmailer.rst b/reference/configuration/swiftmailer.rst index 2bf47c40859..a1b06c2af80 100644 --- a/reference/configuration/swiftmailer.rst +++ b/reference/configuration/swiftmailer.rst @@ -193,10 +193,11 @@ delivery_addresses In previous versions, this option was called ``delivery_address``. -If set, all email messages will be sent to these addresses instead of being -sent to their actual recipients. This is often useful when developing. For -example, by setting this in the ``config_dev.yml`` file, you can guarantee -that all emails sent during development go to one or more some specific accounts. +If set, all email messages will be sent to these addresses instead of being sent +to their actual recipients. This is often useful when developing. For example, +by setting this in the ``config/packages/dev/swiftmailer.yaml`` file, you can +guarantee that all emails sent during development go to one or more some +specific accounts. This uses ``Swift_Plugins_RedirectingPlugin``. Original recipients are available on the ``X-Swift-To``, ``X-Swift-Cc`` and ``X-Swift-Bcc`` headers. diff --git a/reference/configuration/twig.rst b/reference/configuration/twig.rst index c5c2a0acf54..5f132fcdbc7 100644 --- a/reference/configuration/twig.rst +++ b/reference/configuration/twig.rst @@ -8,7 +8,7 @@ TwigBundle Configuration ("twig") .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: exception_controller: twig.controller.exception:showAction @@ -70,7 +70,7 @@ TwigBundle Configuration ("twig") .. code-block:: xml - + loadFromExtension('twig', array( 'form_themes' => array( 'form_div_layout.html.twig', // Default @@ -365,7 +365,7 @@ The values of the ``paths`` option are defined as ``key: value`` pairs where the .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: # ... paths: @@ -373,7 +373,7 @@ The values of the ``paths`` option are defined as ``key: value`` pairs where the .. code-block:: xml - + loadFromExtension('twig', array( // ... 'paths' => array( @@ -409,7 +409,7 @@ for that directory: .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: # ... paths: @@ -417,7 +417,7 @@ for that directory: .. code-block:: xml - + loadFromExtension('twig', array( // ... 'paths' => array( diff --git a/reference/configuration/web_profiler.rst b/reference/configuration/web_profiler.rst index 2943b476cb6..0c1dfe492d0 100644 --- a/reference/configuration/web_profiler.rst +++ b/reference/configuration/web_profiler.rst @@ -58,7 +58,7 @@ Full Default Configuration .. code-block:: yaml - # app/config/config.yml + # config/packages/dev/web_profiler.yaml web_profiler: toolbar: false intercept_redirects: false @@ -66,7 +66,7 @@ Full Default Configuration .. code-block:: xml - + - - - - - - - - - - .. code-block:: php - - use App\Assetic\CustomWorker; - - $container - ->register(CustomWorker::class) - ->addTag('assetic.factory_worker') - ; - -assetic.filter --------------- - -**Purpose**: Register a filter - -AsseticBundle uses this tag to register common filters. You can also use -this tag to register your own filters. - -First, you need to create a filter:: - - use Assetic\Asset\AssetInterface; - use Assetic\Filter\FilterInterface; - - class MyFilter implements FilterInterface - { - public function filterLoad(AssetInterface $asset) - { - $asset->setContent('alert("yo");' . $asset->getContent()); - } - - public function filterDump(AssetInterface $asset) - { - // ... - } - } - -Second, define a service: - -.. configuration-block:: - - .. code-block:: yaml - - services: - App\Assetic\CustomFilter: - tags: - - { name: assetic.filter, alias: my_filter } - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - use App\Assetic\CustomFilter; - - $container - ->register(CustomFilter::class) - ->addTag('assetic.filter', array('alias' => 'my_filter')) - ; - -Finally, apply the filter: - -.. code-block:: twig - - {% javascripts - '@AcmeBaseBundle/Resources/public/js/global.js' - filter='my_filter' - %} - - {% endjavascripts %} - -You can also apply your filter via the ``assetic.filters.my_filter.apply_to`` -config option as it's described here: :doc:`/frontend/assetic/apply_to_option`. -In order to do that, you must define your filter service in a separate xml -config file and point to this file's path via the ``assetic.filters.my_filter.resource`` -configuration key. - -assetic.formula_loader ----------------------- - -**Purpose**: Add a formula loader to the current asset manager - -A Formula loader is a class implementing -``Assetic\\Factory\Loader\\FormulaLoaderInterface`` interface. This class -is responsible for loading assets from a particular kind of resources (for -instance, twig template). Assetic ships loaders for PHP and Twig templates. - -An ``alias`` attribute defines the name of the loader. - -assetic.formula_resource ------------------------- - -**Purpose**: Adds a resource to the current asset manager - -A resource is something formulae can be loaded from. For instance, Twig -templates are resources. - -assetic.templating.php ----------------------- - -**Purpose**: Remove this service if PHP templating is disabled - -The tagged service will be removed from the container if the -``framework.templating.engines`` config section does not contain php. - -assetic.templating.twig ------------------------ - -**Purpose**: Remove this service if Twig templating is disabled - -The tagged service will be removed from the container if -``framework.templating.engines`` config section does not contain ``twig``. - auto_alias ---------- @@ -513,7 +330,7 @@ is generated dynamically. To register your own cache warmer, first create a service that implements the :class:`Symfony\\Component\\HttpKernel\\CacheWarmer\\CacheWarmerInterface` interface:: - // src/Acme/MainBundle/Cache/MyCustomWarmer.php + // src/Cache/MyCustomWarmer.php namespace App\Cache; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; diff --git a/reference/forms/types/entity.rst b/reference/forms/types/entity.rst index 4be56046084..6945ee1b4e3 100644 --- a/reference/forms/types/entity.rst +++ b/reference/forms/types/entity.rst @@ -173,7 +173,7 @@ more details, see the main :ref:`choice_label ` doc // ... $builder->add('genre', EntityType::class, array( - 'class' => 'MyBundle:Genre', + 'class' => 'App\Entity\Genre', 'choice_label' => 'translations[en].name', )); diff --git a/reference/map.rst.inc b/reference/map.rst.inc index 8339192ab96..cfc67ca0832 100644 --- a/reference/map.rst.inc +++ b/reference/map.rst.inc @@ -1,7 +1,7 @@ * **Configuration Options** Ever wondered what configuration options you have available to you in - files such as ``app/config/config.yml``? In this section, all the available + ``config/packages/*.yaml`` files? In this section, all the available configuration is broken down by the key (e.g. ``framework``) that defines each possible section of your Symfony configuration. From 5708a758a4620f97b3a56bf4a021bc3918b7753b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 14 Nov 2017 15:32:43 +0100 Subject: [PATCH 0053/2437] Updated the main email article to Symfony 4/Flex --- email.rst | 130 ++++++++++++++++++------------------------------------ 1 file changed, 43 insertions(+), 87 deletions(-) diff --git a/email.rst b/email.rst index c03ad166a56..451936c974a 100644 --- a/email.rst +++ b/email.rst @@ -4,102 +4,57 @@ How to Send an Email ==================== -Sending emails is a classic task for any web application and one that has -special complications and potential pitfalls. Instead of recreating the wheel, -one solution to send emails is to use the SwiftmailerBundle, which leverages -the power of the `Swift Mailer`_ library. This bundle comes with the Symfony -Standard Edition. +Sending emails is a common task for any web application and one that has +special complications and potential pitfalls. Symfony provides a mailer feature +based on the popular `Swift Mailer`_ library via the `SwiftMailerBundle`_. -.. _swift-mailer-configuration: - -Configuration -------------- - -To use Swift Mailer, you'll need to configure it for your mail server. - -.. tip:: - - Instead of setting up/using your own mail server, you may want to use - a hosted mail provider such as `Mandrill`_, `SendGrid`_, `Amazon SES`_ - or others. These give you an SMTP server, username and password (sometimes - called keys) that can be used with the Swift Mailer configuration. +The Symfony mailer supports sending messages with your own mail servers as well +as using popular email providers like `Mandrill`_, `SendGrid`_, and `Amazon SES`_. -In a standard Symfony installation, some ``swiftmailer`` configuration is -already included: +Installation +------------ -.. configuration-block:: +In applications using :doc:`Symfony Flex `, execute this command to +install and enable the mailer: - .. code-block:: yaml +.. code-block:: terminal - # app/config/config.yml - swiftmailer: - transport: '%mailer_transport%' - host: '%mailer_host%' - username: '%mailer_user%' - password: '%mailer_password%' + $ composer require mailer - .. code-block:: xml +If your application doesn't use Symfony Flex, follow the installation +instructions of the `SwiftMailerBundle`_. - - - - - - - - .. code-block:: php +.. _swift-mailer-configuration: - // app/config/config.php - $container->loadFromExtension('swiftmailer', array( - 'transport' => "%mailer_transport%", - 'host' => "%mailer_host%", - 'username' => "%mailer_user%", - 'password' => "%mailer_password%", - )); +Configuration +------------- -These values (e.g. ``%mailer_transport%``), are reading from the parameters -that are set in the :ref:`parameters.yml ` file. You -can modify the values in that file, or set the values directly here. +The ``config/packages/swiftmailer.yaml`` file created when installing the mailer +provides all the initial config needed to make it work, except the parameters +required to connect to the mail server. Those parameters are defined in the +``MAILER_URL`` environment variable in the ``.env`` file: -The following configuration attributes are available: +.. code-block:: bash -* ``transport`` (``smtp``, ``mail``, ``sendmail``, or ``gmail``) -* ``username`` -* ``password`` -* ``host`` -* ``port`` -* ``encryption`` (``tls``, or ``ssl``) -* ``auth_mode`` (``plain``, ``login``, or ``cram-md5``) -* ``spool`` + # use this to disable the email delivery + MAILER_URL=null://localhost - * ``type`` (how to queue the messages, ``file`` or ``memory`` is supported, see :doc:`/email/spool`) - * ``path`` (where to store the messages) -* ``delivery_addresses`` (an array of email addresses where to send ALL emails) -* ``disable_delivery`` (set to true to disable delivery completely) + # use this to send emails via Gmail (don't use this in production) + MAILER_URL=gmail://username:password@localhost -.. caution:: + # use this to configure a traditional SMTP server + MAILER_URL=smtp://localhost:25?encryption=ssl&auth_mode=login&username=&password= - Starting from SwiftMailer 5.4.5, the ``mail`` transport is deprecated - and will be removed in version 6. Consider using another transport like - ``smtp``, ``sendmail`` or ``gmail``. +Refer to the :doc:`SwiftMailer configuration reference ` +for the detailed explanation of all the available config options. Sending Emails -------------- The Swift Mailer library works by creating, configuring and then sending ``Swift_Message`` objects. The "mailer" is responsible for the actual delivery -of the message and is accessible via the ``mailer`` service. Overall, sending -an email is pretty straightforward:: +of the message and is accessible via the ``Swift_Mailer`` service. Overall, +sending an email is pretty straightforward:: public function indexAction($name, \Swift_Mailer $mailer) { @@ -108,8 +63,8 @@ an email is pretty straightforward:: ->setTo('recipient@example.com') ->setBody( $this->renderView( - // templates/Emails/registration.html.twig - 'Emails/registration.html.twig', + // templates/emails/registration.html.twig + 'emails/registration.html.twig', array('name' => $name) ), 'text/html' @@ -118,7 +73,7 @@ an email is pretty straightforward:: * If you also want to include a plaintext version of the message ->addPart( $this->renderView( - 'Emails/registration.txt.twig', + 'emails/registration.txt.twig', array('name' => $name) ), 'text/plain' @@ -128,9 +83,6 @@ an email is pretty straightforward:: $mailer->send($message); - // or, you can also fetch the mailer service this way - // $this->get('mailer')->send($message); - return $this->render(...); } @@ -140,7 +92,7 @@ template might look something like this: .. code-block:: html+jinja - {# templates/Emails/registration.html.twig #} + {# templates/emails/registration.html.twig #}

    You did it! You registered!

    Hi {{ name }}! You're successfully registered. @@ -154,19 +106,23 @@ template might look something like this: The ``$message`` object supports many more options, such as including attachments, -adding HTML content, and much more. Fortunately, Swift Mailer covers the topic -of `Creating Messages`_ in great detail in its documentation. +adding HTML content, and much more. Refer to the `Creating Messages`_ section +of the Swift Mailer documentation for more details. Learn more ---------- .. toctree:: :maxdepth: 1 - :glob: - email/* + email/dev_environment + email/gmail + email/cloud + email/spool + email/testing .. _`Swift Mailer`: http://swiftmailer.org/ +.. _`SwiftMailerBundle`: https://github.com/symfony/swiftmailer-bundle .. _`Creating Messages`: http://swiftmailer.org/docs/messages.html .. _`Mandrill`: https://mandrill.com/ .. _`SendGrid`: https://sendgrid.com/ From 1732ccc0b70dc549edc989ae8bdd00e98c38d855 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 14 Nov 2017 15:40:31 +0100 Subject: [PATCH 0054/2437] Fixed a RST reference --- email.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/email.rst b/email.rst index 451936c974a..56ac022f8c2 100644 --- a/email.rst +++ b/email.rst @@ -45,7 +45,7 @@ required to connect to the mail server. Those parameters are defined in the # use this to configure a traditional SMTP server MAILER_URL=smtp://localhost:25?encryption=ssl&auth_mode=login&username=&password= -Refer to the :doc:`SwiftMailer configuration reference ` +Refer to the :doc:`SwiftMailer configuration reference ` for the detailed explanation of all the available config options. Sending Emails From 9690dfdb12c9d28fad06bf454c6e7f994d3e0555 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 14 Nov 2017 17:24:26 +0100 Subject: [PATCH 0055/2437] Updated the Workflow articles to Symfony 4 --- workflow.rst | 8 +++- workflow/dumping-workflows.rst | 8 ++-- workflow/state-machines.rst | 26 +++++++++--- workflow/usage.rst | 73 ++++++++++++++++++++++------------ 4 files changed, 78 insertions(+), 37 deletions(-) diff --git a/workflow.rst b/workflow.rst index 8e4cba3b5a9..b25e62b8379 100644 --- a/workflow.rst +++ b/workflow.rst @@ -41,10 +41,14 @@ By defining a workflow like this, there is an overview how the process looks lik logic is not mixed with the controllers, models or view. The order of the steps can be changed by changing the configuration only. +Learn more +---------- + .. toctree:: :maxdepth: 1 - :glob: - workflow/* + workflow/usage + workflow/state-machines + workflow/dumping-workflows .. _Petri nets: https://en.wikipedia.org/wiki/Petri_net diff --git a/workflow/dumping-workflows.rst b/workflow/dumping-workflows.rst index 0e784062c41..fd323f7efeb 100644 --- a/workflow/dumping-workflows.rst +++ b/workflow/dumping-workflows.rst @@ -4,8 +4,8 @@ How to Dump Workflows ===================== -To help you debug your workflows, you can dump a representation of your workflow with -the use of a ``DumperInterface``. Use the ``GraphvizDumper`` to create a +To help you debug your workflows, you can dump a representation of your workflow +with the use of a ``DumperInterface``. Use the ``GraphvizDumper`` to create a PNG image of the workflow defined above:: // dump-graph.php @@ -20,8 +20,8 @@ The result will look like this: .. image:: /_images/components/workflow/blogpost.png -If you have configured your workflow with the Symfony framework, you may dump the dot file -with the ``WorkflowDumpCommand``: +Inside a Symfony application with both Workflow and Console support, you can +dump the dot file with the ``workflow:dump`` command: .. code-block:: terminal diff --git a/workflow/state-machines.rst b/workflow/state-machines.rst index 25770be0314..93e078eaac6 100644 --- a/workflow/state-machines.rst +++ b/workflow/state-machines.rst @@ -28,7 +28,7 @@ Below is the configuration for the pull request state machine. .. code-block:: yaml - # app/config/config.yml + # config/packages/workflow.yaml framework: workflows: pull_request: @@ -67,7 +67,7 @@ Below is the configuration for the pull request state machine. .. code-block:: xml - + loadFromExtension('framework', array( // ... 'workflows' => array( @@ -190,8 +189,23 @@ Below is the configuration for the pull request state machine. ), )); -You can now use this state machine by getting the ``state_machine.pull_request`` service:: +In a Symfony application using the +:ref:`default services.yaml configuration `, +you can get this state machine by injecting the Workflow registry service:: + + // ... + use Symfony\Component\Workflow\Registry; + + class SomeService + { + private $stateMachine; + + public function __constructor(Registry $workflows) + { + $this->stateMachine = $workflows->get('pull_request'); + } - $stateMachine = $this->container->get('state_machine.pull_request'); + // ... + } .. _Petri net: https://en.wikipedia.org/wiki/Petri_net diff --git a/workflow/usage.rst b/workflow/usage.rst index 9e0124d904a..c68528a5884 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -1,8 +1,15 @@ .. index:: single: Workflow; Usage -How to Use the Workflow -======================= +How to Create and Use Workflows +=============================== + +Before creating your first workflow, execute this command to install the +:doc:`Workflow component ` in your application: + +.. code-block:: terminal + + $ composer require workflow A workflow is a process or a lifecycle that your objects go through. Each step or stage in the process is called a *place*. You do also define *transitions* @@ -14,15 +21,15 @@ A set of places and transitions creates a **definition**. A workflow needs a ``Definition`` and a way to write the states to the objects (i.e. an instance of a :class:`Symfony\\Component\\Workflow\\MarkingStore\\MarkingStoreInterface`.) -Consider the following example for a blog post. A post can have places: -'draft', 'review', 'rejected', 'published'. You can define the workflow +Consider the following example for a blog post that can have these places: +``draft``, ``review``, ``rejected``, ``published``. You can define the workflow like this: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/workflow.yaml framework: workflows: blog_publishing: @@ -51,7 +58,7 @@ like this: .. code-block:: xml - + loadFromExtension('framework', array( // ... @@ -152,28 +159,43 @@ like this: .. tip:: - The ``type`` (default value ``single_state``) and ``arguments`` (default value ``marking``) - attributes of the ``marking_store`` option are optional. If omitted, their default values - will be used. + The ``type`` (default value ``single_state``) and ``arguments`` (default + value ``marking``) attributes of the ``marking_store`` option are optional. + If omitted, their default values will be used. -With this workflow named ``blog_publishing``, you can get help to decide -what actions are allowed on a blog post:: +With this workflow named ``blog_publishing``, you can now decide what actions +are allowed on a blog post. For example, inside a controller of an application +using the :ref:`default services.yaml configuration `, +you can get the workflow by injecting the Workflow registry service:: - $post = new \App\Entity\BlogPost(); + // ... + use Symfony\Component\Workflow\Registry; - $workflow = $this->container->get('workflow.blog_publishing'); - $workflow->can($post, 'publish'); // False - $workflow->can($post, 'to_review'); // True + class BlogController + { + public function edit(Registry $workflows) + { + $post = new \App\Entity\BlogPost(); + $workflow = $workflows->get($post); - // Update the currentState on the post - try { - $workflow->apply($post, 'to_review'); - } catch (LogicException $e) { - // ... - } + // if there are multiple workflows for the same class, + // pass the workflow name as the second argument + // $workflow = $workflows->get($post, 'blog_publishing'); - // See all the available transition for the post in the current state - $transitions = $workflow->getEnabledTransitions($post); + $workflow->can($post, 'publish'); // False + $workflow->can($post, 'to_review'); // True + + // Update the currentState on the post + try { + $workflow->apply($post, 'to_review'); + } catch (LogicException $e) { + // ... + } + + // See all the available transition for the post in the current state + $transitions = $workflow->getEnabledTransitions($post); + } + } Using Events ------------ @@ -250,7 +272,8 @@ order: * ``workflow.[workflow name].announce`` * ``workflow.[workflow name].announce.[transition name]`` -Here is an example how to enable logging for every time a the "blog_publishing" workflow leaves a place:: +Here is an example how to enable logging for every time the ``blog_publishing`` +workflow leaves a place:: use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; From 0261149c3638983374557b79ecf4d00f71b4eb71 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 14 Nov 2017 17:26:08 +0100 Subject: [PATCH 0056/2437] Fixed a typo --- workflow/state-machines.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/state-machines.rst b/workflow/state-machines.rst index 93e078eaac6..0f9c70cdd07 100644 --- a/workflow/state-machines.rst +++ b/workflow/state-machines.rst @@ -67,7 +67,7 @@ Below is the configuration for the pull request state machine. .. code-block:: xml - + Date: Tue, 14 Nov 2017 17:43:07 +0100 Subject: [PATCH 0057/2437] More Symfony 4 updates for the service tags article --- service_container/tags.rst | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/service_container/tags.rst b/service_container/tags.rst index 34d6c852de9..19fd550dfdc 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -129,11 +129,13 @@ Then, define the chain as a service: .. code-block:: yaml + # config/services.yaml services: App\Mail\TransportChain: ~ .. code-block:: xml + autowire(TransportChain::class); @@ -162,6 +165,7 @@ For example, you may add the following transports as services: .. code-block:: yaml + # config/services.yaml services: Swift_SmtpTransport: arguments: ['%mailer_host%'] @@ -172,6 +176,7 @@ For example, you may add the following transports as services: .. code-block:: xml + register(\Swift_SmtpTransport::class) ->addArgument('%mailer_host%') ->addTag('app.mail_transport'); @@ -245,18 +251,18 @@ Register the Pass with the Container ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In order to run the compiler pass when the container is compiled, you have to -add the compiler pass to the container in the ``build()`` method of your -bundle:: +add the compiler pass to the container in a :doc:`bundle extension ` +or from your kernel:: - // src/AppBundle.php - - // ... - use Symfony\Component\DependencyInjection\ContainerBuilder; + // src/Kernel.php use App\DependencyInjection\Compiler\MailTransportPass; + // ... - class AppBundle extends Bundle + class Kernel extends Kernel { - public function build(ContainerBuilder $container) + // ... + + protected function build(ContainerBuilder $container) { $container->addCompilerPass(new MailTransportPass()); } @@ -310,6 +316,7 @@ To answer this, change the service declaration: .. code-block:: yaml + # config/services.yaml services: Swift_SmtpTransport: arguments: ['%mailer_host%'] @@ -322,6 +329,7 @@ To answer this, change the service declaration: .. code-block:: xml + register(\Swift_SmtpTransport::class) ->addArgument('%mailer_host%') ->addTag('app.mail_transport', array('alias' => 'foo')); @@ -358,8 +367,8 @@ To answer this, change the service declaration: .. code-block:: yaml + # config/services.yaml services: - # Compact syntax Swift_SendmailTransport: class: \Swift_SendmailTransport From 6d7415f5421a70f368a9053a44203dbc4350018f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 14 Nov 2017 20:43:48 +0100 Subject: [PATCH 0058/2437] Updated routing articles to Symfony 4 --- routing/conditions.rst | 9 ++- routing/custom_route_loader.rst | 28 ++++---- routing/external_resources.rst | 39 +++++------ routing/extra_information.rst | 12 ++-- routing/hostname_pattern.rst | 85 ++++++++++++++---------- routing/optional_placeholders.rst | 24 +++---- routing/redirect_in_config.rst | 41 ++++++------ routing/redirect_trailing_slash.rst | 11 +-- routing/requirements.rst | 32 ++++----- routing/scheme.rst | 8 +-- routing/service_container_parameters.rst | 18 ++--- routing/slash_in_parameter.rst | 11 +-- 12 files changed, 167 insertions(+), 151 deletions(-) diff --git a/routing/conditions.rst b/routing/conditions.rst index 6358ff608f4..b9658d6388a 100644 --- a/routing/conditions.rst +++ b/routing/conditions.rst @@ -12,13 +12,15 @@ define arbitrary matching logic, use the ``conditions`` routing option: .. code-block:: yaml + # config/routes.yaml contact: path: /contact - defaults: { _controller: AcmeDemoBundle:Main:contact } + defaults: { _controller: 'App\Controller\DefaultController::contact' } condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'" .. code-block:: xml + - AcmeDemoBundle:Main:contact + App\Controller\DefaultController::contact context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i' .. code-block:: php + // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('contact', new Route( '/contact', array( - '_controller' => 'AcmeDemoBundle:Main:contact', + '_controller' => 'App\Controller\DefaultController::contact', ), array(), array(), diff --git a/routing/custom_route_loader.rst b/routing/custom_route_loader.rst index ac32a9d9c44..4ccddcaacb0 100644 --- a/routing/custom_route_loader.rst +++ b/routing/custom_route_loader.rst @@ -36,18 +36,18 @@ and therefore have two important methods: :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports` and :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load`. -Take these lines from the ``routing.yml`` in the Symfony Standard Edition: +Take these lines from the ``routes.yaml`` in the Symfony Standard Edition: .. code-block:: yaml # config/routes.yaml - app: - resource: '@AppBundle/Controller/' - type: annotation + controllers: + resource: ../src/Controller/ + type: annotation When the main loader parses this, it tries all registered delegate loaders and calls their :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::supports` -method with the given resource (``@AppBundle/Controller/``) +method with the given resource (``../src/Controller/``) and type (``annotation``) as arguments. When one of the loader returns ``true``, its :method:`Symfony\\Component\\Config\\Loader\\LoaderInterface::load` method will be called, which should return a :class:`Symfony\\Component\\Routing\\RouteCollection` @@ -56,7 +56,7 @@ containing :class:`Symfony\\Component\\Routing\\Route` objects. .. note:: Routes loaded this way will be cached by the Router the same way as - when they are defined in one of the default formats (e.g. XML, YML, + when they are defined in one of the default formats (e.g. XML, YAML, PHP file). Creating a custom Loader @@ -97,7 +97,7 @@ you do. The resource name itself is not actually used in the example:: // prepare a new route $path = '/extra/{parameter}'; $defaults = array( - '_controller' => 'AppBundle:Extra:extra', + '_controller' => 'App\Controller\ExtraController::extra', ); $requirements = array( 'parameter' => '\d+', @@ -120,8 +120,7 @@ you do. The resource name itself is not actually used in the example:: } Make sure the controller you specify really exists. In this case you -have to create an ``extraAction()`` method in the ``ExtraController`` -of the ``AppBundle``:: +have to create an ``extra()`` method in the ``ExtraController``:: // src/Controller/ExtraController.php namespace App\Controller; @@ -131,7 +130,7 @@ of the ``AppBundle``:: class ExtraController extends Controller { - public function extraAction($parameter) + public function extra($parameter) { return new Response($parameter); } @@ -152,6 +151,7 @@ Now define a service for the ``ExtraLoader``: .. code-block:: xml + import($resource, $type); diff --git a/routing/external_resources.rst b/routing/external_resources.rst index cb4600529c6..1493d2f3ce9 100644 --- a/routing/external_resources.rst +++ b/routing/external_resources.rst @@ -14,9 +14,9 @@ This can be done by "importing" directories into the routing configuration: .. code-block:: yaml # config/routes.yaml - app: - resource: '@AppBundle/Controller/' - type: annotation # required to enable the Annotation reader for this resource + controllers: + resource: ../src/Controller/ + type: annotation .. code-block:: xml @@ -27,8 +27,7 @@ This can be done by "importing" directories into the routing configuration: xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - - + .. code-block:: php @@ -38,27 +37,23 @@ This can be done by "importing" directories into the routing configuration: $collection = new RouteCollection(); $collection->addCollection( - // second argument is the type, which is required to enable - // the annotation reader for this resource - $loader->import("@AppBundle/Controller/", "annotation") + $loader->import("../src/Controller/", "annotation") ); return $collection; .. note:: - When importing resources from YAML, the key (e.g. ``app``) is meaningless. + When importing resources from YAML, the key (e.g. ``controllers``) is meaningless. Just be sure that it's unique so no other lines override it. The ``resource`` key loads the given routing resource. In this example the -resource is a directory, where the ``@AppBundle`` shortcut syntax resolves -to the full path of the AppBundle. When pointing to a directory, all files -in that directory are parsed and put into the routing. +resource is a directory and all files in that directory are parsed and put into +the routing. .. note:: - You can also include other routing configuration files, this is often - used to import the routing of third party bundles: + You can also include other routing configuration files: .. configuration-block:: @@ -66,7 +61,7 @@ in that directory are parsed and put into the routing. # config/routes.yaml app: - resource: '@AcmeOtherBundle/Resources/config/routing.yml' + resource: '@ThirdPartyBundle/Resources/config/routing.yaml' .. code-block:: xml @@ -77,7 +72,7 @@ in that directory are parsed and put into the routing. xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - + .. code-block:: php @@ -87,7 +82,7 @@ in that directory are parsed and put into the routing. $collection = new RouteCollection(); $collection->addCollection( - $loader->import("@AcmeOtherBundle/Resources/config/routing.php") + $loader->import("@ThirdPartyBundle/Resources/config/routing.php") ); return $collection; @@ -96,7 +91,7 @@ Prefixing Imported Routes ~~~~~~~~~~~~~~~~~~~~~~~~~ You can also choose to provide a "prefix" for the imported routes. For example, -suppose you want to prefix all routes in the AppBundle with ``/site`` (e.g. +suppose you want to prefix all application routes with ``/site`` (e.g. ``/site/blog/{slug}`` instead of ``/blog/{slug}``): .. configuration-block:: @@ -104,8 +99,8 @@ suppose you want to prefix all routes in the AppBundle with ``/site`` (e.g. .. code-block:: yaml # config/routes.yaml - app: - resource: '@AppBundle/Controller/' + controllers: + resource: '../src/Controller/' type: annotation prefix: /site @@ -119,7 +114,7 @@ suppose you want to prefix all routes in the AppBundle with ``/site`` (e.g. http://symfony.com/schema/routing/routing-1.0.xsd"> @@ -129,7 +124,7 @@ suppose you want to prefix all routes in the AppBundle with ``/site`` (e.g. // config/routes.php use Symfony\Component\Routing\RouteCollection; - $app = $loader->import('@AppBundle/Controller/', 'annotation'); + $app = $loader->import('../src/Controller/', 'annotation'); $app->addPrefix('/site'); $collection = new RouteCollection(); diff --git a/routing/extra_information.rst b/routing/extra_information.rst index cdf35bad73b..6feb31e195e 100644 --- a/routing/extra_information.rst +++ b/routing/extra_information.rst @@ -17,7 +17,7 @@ to your controller, and as attributes of the ``Request`` object: blog: path: /blog/{page} defaults: - _controller: AppBundle:Blog:index + _controller: App\Controller\BlogController::index page: 1 title: "Hello world!" @@ -31,7 +31,7 @@ to your controller, and as attributes of the ``Request`` object: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Blog:index + App\Controller\BlogController::index 1 Hello world! @@ -45,7 +45,7 @@ to your controller, and as attributes of the ``Request`` object: $collection = new RouteCollection(); $collection->add('blog', new Route('/blog/{page}', array( - '_controller' => 'AppBundle:Blog:index', + '_controller' => 'App\Controller\BlogController::index', 'page' => 1, 'title' => 'Hello world!', ))); @@ -55,7 +55,7 @@ to your controller, and as attributes of the ``Request`` object: Now, you can access this extra parameter in your controller, as an argument to the controller method:: - public function indexAction($page, $title) + public function index($page, $title) { // ... } @@ -63,8 +63,8 @@ to the controller method:: Alternatively, the title could be accessed through the ``Request`` object:: use Symfony\Component\HttpFoundation\Request; - - public function indexAction(Request $request, $page) + + public function index(Request $request, $page) { $title = $request->attributes->get('title'); diff --git a/routing/hostname_pattern.rst b/routing/hostname_pattern.rst index 93bc5e00d93..66fd98ff3aa 100644 --- a/routing/hostname_pattern.rst +++ b/routing/hostname_pattern.rst @@ -21,7 +21,7 @@ You can also match on the HTTP *host* of the incoming request. /** * @Route("/", name="mobile_homepage", host="m.example.com") */ - public function mobileHomepageAction() + public function mobileHomepage() { // ... } @@ -29,7 +29,7 @@ You can also match on the HTTP *host* of the incoming request. /** * @Route("/", name="homepage") */ - public function homepageAction() + public function homepage() { // ... } @@ -37,17 +37,19 @@ You can also match on the HTTP *host* of the incoming request. .. code-block:: yaml + # config/routes.yaml mobile_homepage: path: / host: m.example.com - defaults: { _controller: AppBundle:Main:mobileHomepage } + defaults: { _controller: App\Controller\MainController::mobileHomepage } homepage: path: / - defaults: { _controller: AppBundle:Main:homepage } + defaults: { _controller: App\Controller\MainController::homepage } .. code-block:: xml + - AppBundle:Main:mobileHomepage + App\Controller\MainController::mobileHomepage - AppBundle:Main:homepage + App\Controller\MainController::homepage .. code-block:: php + // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('mobile_homepage', new Route('/', array( - '_controller' => 'AppBundle:Main:mobileHomepage', + '_controller' => 'App\Controller\MainController::mobileHomepage', ), array(), array(), 'm.example.com')); $collection->add('homepage', new Route('/', array( - '_controller' => 'AppBundle:Main:homepage', + '_controller' => 'App\Controller\MainController::homepage', ))); return $collection; @@ -103,7 +106,7 @@ you can use placeholders in your hostname: /** * @Route("/", name="projects_homepage", host="{project_name}.example.com") */ - public function projectsHomepageAction() + public function projectsHomepage() { // ... } @@ -111,7 +114,7 @@ you can use placeholders in your hostname: /** * @Route("/", name="homepage") */ - public function homepageAction() + public function homepage() { // ... } @@ -119,17 +122,19 @@ you can use placeholders in your hostname: .. code-block:: yaml + # config/routes.yaml projects_homepage: path: / host: "{project_name}.example.com" - defaults: { _controller: AppBundle:Main:projectsHomepage } + defaults: { _controller: App\Controller\MainController::projectsHomepage } homepage: path: / - defaults: { _controller: AppBundle:Main:homepage } + defaults: { _controller: App\Controller\MainController::homepage } .. code-block:: xml + - AppBundle:Main:projectsHomepage + App\Controller\MainController::projectsHomepage - AppBundle:Main:homepage + App\Controller\MainController::homepage .. code-block:: php + // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('project_homepage', new Route('/', array( - '_controller' => 'AppBundle:Main:projectsHomepage', + '_controller' => 'App\Controller\MainController::projectsHomepage', ), array(), array(), '{project_name}.example.com')); $collection->add('homepage', new Route('/', array( - '_controller' => 'AppBundle:Main:homepage', + '_controller' => 'App\Controller\MainController::homepage', ))); return $collection; @@ -186,7 +192,7 @@ instance, if you want to match both ``m.example.com`` and * requirements={"subdomain"="m|mobile"} * ) */ - public function mobileHomepageAction() + public function mobileHomepage() { // ... } @@ -194,7 +200,7 @@ instance, if you want to match both ``m.example.com`` and /** * @Route("/", name="homepage") */ - public function homepageAction() + public function homepage() { // ... } @@ -202,21 +208,23 @@ instance, if you want to match both ``m.example.com`` and .. code-block:: yaml + # config/routes.yaml mobile_homepage: path: / host: "{subdomain}.example.com" defaults: - _controller: AppBundle:Main:mobileHomepage + _controller: App\Controller\MainController::mobileHomepage subdomain: m requirements: subdomain: m|mobile homepage: path: / - defaults: { _controller: AppBundle:Main:homepage } + defaults: { _controller: App\Controller\MainController::homepage } .. code-block:: xml + - AppBundle:Main:mobileHomepage + App\Controller\MainController::mobileHomepage m m|mobile - AppBundle:Main:homepage + App\Controller\MainController::homepage .. code-block:: php + // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('mobile_homepage', new Route('/', array( - '_controller' => 'AppBundle:Main:mobileHomepage', + '_controller' => 'App\Controller\MainController::mobileHomepage', 'subdomain' => 'm', ), array( 'subdomain' => 'm|mobile', ), array(), '{subdomain}.example.com')); $collection->add('homepage', new Route('/', array( - '_controller' => 'AppBundle:Main:homepage', + '_controller' => 'App\Controller\MainController::homepage', ))); return $collection; @@ -279,7 +288,7 @@ instance, if you want to match both ``m.example.com`` and * requirements={"domain"="%domain%"} * ) */ - public function mobileHomepageAction() + public function mobileHomepage() { // ... } @@ -287,7 +296,7 @@ instance, if you want to match both ``m.example.com`` and /** * @Route("/", name="homepage") */ - public function homepageAction() + public function homepage() { // ... } @@ -295,21 +304,23 @@ instance, if you want to match both ``m.example.com`` and .. code-block:: yaml + # config/routes.yaml mobile_homepage: path: / host: "m.{domain}" defaults: - _controller: AppBundle:Main:mobileHomepage + _controller: App\Controller\MainController::mobileHomepage domain: '%domain%' requirements: domain: '%domain%' homepage: path: / - defaults: { _controller: AppBundle:Main:homepage } + defaults: { _controller: App\Controller\MainController::homepage } .. code-block:: xml + - AppBundle:Main:mobileHomepage + App\Controller\MainController::mobileHomepage %domain% %domain% - AppBundle:Main:homepage + App\Controller\MainController::homepage .. code-block:: php + // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('mobile_homepage', new Route('/', array( - '_controller' => 'AppBundle:Main:mobileHomepage', + '_controller' => 'App\Controller\MainController::mobileHomepage', 'domain' => '%domain%', ), array( 'domain' => '%domain%', ), array(), 'm.{domain}')); $collection->add('homepage', new Route('/', array( - '_controller' => 'AppBundle:Main:homepage', + '_controller' => 'App\Controller\MainController::homepage', ))); return $collection; @@ -379,24 +391,27 @@ You can also set the host option on imported routes: .. code-block:: yaml + # config/routes.yaml app_hello: - resource: '@AppBundle/Resources/config/routing.yml' + resource: '@ThirdPartyBundle/Resources/config/routing.yml' host: "hello.example.com" .. code-block:: xml + - + .. code-block:: php - $collection = $loader->import("@AppBundle/Resources/config/routing.php"); + // config/routes.php + $collection = $loader->import("@ThirdPartyBundle/Resources/config/routing.php"); $collection->setHost('hello.example.com'); return $collection; diff --git a/routing/optional_placeholders.rst b/routing/optional_placeholders.rst index 462bd71e8f5..7c3c4288c49 100644 --- a/routing/optional_placeholders.rst +++ b/routing/optional_placeholders.rst @@ -21,7 +21,7 @@ the available blog posts for this imaginary blog application: /** * @Route("/blog") */ - public function indexAction() + public function index() { // ... } @@ -32,7 +32,7 @@ the available blog posts for this imaginary blog application: # config/routes.yaml blog: path: /blog - defaults: { _controller: AppBundle:Blog:index } + defaults: { _controller: App\Controller\BlogController::index } .. code-block:: xml @@ -44,7 +44,7 @@ the available blog posts for this imaginary blog application: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Blog:index + App\Controller\BlogController::index @@ -56,7 +56,7 @@ the available blog posts for this imaginary blog application: $collection = new RouteCollection(); $collection->add('blog', new Route('/blog', array( - '_controller' => 'AppBundle:Blog:index', + '_controller' => 'App\Controller\BlogController::index', ))); return $collection; @@ -77,7 +77,7 @@ entries? Update the route to have a new ``{page}`` placeholder: /** * @Route("/blog/{page}") */ - public function indexAction($page) + public function index($page) { // ... } @@ -87,7 +87,7 @@ entries? Update the route to have a new ``{page}`` placeholder: # config/routes.yaml blog: path: /blog/{page} - defaults: { _controller: AppBundle:Blog:index } + defaults: { _controller: App\Controller\BlogController::index } .. code-block:: xml @@ -99,7 +99,7 @@ entries? Update the route to have a new ``{page}`` placeholder: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Blog:index + App\Controller\BlogController::index @@ -111,7 +111,7 @@ entries? Update the route to have a new ``{page}`` placeholder: $collection = new RouteCollection(); $collection->add('blog', new Route('/blog/{page}', array( - '_controller' => 'AppBundle:Blog:index', + '_controller' => 'App\Controller\BlogController::index', ))); return $collection; @@ -137,7 +137,7 @@ This is done by including it in the ``defaults`` collection: /** * @Route("/blog/{page}", defaults={"page" = 1}) */ - public function indexAction($page) + public function index($page) { // ... } @@ -147,7 +147,7 @@ This is done by including it in the ``defaults`` collection: # config/routes.yaml blog: path: /blog/{page} - defaults: { _controller: AppBundle:Blog:index, page: 1 } + defaults: { _controller: App\Controller\BlogController::index, page: 1 } .. code-block:: xml @@ -159,7 +159,7 @@ This is done by including it in the ``defaults`` collection: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Blog:index + App\Controller\BlogController::index 1 @@ -172,7 +172,7 @@ This is done by including it in the ``defaults`` collection: $collection = new RouteCollection(); $collection->add('blog', new Route('/blog/{page}', array( - '_controller' => 'AppBundle:Blog:index', + '_controller' => 'App\Controller\BlogController::index', 'page' => 1, ))); diff --git a/routing/redirect_in_config.rst b/routing/redirect_in_config.rst index b1b8be131e6..c6cbcadef44 100644 --- a/routing/redirect_in_config.rst +++ b/routing/redirect_in_config.rst @@ -27,16 +27,16 @@ action to redirect to this new url: # config/routes.yaml # load some routes - one should ultimately have the path "/app" - AppBundle: - resource: '@AppBundle/Controller/' + controllers: + resource: ../src/Controller/ type: annotation prefix: /app - # redirecting the root - root: + # redirecting the homepage + homepage: path: / defaults: - _controller: FrameworkBundle:Redirect:urlRedirect + _controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction path: /app permanent: true @@ -50,14 +50,14 @@ action to redirect to this new url: http://symfony.com/schema/routing/routing-1.0.xsd"> - - - - FrameworkBundle:Redirect:urlRedirect + + + Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction /app true @@ -72,14 +72,14 @@ action to redirect to this new url: $collection = new RouteCollection(); // load some routes - one should ultimately have the path "/app" - $appRoutes = $loader->import("@AppBundle/Controller/", "annotation"); + $appRoutes = $loader->import("../src/Controller/", "annotation"); $appRoutes->setPrefix('/app'); $collection->addCollection($appRoutes); - // redirecting the root - $collection->add('root', new Route('/', array( - '_controller' => 'FrameworkBundle:Redirect:urlRedirect', + // redirecting the homepage + $collection->add('homepage', new Route('/', array( + '_controller' => 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction', 'path' => '/app', 'permanent' => true, ))); @@ -108,11 +108,10 @@ action: # ... - # redirecting the admin home - root: + admin: path: /wp-admin defaults: - _controller: FrameworkBundle:Redirect:redirect + _controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction route: sonata_admin_dashboard permanent: true @@ -127,9 +126,8 @@ action: - - - FrameworkBundle:Redirect:redirect + + Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction sonata_admin_dashboard true @@ -144,9 +142,8 @@ action: $collection = new RouteCollection(); // ... - // redirecting the root - $collection->add('root', new Route('/wp-admin', array( - '_controller' => 'FrameworkBundle:Redirect:redirect', + $collection->add('admin', new Route('/wp-admin', array( + '_controller' => 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction', 'route' => 'sonata_admin_dashboard', 'permanent' => true, ))); diff --git a/routing/redirect_trailing_slash.rst b/routing/redirect_trailing_slash.rst index 0963938b6bb..720bd019890 100644 --- a/routing/redirect_trailing_slash.rst +++ b/routing/redirect_trailing_slash.rst @@ -20,7 +20,7 @@ new URL with a 301 response status code:: class RedirectingController extends Controller { - public function removeTrailingSlashAction(Request $request) + public function removeTrailingSlash(Request $request) { $pathInfo = $request->getPathInfo(); $requestUri = $request->getRequestUri(); @@ -52,7 +52,7 @@ system, as explained below: * @Route("/{url}", name="remove_trailing_slash", * requirements={"url" = ".*\/$"}, methods={"GET"}) */ - public function removeTrailingSlashAction(Request $request) + public function removeTrailingSlash(Request $request) { // ... } @@ -60,9 +60,10 @@ system, as explained below: .. code-block:: yaml + # config/routes.yaml remove_trailing_slash: path: /{url} - defaults: { _controller: AppBundle:Redirecting:removeTrailingSlash } + defaults: { _controller: App\Controller\RedirectingController::removeTrailingSlash } requirements: url: .*/$ methods: [GET] @@ -72,7 +73,7 @@ system, as explained below: - AppBundle:Redirecting:removeTrailingSlash + App\Controller\RedirectingController::removeTrailingSlash .*/$ @@ -88,7 +89,7 @@ system, as explained below: new Route( '/{url}', array( - '_controller' => 'AppBundle:Redirecting:removeTrailingSlash', + '_controller' => 'App\Controller\RedirectingController::removeTrailingSlash', ), array( 'url' => '.*/$', diff --git a/routing/requirements.rst b/routing/requirements.rst index 4a6dd5a8592..92deb348c7a 100644 --- a/routing/requirements.rst +++ b/routing/requirements.rst @@ -23,7 +23,7 @@ a routing ``{wildcard}`` to only match some regular expression: /** * @Route("/blog/{page}", name="blog_list", requirements={"page": "\d+"}) */ - public function listAction($page) + public function list($page) { // ... } @@ -34,7 +34,7 @@ a routing ``{wildcard}`` to only match some regular expression: # config/routes.yaml blog_list: path: /blog/{page} - defaults: { _controller: AppBundle:Blog:list } + defaults: { _controller: App\Controller\BlogController::list } requirements: page: '\d+' @@ -48,7 +48,7 @@ a routing ``{wildcard}`` to only match some regular expression: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Blog:list + App\Controller\BlogController::list \d+ @@ -63,7 +63,7 @@ a routing ``{wildcard}`` to only match some regular expression: $collection = new RouteCollection(); $collection->add('blog_list', new Route('/blog/{page}', array( - '_controller' => 'AppBundle:Blog:list', + '_controller' => 'App\Controller\BlogController::list', ), array( 'page' => '\d+' ))); @@ -101,7 +101,7 @@ URL: * "_locale": "en|fr" * }) */ - public function homepageAction($_locale) + public function homepage($_locale) { } } @@ -111,7 +111,7 @@ URL: # config/routes.yaml homepage: path: /{_locale} - defaults: { _controller: AppBundle:Main:homepage, _locale: en } + defaults: { _controller: App\Controller\MainController::homepage, _locale: en } requirements: _locale: en|fr @@ -125,7 +125,7 @@ URL: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Main:homepage + App\Controller\MainController::homepage en en|fr @@ -139,7 +139,7 @@ URL: $collection = new RouteCollection(); $collection->add('homepage', new Route('/{_locale}', array( - '_controller' => 'AppBundle:Main:homepage', + '_controller' => 'App\Controller\MainController::homepage', '_locale' => 'en', ), array( '_locale' => 'en|fr', @@ -200,7 +200,7 @@ accomplished with the following route configuration: /** * @Route("/api/posts/{id}", methods={"GET","HEAD"}) */ - public function showAction($id) + public function show($id) { // ... return a JSON response with the post } @@ -208,7 +208,7 @@ accomplished with the following route configuration: /** * @Route("/api/posts/{id}", methods="PUT") */ - public function editAction($id) + public function edit($id) { // ... edit a post } @@ -219,12 +219,12 @@ accomplished with the following route configuration: # config/routes.yaml api_post_show: path: /api/posts/{id} - defaults: { _controller: AppBundle:BlogApi:show } + defaults: { _controller: App\Controller\BlogApiController::show } methods: [GET, HEAD] api_post_edit: path: /api/posts/{id} - defaults: { _controller: AppBundle:BlogApi:edit } + defaults: { _controller: App\Controller\BlogApiController::edit } methods: [PUT] .. code-block:: xml @@ -237,11 +237,11 @@ accomplished with the following route configuration: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:BlogApi:show + App\Controller\BlogApiController::show - AppBundle:BlogApi:edit + App\Controller\BlogApiController::edit @@ -253,11 +253,11 @@ accomplished with the following route configuration: $collection = new RouteCollection(); $collection->add('api_post_show', new Route('/api/posts/{id}', array( - '_controller' => 'AppBundle:BlogApi:show', + '_controller' => 'App\Controller\BlogApiController::show', ), array(), array(), '', array(), array('GET', 'HEAD'))); $collection->add('api_post_edit', new Route('/api/posts/{id}', array( - '_controller' => 'AppBundle:BlogApi:edit', + '_controller' => 'App\Controller\BlogApiController::edit', ), array(), array(), '', array(), array('PUT'))); return $collection; diff --git a/routing/scheme.rst b/routing/scheme.rst index 25308bedf06..8deff6c7cd9 100644 --- a/routing/scheme.rst +++ b/routing/scheme.rst @@ -23,7 +23,7 @@ the URI scheme via schemes: /** * @Route("/secure", name="secure", schemes={"https"}) */ - public function secureAction() + public function secure() { // ... } @@ -34,7 +34,7 @@ the URI scheme via schemes: # config/routes.yaml secure: path: /secure - defaults: { _controller: AppBundle:Main:secure } + defaults: { _controller: App\Controller\MainController::secure } schemes: [https] .. code-block:: xml @@ -47,7 +47,7 @@ the URI scheme via schemes: xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Main:secure + App\Controller\MainController::secure @@ -59,7 +59,7 @@ the URI scheme via schemes: $collection = new RouteCollection(); $collection->add('secure', new Route('/secure', array( - '_controller' => 'AppBundle:Main:secure', + '_controller' => 'App\Controller\MainController::secure', ), array(), array(), '', array('https'))); return $collection; diff --git a/routing/service_container_parameters.rst b/routing/service_container_parameters.rst index a8c2e3e5a77..a5e2fcff816 100644 --- a/routing/service_container_parameters.rst +++ b/routing/service_container_parameters.rst @@ -21,7 +21,7 @@ inside your routing configuration: # config/routes.yaml contact: path: /{_locale}/contact - defaults: { _controller: AppBundle:Main:contact } + defaults: { _controller: App\Controller\MainController::contact } requirements: _locale: '%app.locales%' @@ -35,7 +35,7 @@ inside your routing configuration: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Main:contact + App\Controller\MainController::contact %app.locales% @@ -48,7 +48,7 @@ inside your routing configuration: $collection = new RouteCollection(); $collection->add('contact', new Route('/{_locale}/contact', array( - '_controller' => 'AppBundle:Main:contact', + '_controller' => 'App\Controller\MainController::contact', ), array( '_locale' => '%app.locales%', ))); @@ -62,13 +62,13 @@ in your container: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml parameters: app.locales: en|es .. code-block:: xml - + setParameter('app.locales', 'en|es'); You can also use a parameter to define your route path (or part of your @@ -95,7 +95,7 @@ path): # config/routes.yaml some_route: path: /%app.route_prefix%/contact - defaults: { _controller: AppBundle:Main:contact } + defaults: { _controller: App\Controller\MainController::contact } .. code-block:: xml @@ -107,7 +107,7 @@ path): http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Main:contact + App\Controller\MainController::contact @@ -119,7 +119,7 @@ path): $collection = new RouteCollection(); $collection->add('some_route', new Route('/%app.route_prefix%/contact', array( - '_controller' => 'AppBundle:Main:contact', + '_controller' => 'App\Controller\MainController::contact', ))); return $collection; diff --git a/routing/slash_in_parameter.rst b/routing/slash_in_parameter.rst index b21d291d45f..08371caec16 100644 --- a/routing/slash_in_parameter.rst +++ b/routing/slash_in_parameter.rst @@ -33,7 +33,7 @@ a more permissive regular expression for it: /** * @Route("/share/{token}", name="share", requirements={"token"=".+"}) */ - public function shareAction($token) + public function share($token) { // ... } @@ -41,14 +41,16 @@ a more permissive regular expression for it: .. code-block:: yaml + # config/routes.yaml share: path: /share/{token} - defaults: { _controller: AppBundle:Default:share } + defaults: { _controller: App\Controller\DefaultController::share } requirements: token: .+ .. code-block:: xml + - AppBundle:Default:share + App\Controller\DefaultController::share .+ .. code-block:: php + // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('share', new Route('/share/{token}', array( - '_controller' => 'AppBundle:Default:share', + '_controller' => 'App\Controller\DefaultController::share', ), array( 'token' => '.+', ))); From 1c398aab0bcf3fb989e6fc4ab2205ffd1b3616f0 Mon Sep 17 00:00:00 2001 From: Krzysztof Lament Date: Tue, 14 Nov 2017 21:09:05 +0100 Subject: [PATCH 0059/2437] Place annotation before the number method An annotation should correspond to a method, not a controller class --- page_creation.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/page_creation.rst b/page_creation.rst index 4670b2b8f6d..b2e219c3b1c 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -116,12 +116,12 @@ After this one-time setup, you can now add your route directly *above* the contr // ... + use Symfony\Component\Routing\Annotation\Route; - - + /** - + * @Route("/lucky/number") - + */ + class LuckyController { + + /** + + * @Route("/lucky/number") + + */ public function number() { // this looks exactly the same From fe14a011d151f3db69fcd6865612fe2e7d1de981 Mon Sep 17 00:00:00 2001 From: David Negreira Date: Tue, 14 Nov 2017 21:20:55 +0100 Subject: [PATCH 0060/2437] Update business-logic.rst no AppBundle in symfony 4 --- best_practices/business-logic.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/best_practices/business-logic.rst b/best_practices/business-logic.rst index e59705e34de..ce12825a4e9 100644 --- a/best_practices/business-logic.rst +++ b/best_practices/business-logic.rst @@ -125,7 +125,7 @@ library or strategy you want for this. In practice, many Symfony applications rely on the independent `Doctrine project`_ to define their model using entities and repositories. Just like with business logic, we recommend storing Doctrine entities in the -AppBundle. +``src/`` directory. The three entities defined by our sample blog application are a good example: From 39732fe0b316c32c4a1e0865cf5b7d8a49f3801e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 14 Nov 2017 23:21:46 +0100 Subject: [PATCH 0061/2437] [#8628] add missing redirection map entry --- _build/redirection_map | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_build/redirection_map b/_build/redirection_map index 33f907fb299..e3c33de6f47 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -77,6 +77,7 @@ /book/configuration /configuration /book/propel /propel/propel /book/performance /performance +/bundles/installation /bundles /cookbook/assetic/apply_to_option /frontend/assetic/apply_to_option /cookbook/assetic/asset_management /frontend/assetic/asset_management /cookbook/assetic/index /frontend/assetic @@ -353,4 +354,4 @@ /templating/templating_service /templates /testing/simulating_authentication /testing/http_authentication /validation/group_service_resolver /form/validation_group_service_resolver -/request/load_balancer_reverse_proxy /deployment/proxies \ No newline at end of file +/request/load_balancer_reverse_proxy /deployment/proxies From 998f617ccd7b3cc7f89f5e6aa743b4afa7111bc5 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 14 Nov 2017 23:24:33 +0100 Subject: [PATCH 0062/2437] clean up removed document from toctree --- bundles/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/bundles/index.rst b/bundles/index.rst index d5349f6353c..c6da8e269e2 100644 --- a/bundles/index.rst +++ b/bundles/index.rst @@ -6,7 +6,6 @@ Bundles .. toctree:: :maxdepth: 2 - installation remove override inheritance From c461ddf234c43d469206569c6b0ea0c7e81657a1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 10 Nov 2017 17:26:39 +0100 Subject: [PATCH 0063/2437] Updated the bundle configuration articles to Symfony 4 --- bundles/configuration.rst | 55 ++++++++------------- bundles/extension.rst | 101 +++++++++++--------------------------- 2 files changed, 50 insertions(+), 106 deletions(-) diff --git a/bundles/configuration.rst b/bundles/configuration.rst index 081e7df682a..51a73837da3 100644 --- a/bundles/configuration.rst +++ b/bundles/configuration.rst @@ -5,11 +5,12 @@ How to Create Friendly Configuration for a Bundle ================================================= -If you open your application configuration file (usually ``app/config/config.yml``), -you'll see a number of different configuration sections, such as ``framework``, -``twig`` and ``doctrine``. Each of these configures a specific bundle, allowing -you to define options at a high level and then let the bundle make all the -low-level, complex changes based on your settings. +If you open your main application configuration directory (usually +``config/packages/``), you'll see a number of different files, such as +``framework.yaml``, ``twig.yaml`` and ``doctrine.yaml``. Each of these +configures a specific bundle, allowing you to define options at a high level and +then let the bundle make all the low-level, complex changes based on your +settings. For example, the following configuration tells the FrameworkBundle to enable the form integration, which involves the definition of quite a few services as well @@ -43,17 +44,6 @@ as integration of other related components: 'form' => true, )); -.. sidebar:: Using Parameters to Configure your Bundle - - If you don't have plans to share your bundle between projects, it doesn't - make sense to use this more advanced way of configuration. Since you use - the bundle only in one project, you can just change the service - configuration each time. - - If you *do* want to be able to configure something from within - ``config.yml``, you can always create a parameter there and use that - parameter somewhere else. - Using the Bundle Extension -------------------------- @@ -71,7 +61,7 @@ bundle configuration would look like: .. code-block:: yaml - # app/config/config.yml + # config/packages/acme_social.yaml acme_social: twitter: client_id: 123 @@ -79,7 +69,7 @@ bundle configuration would look like: .. code-block:: xml - + loadFromExtension('acme_social', array( 'client_id' => 123, 'client_secret' => 'your_secret', @@ -145,20 +135,20 @@ For the configuration example in the previous section, the array passed to your ) Notice that this is an *array of arrays*, not just a single flat array of the -configuration values. This is intentional, as it allows Symfony to parse -several configuration resources. For example, if ``acme_social`` appears in -another configuration file - say ``config_dev.yml`` - with different values -beneath it, the incoming array might look like this:: +configuration values. This is intentional, as it allows Symfony to parse several +configuration resources. For example, if ``acme_social`` appears in another +configuration file - say ``config/packages/dev/acme_social.yaml`` - with +different values beneath it, the incoming array might look like this:: array( - // values from config.yml + // values from config/packages/acme_social.yaml array( 'twitter' => array( 'client_id' => 123, 'client_secret' => 'your_secret', ), ), - // values from config_dev.yml + // values from config/packages/dev/acme_social.yaml array( 'twitter' => array( 'client_id' => 456, @@ -219,7 +209,6 @@ force validation (e.g. if an additional option was passed, an exception will be thrown):: // src/Acme/SocialBundle/DependencyInjection/AcmeSocialExtension.php - public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); @@ -324,12 +313,10 @@ In your extension, you can load this and dynamically set its arguments:: Modifying the Configuration of Another Bundle --------------------------------------------- -If you have multiple bundles that depend on each other, it may be useful -to allow one ``Extension`` class to modify the configuration passed to another -bundle's ``Extension`` class, as if the end-developer has actually placed that -configuration in their ``app/config/config.yml`` file. This can be achieved -using a prepend extension. For more details, see -:doc:`/bundles/prepend_extension`. +If you have multiple bundles that depend on each other, it may be useful to +allow one ``Extension`` class to modify the configuration passed to another +bundle's ``Extension`` class. This can be achieved using a prepend extension. +For more details, see :doc:`/bundles/prepend_extension`. Dump the Configuration ---------------------- @@ -401,7 +388,7 @@ namespace is then replaced with the XSD validation base path returned from method. This namespace is then followed by the rest of the path from the base path to the file itself. -By convention, the XSD file lives in the ``Resources/config/schema``, but you +By convention, the XSD file lives in the ``Resources/config/schema/``, but you can place it anywhere you like. You should return this path as the base path:: // src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php @@ -422,7 +409,7 @@ Assuming the XSD file is called ``hello-1.0.xsd``, the schema location will be .. code-block:: xml - + ` -to return the correct DI alias. The DI alias is the name used to refer to the -bundle in the container (e.g. in the ``app/config/config.yml`` file). By +method to return the correct DI alias. The DI alias is the name used to refer to +the bundle in the container (e.g. in the ``config/packages/`` files). By default, this is done by removing the ``Extension`` suffix and converting the class name to underscores (e.g. ``AcmeHelloExtension``'s DI alias is ``acme_hello``). @@ -86,11 +83,10 @@ container. In the ``load()`` method, you can use PHP code to register service definitions, but it is more common if you put these definitions in a configuration file -(using the Yaml, XML or PHP format). Luckily, you can use the file loaders in -the extension! +(using the YAML, XML or PHP format). For instance, assume you have a file called ``services.xml`` in the -``Resources/config`` directory of your bundle, your ``load()`` method looks like:: +``Resources/config/`` directory of your bundle, your ``load()`` method looks like:: use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\Config\FileLocator; @@ -105,39 +101,22 @@ For instance, assume you have a file called ``services.xml`` in the $loader->load('services.xml'); } -Other available loaders are the ``YamlFileLoader``, ``PhpFileLoader`` and -``IniFileLoader``. - -.. note:: - - The ``IniFileLoader`` can only be used to load parameters and it can only - load them as strings. - -.. caution:: - - If you removed the default file with service definitions (i.e. - ``config/services.yaml``), make sure to also remove it from the - ``imports`` key in ``app/config/config.yml``. +The other available loaders are ``YamlFileLoader`` and ``PhpFileLoader``. Using Configuration to Change the Services ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Extension is also the class that handles the configuration for that -particular bundle (e.g. the configuration in ``app/config/config.yml``). To -read more about it, see the ":doc:`/bundles/configuration`" article. +particular bundle (e.g. the configuration in ``config/packages/.yaml``). +To read more about it, see the ":doc:`/bundles/configuration`" article. Adding Classes to Compile ------------------------- -Symfony creates a big ``classes.php`` file in the cache directory to aggregate -the contents of the PHP classes that are used in every request. This reduces the -I/O operations and increases the application performance. - -Your bundles can also add their own classes into this file thanks to the -``addClassesToCompile()`` and ``addAnnotatedClassesToCompile()`` methods (both -work in the same way, but the second one is for classes that contain PHP -annotations). Define the classes to compile as an array of their fully qualified -class names:: +Bundles can hint Symfony about which of their classes contain annotations so +they are compiled when generating the application cache to improve the overall +performance. Define the list of annotated classes to compile in the +``addAnnotatedClassesToCompile()`` method:: use App\Manager\UserManager; use App\Utils\Slugger; @@ -147,16 +126,12 @@ class names:: { // ... - // this method can't compile classes that contain PHP annotations - $this->addClassesToCompile(array( - UserManager::class, - Slugger::class, - // ... - )); - - // add here only classes that contain PHP annotations $this->addAnnotatedClassesToCompile(array( + // you can define the fully qualified class names... 'App\\Controller\\DefaultController', + // ... but glob patterns are also supported: + '**Bundle\\Controller\\', + // ... )); } @@ -166,24 +141,6 @@ class names:: If some class extends from other classes, all its parents are automatically included in the list of classes to compile. -The classes to compile can also be added using file path patterns:: - - // ... - public function load(array $configs, ContainerBuilder $container) - { - // ... - - $this->addClassesToCompile(array( - '**Bundle\\Manager\\', - // ... - )); - - $this->addAnnotatedClassesToCompile(array( - '**Bundle\\Controller\\', - // ... - )); - } - Patterns are transformed into the actual class namespaces using the classmap generated by Composer. Therefore, before using these patterns, you must generate the full classmap executing the ``dump-autoload`` command of Composer. From cf0a4669ca10f59ad82e300c43dcfa5d53a260cf Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 14 Nov 2017 23:34:17 +0100 Subject: [PATCH 0064/2437] [#8620] minor typo fix --- bundles/extension.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/extension.rst b/bundles/extension.rst index cb601ea6e47..95604f4c40d 100644 --- a/bundles/extension.rst +++ b/bundles/extension.rst @@ -19,7 +19,7 @@ follow these conventions (but later you'll learn how to skip them if needed): * It has to live in the ``DependencyInjection`` namespace of the bundle; * It has to implement the :class:`Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface`, - which is usually achieve by extending the + which is usually achieved by extending the :class:`Symfony\\Component\\DependencyInjection\\Extension\\Extension` class; * The name is equal to the bundle name with the ``Bundle`` suffix replaced by From ad4b3a26b1b9e8a8b12b03fba604860d284d7a27 Mon Sep 17 00:00:00 2001 From: Wouter J Date: Mon, 13 Nov 2017 23:10:37 +0100 Subject: [PATCH 0065/2437] Made two configuration sub guides flex-ready --- configuration/configuration_organization.rst | 9 +- configuration/environments.rst | 359 ++++++++---------- configuration/external_parameters.rst | 114 ++---- .../front_controllers_and_kernel.rst | 39 +- 4 files changed, 209 insertions(+), 312 deletions(-) diff --git a/configuration/configuration_organization.rst b/configuration/configuration_organization.rst index 5c22dfc2572..2bb3cbba181 100644 --- a/configuration/configuration_organization.rst +++ b/configuration/configuration_organization.rst @@ -4,10 +4,9 @@ How to Organize Configuration Files =================================== -The default Symfony Standard Edition defines three -:doc:`execution environments ` called -``dev``, ``prod`` and ``test``. An environment simply represents a way to -execute the same codebase with different configurations. +The Symfony skeleton defines three :doc:`execution environments ` +called ``dev``, ``prod`` and ``test``. An environment simply represents a way +to execute the same codebase with different configurations. In order to select the configuration file to load for each environment, Symfony executes the ``registerContainerConfiguration()`` method of the ``AppKernel`` @@ -17,7 +16,7 @@ class:: use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\Config\Loader\LoaderInterface; - class AppKernel extends Kernel + class Kernel extends BaseKernel { // ... diff --git a/configuration/environments.rst b/configuration/environments.rst index c90657f630f..df77a79b73d 100644 --- a/configuration/environments.rst +++ b/configuration/environments.rst @@ -20,128 +20,58 @@ Different Environments, different Configuration Files ----------------------------------------------------- A typical Symfony application begins with three environments: ``dev``, -``prod``, and ``test``. As mentioned, each environment simply represents -a way to execute the same codebase with different configuration. It should -be no surprise then that each environment loads its own individual configuration -file. If you're using the YAML configuration format, the following files -are used: +``prod`` and ``test``. As mentioned, each environment represents a way to +execute the same codebase with different configuration. It should be no +surprise then that each environment loads its own individual configuration +files. These different files are organized by environment: -* for the ``dev`` environment: ``app/config/config_dev.yml`` -* for the ``prod`` environment: ``app/config/config_prod.yml`` -* for the ``test`` environment: ``app/config/config_test.yml`` +* for the ``dev`` environment: ``config/packages/dev/`` +* for the ``prod`` environment: ``config/packages/prod/`` +* for the ``test`` environment: ``config/packages/test/`` -This works via a simple standard that's used by default inside the ``AppKernel`` -class: +In reality, each environment differs only somewhat from others. This means that +all environments share a large base of common configurations. This configuration +is put in files directly in the ``config/packages/`` directory. -.. code-block:: php +The location of these files is defined by the application's Kernel:: - // app/AppKernel.php + // src/Kernel.php // ... - - class AppKernel extends Kernel + class Kernel extends BaseKernel { // ... - public function registerContainerConfiguration(LoaderInterface $loader) + protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) { - $loader->load($this->getProjectDir().'/app/config/config_'.$this->getEnvironment().'.yml'); - } - } - -As you can see, when Symfony is loaded, it uses the given environment to -determine which configuration file to load. This accomplishes the goal of -multiple environments in an elegant, powerful and transparent way. - -Of course, in reality, each environment differs only somewhat from others. -Generally, all environments will share a large base of common configuration. -Opening the ``config_dev.yml`` configuration file, you can see how this is -accomplished easily and transparently: - -.. configuration-block:: - - .. code-block:: yaml - - imports: - - { resource: config.yml } - - # ... - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - $loader->import('config.php'); - - // ... - -To share common configuration, each environment's configuration file -simply first imports from a central configuration file (``config.yml``). -The remainder of the file can then deviate from the default configuration -by overriding individual parameters. For example, by default, the ``web_profiler`` -toolbar is disabled. However, in the ``dev`` environment, the toolbar is -activated by modifying the value of the ``toolbar`` option in the ``config_dev.yml`` -configuration file: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config_dev.yml - imports: - - { resource: config.yml } - - web_profiler: - toolbar: true - # ... - - .. code-block:: xml - - - - - - - - + // ... + $confDir = $this->getProjectDir().'/config'; - + // always load all files in /config/packages/ + $loader->load($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob'); - + // then, if available, load the files in the specific environment directory + if (is_dir($confDir.'/packages/'.$this->environment)) { + $loader->load($confDir.'/packages/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); + } - .. code-block:: php - - // app/config/config_dev.php - $loader->import('config.php'); + // load a special services.(yaml/xml/php) and, if available, services_ENVIRONMENT.(yaml/xml/php) file + $loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/services_'.$this->environment.self::CONFIG_EXTS, 'glob'); + } + } - $container->loadFromExtension('web_profiler', array( - 'toolbar' => true, +Take the framework package, installed by default, as an example: - // ... - )); +* Loaded in all environments, ``config/packages/framework.yaml`` configures the + framework with some ``secret`` setting; +* In the **prod** environment, nothing extra will be set as there is no + ``config/packages/prod/`` directory; +* The same applies to **dev**, as there is no + ``config/packages/framework.yaml``. There are however other packages (e.g. + ``routing.yaml``) with special dev settings; +* At last, during the **test** environment, the framework's test features are + enabled in ``config/packages/test/framework.yaml``. .. index:: single: Environments; Executing different environments @@ -149,77 +79,77 @@ configuration file: Executing an Application in different Environments -------------------------------------------------- -To execute the application in each environment, load up the application using -either ``app.php`` (for the ``prod`` environment) or ``app_dev.php`` -(for the ``dev`` environment) front controller: +To execute the application in each environment, change the ``APP_ENV`` +environment variable. During development, this is done in ``.env``: -.. code-block:: text +.. code-block:: bash + + # .env + APP_ENV=dev + + # or for test: + #APP_ENV=test - http://localhost/app.php -> *prod* environment - http://localhost/app_dev.php -> *dev* environment +Visit the ``http://localhost:8000/index.php`` page in your web browser to see +your application in the configured environment. -If you don't have *either* filename in your URL, then it's up to your web server -to decide *which* file to execute behind the scenes. If you're using the built-in -PHP web server, it knows to use the ``app_dev.php`` file. On production, you'll -:doc:`configure your web server ` to use ``app.php``. -Either way: *one of these two files is always executed*. +.. tip:: + + In production, it is recommended to configure the environment variables in + your :ref:`web server configuration `. .. note:: - The given URLs assume that your web server is configured to use the ``web/`` - directory of the application as its root. Read more in - :doc:`Installing Symfony `. + The given URLs assume that your web server is configured to use the ``public/`` + directory of the application as its root. Read more in :doc:`Installing Symfony `. -If you open up one of these files, you'll quickly see that the environment -used by each is explicitly set:: +If you open the file you just visited (``public/index.php``), you'll see that +the environment variable is passed to the kernel:: - // web/app.php - // ... + // public/index.php - $kernel = new AppKernel('prod', false); + // ... + $kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', $_SERVER['APP_DEBUG'] ?? false); // ... -The ``prod`` key specifies that this application will run in the ``prod`` -environment. A Symfony application can be executed in any environment by using -this code and changing the environment string. +You can also replace ``$_SERVER['APP_ENV'] ?? 'dev'`` by just ``'dev'`` to +always run the application in the dev environment, independent of the +``APP_ENV`` variable. .. note:: The ``test`` environment is used when writing functional tests and is - not accessible in the browser directly via a front controller. In other - words, unlike the other environments, there is no ``app_test.php`` front - controller file. + usually not accessed in the browser directly via a front controller. .. index:: single: Configuration; Debug mode .. sidebar:: *Debug* Mode - Important, but unrelated to the topic of *environments* is the ``false`` - argument as the second argument to the ``AppKernel`` constructor. This - specifies if the application should run in "debug mode". Regardless - of the environment, a Symfony application can be run with debug mode - set to ``true`` or ``false``. This affects many things in the application, - such as displaying stacktraces on error pages or if cache files are - dynamically rebuilt on each request. Though not a requirement, debug mode - is generally set to ``true`` for the ``dev`` and ``test`` environments and - ``false`` for the ``prod`` environment. + Important, but unrelated to the topic of *environments* is the second + argument to the ``Kernel`` constructor. This specifies if the application + should run in "debug mode". Regardless of the environment, a Symfony + application can be run with debug mode set to ``true`` or ``false`` + (respectively ``1`` or ``0`` for the ``APP_ENV`` variable defined in + ``.env``). This affects many things in the application, such as displaying + stacktraces on error pages or if cache files are dynamically rebuilt on + each request. Though not a requirement, debug mode is generally set to + ``true`` for the ``dev`` and ``test`` environments and ``false`` for the + ``prod`` environment. Internally, the value of the debug mode becomes the ``kernel.debug`` parameter used inside the :doc:`service container `. If you look inside the application configuration file, you'll see the - parameter used, for example, to turn logging on or off when using the - Doctrine DBAL: + parameter used, for example, to turn Twig's debug mode on: .. configuration-block:: .. code-block:: yaml - doctrine: - dbal: - logging: '%kernel.debug%' - # ... + # config/packages/twig.yaml + twig: + debug: '%kernel.debug%' .. code-block:: xml @@ -229,20 +159,17 @@ this code and changing the environment string. xmlns:doctrine="http://symfony.com/schema/dic/doctrine" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd - http://symfony.com/schema/dic/doctrine - http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd"> + http://symfony.com/schema/dic/twig + http://symfony.com/schema/dic/twig/twig-1.0.xsd"> - + .. code-block:: php - $container->loadFromExtension('doctrine', array( - 'dbal' => array( - 'logging' => '%kernel.debug%', - // ... - ), + $container->loadFromExtension('twig', array( + 'debug' => '%kernel.debug%', // ... )); @@ -265,15 +192,8 @@ behavior: $ php bin/console command_name --env=test --no-debug In addition to the ``--env`` and ``--no-debug`` options, the behavior of Symfony -commands can also be controlled with environment variables. The Symfony console -application checks the existence and value of these environment variables before -executing any command: - -``SYMFONY_ENV`` - Sets the execution environment of the command to the value of this variable - (``dev``, ``prod``, ``test``, etc.); -``SYMFONY_DEBUG`` - If ``0``, debug mode is disabled. Otherwise, debug mode is enabled. +commands can also be controlled with the same environment variables used by +``public/index.php``. These environment variables are very useful for production servers because they allow you to ensure that commands always run in the ``prod`` environment without @@ -285,10 +205,8 @@ having to add any command option. Creating a new Environment -------------------------- -By default, a Symfony application has three environments that handle most -cases. Of course, since an environment is nothing more than a string that -corresponds to a set of configuration, creating a new environment is quite -easy. +Since an environment is nothing more than a string that corresponds to a set of +configuration, creating a new environment is quite easy. Suppose, for example, that before deployment, you need to benchmark your application. One way to benchmark the application is to use near-production @@ -296,22 +214,20 @@ settings, but with Symfony's ``web_profiler`` enabled. This allows Symfony to record information about your application while benchmarking. The best way to accomplish this is via a new environment called, for example, -``benchmark``. Start by creating a new configuration file: +``benchmark``. Start by creating a new configuration directory and a +configuration file: .. configuration-block:: .. code-block:: yaml - # app/config/config_benchmark.yml - imports: - - { resource: config_prod.yml } - + # config/packages/benchmark/web_profiler.yaml framework: profiler: { only_exceptions: false } .. code-block:: xml - + - - - - @@ -333,50 +245,77 @@ The best way to accomplish this is via a new environment called, for example, .. code-block:: php - // app/config/config_benchmark.php - $loader->import('config_prod.php'); - + // config/packages/benchmark/web_profiler.php $container->loadFromExtension('framework', array( 'profiler' => array('only_exceptions' => false), )); -.. include:: /components/dependency_injection/_imports-parameters-note.rst.inc +And... you're finished! The application now supports a new environment called +``benchmark``. -And with this simple addition, the application now supports a new environment -called ``benchmark``. +Change the ``APP_ENV`` variable to ``benchmark`` to be able to access the new +environment through your browser: -This new configuration file imports the configuration from the ``prod`` environment -and modifies it. This guarantees that the new environment is identical to -the ``prod`` environment, except for any changes explicitly made here. +.. code-block:: bash -Because you'll want this environment to be accessible via a browser, you -should also create a front controller for it. Copy the ``web/app.php`` file -to ``web/app_benchmark.php`` and edit the environment to be ``benchmark``:: + # .env + APP_ENV=benchmark - // web/app_benchmark.php - // ... +.. sidebar:: Importing configuration - // change just this line - $kernel = new AppKernel('benchmark', false); + Besides loading files in the Kernel, you can also import files in the + configuration directly. For instance, to make sure the benchmark + environment is identical to the prod environment, you might want to load + all its configuration as well. - // ... + You can achieve this by using a special ``imports`` key: -The new environment is now accessible via:: + .. configuration-block: - http://localhost/app_benchmark.php + .. code-block:: yaml -.. note:: + # config/packages/benchmark/other.yaml + imports: + - { resource: '../prod/' } - Some environments, like the ``dev`` environment, are never meant to be - accessed on any deployed server by the public. This is because - certain environments, for debugging purposes, may give too much information - about the application or underlying infrastructure. To be sure these environments - aren't accessible, the front controller is usually protected from external - IP addresses via the following code at the top of the controller:: + # other resources are possible as well, like importing other + # files or using globs: + #- { resource: '/etc/myapp/some_special_config.xml' } + #- { resource: '/etc/myapp/*.yaml' } - if (!in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))) { - die('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.'); - } + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/benchmark/other.php + $loader->import('../prod/'); + + // other resources are possible as well, like importing other + // files or using globs: + //$loader->import('/etc/myapp/some_special_config.yaml'); + //$loader->import('/etc/myapp/*.php'); .. index:: single: Environments; Cache directory @@ -388,7 +327,7 @@ Symfony takes advantage of caching in many ways: the application configuration, routing configuration, Twig templates and more are cached to PHP objects stored in files on the filesystem. -By default, these cached files are largely stored in the ``var/cache`` directory. +By default, these cached files are largely stored in the ``var/cache/`` directory. However, each environment caches its own set of files: .. code-block:: text @@ -402,8 +341,8 @@ However, each environment caches its own set of files: Sometimes, when debugging, it may be helpful to inspect a cached file to understand how something is working. When doing so, remember to look in -the directory of the environment you're using (most commonly ``dev`` while -developing and debugging). While it can vary, the ``var/cache/dev`` directory +the directory of the environment you're using (most commonly ``dev/`` while +developing and debugging). While it can vary, the ``var/cache/dev/`` directory includes the following: ``appDevDebugProjectContainer.php`` diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 8788cb4c47c..a052cacd1e9 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -4,7 +4,7 @@ How to Set external Parameters in the Service Container ======================================================= -In the article :doc:`/configuration`, you learned how to manage your application +In :doc:`/configuration`, you learned how to manage your application configuration. At times, it may benefit your application to store certain credentials outside of your project code. Database configuration is one such example. The flexibility of the Symfony service container allows you to easily @@ -18,22 +18,30 @@ the variables you want to use enclosed between ``env()``. Their actual values will be resolved at runtime (once per request), so that dumped containers can be reconfigured dynamically even after being compiled. -For example, if you want to use the value of the ``DATABASE_HOST`` environment -variable in your service container configuration, you can reference it using -``%env(DATABASE_HOST)%`` in your configuration files: +For example, when installing the ``doctrine`` recipe, database configuration is +put in a ``DATABASE_URL`` environment variable: + +.. code-block:: bash + + # .env + DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" + +This variable is referenced in the service container configuration using +``%env(DATABASE_HOST)%``: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/doctrine.yaml doctrine: dbal: - host: '%env(DATABASE_HOST)%' + url: '%env(DATABASE_URL)%' + # ... .. code-block:: xml - + @@ -53,10 +61,10 @@ variable in your service container configuration, you can reference it using .. code-block:: php - // app/config/config.php + // config/packages/doctrine.php $container->loadFromExtension('doctrine', array( 'dbal' => array( - 'host' => '%env(DATABASE_HOST)%', + 'url' => '%env(DATABASE_URL)%', ) )); @@ -67,34 +75,37 @@ will be used whenever the corresponding environment variable is *not* found: .. code-block:: yaml - # app/config/parameters.yml + # config/services.yaml parameters: - database_host: '%env(DATABASE_HOST)%' env(DATABASE_HOST): localhost .. code-block:: xml - + - %env(DATABASE_HOST)% localhost .. code-block:: php - // app/config/parameters.php - $container->setParameter('database_host', '%env(DATABASE_HOST)%'); + // config/services.php $container->setParameter('env(DATABASE_HOST)', 'localhost'); -Setting environment variables is generally done at the web server level or in the -terminal. If you're using Apache, Nginx or just the console, you can use e.g. one -of the following: +.. _configuration-env-var-in-prod: + +Configuring Environment Variables in Production +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +During development, you'll use the ``.env`` file to configure your environment +variables. On your production server, it is recommended to configure these at +the web server level. If you're using Apache or Nginx, you can use e.g. one of +the following: .. configuration-block:: @@ -103,19 +114,12 @@ of the following: # ... - SetEnv DATABASE_USER user - SetEnv DATABASE_PASSWORD secret + SetEnv DATABASE_URL "mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" .. code-block:: nginx - fastcgi_param DATABASE_USER user; - fastcgi_param DATABASE_PASSWORD secret; - - .. code-block:: terminal - - $ export DATABASE_USER=user - $ export DATABASE_PASSWORD=secret + fastcgi_param DATABASE_URL "mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7"; .. tip:: @@ -135,53 +139,19 @@ See :ref:`component-di-parameters-constants` for more details. Miscellaneous Configuration --------------------------- -The ``imports`` directive can be used to pull in parameters stored elsewhere. -Importing a PHP file gives you the flexibility to add whatever is needed -in the container. The following imports a file named ``parameters.php``. - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - imports: - - { resource: parameters.php } - - .. code-block:: xml - - - - - - - - +You can mix whatever configuration format you like (YAML, XML and PHP) in +``config/packages/``. Importing a PHP file gives you the flexibility to add +whatever is needed in the container. For instance, you can create a +``drupal.php`` file in which you set a database URL based on Drupal's database +configuration:: - + // config/packages/drupal.php - .. code-block:: php - - // app/config/config.php - $loader->import('parameters.php'); - -.. note:: - - A resource file can be one of many types. PHP, XML, YAML, INI, and - closure resources are all supported by the ``imports`` directive. - -In ``parameters.php``, tell the service container the parameters that you wish -to set. This is useful when important configuration is in a non-standard -format. The example below includes a Drupal database configuration in -the Symfony service container. - -.. code-block:: php - - // app/config/parameters.php + // import Drupal's configuration include_once('/path/to/drupal/sites/default/settings.php'); - $container->setParameter('drupal.database.url', $db_url); + + // set a app.database_url parameter + $container->setParameter('app.database_url', $db_url); .. _`SetEnv`: http://httpd.apache.org/docs/current/env.html .. _`fastcgi_param`: http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_param diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index 54cab74072a..a5160a47108 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -27,16 +27,16 @@ three parts that work together: The Front Controller -------------------- -The `front controller`_ is a well-known design pattern; it is a section of -code that *all* requests served by an application run through. +The `front controller`_ is a design pattern; it is a section of code that *all* +requests served by an application run through. -In the `Symfony Standard Edition`_, this role is taken by the `index.php`_ file -in the ``public/`` directory. This is the very first PHP script executed when a +In the Symfony Skeleton, this role is taken by the `index.php`_ file in the +``public/`` directory. This is the very first PHP script executed when a request is processed. The main purpose of the front controller is to create an instance of the -``AppKernel`` (more on that in a second), make it handle the request -and return the resulting response to the browser. +``Kernel`` (more on that in a second), make it handle the request and return +the resulting response to the browser. Because every request is routed through it, the front controller can be used to perform global initialization prior to setting up the kernel or @@ -47,33 +47,23 @@ to `decorate`_ the kernel with additional features. Examples include: :ref:`AppCache `; * Enabling the :doc:`Debug Component `. -The front controller can be chosen by requesting URLs like: +You can choose the front controller that's used by adding it in the URL, like: .. code-block:: text - http://localhost/app_dev.php/some/path/... + http://localhost/index.php/some/path/... As you can see, this URL contains the PHP script to be used as the front -controller. You can use that to easily switch the front controller or use -a custom one by placing it in the ``web/`` directory (e.g. ``app_cache.php``). +controller. You can use that to easily switch to a custom made front controller +that is located in the ``public/`` directory or e.g. access the ``check.php`` +file. -When using Apache and the `RewriteRule shipped with the Symfony Standard Edition`_, -you can omit the filename from the URL and the RewriteRule will use ``app.php`` -as the default one. +.. seealso:: -.. note:: - - Pretty much every other web server should be able to achieve a - behavior similar to that of the RewriteRule described above. - Check your server documentation for details or see + You almost never want to show the front controller in the URL. This is + achieved by configuring the web server, as shown in :doc:`/setup/web_server_configuration`. -.. note:: - - Make sure you appropriately secure your front controllers against unauthorized - access. For example, you don't want to make a debugging environment - available to arbitrary users in your production environment. - Technically, the `bin/console`_ script used when running Symfony on the command line is also a front controller, only that is not used for web, but for command line requests. @@ -164,5 +154,4 @@ way of loading your configuration. .. _bin/console: https://github.com/symfony/symfony-standard/blob/master/bin/console .. _AppKernel: https://github.com/symfony/symfony-standard/blob/master/app/AppKernel.php .. _decorate: https://en.wikipedia.org/wiki/Decorator_pattern -.. _RewriteRule shipped with the Symfony Standard Edition: https://github.com/symfony/symfony-standard/blob/master/web/.htaccess .. _template methods: https://en.wikipedia.org/wiki/Template_method_pattern From 912d94a9a19852ad9592499e735be3fab538add1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 15 Nov 2017 08:42:04 +0100 Subject: [PATCH 0066/2437] Minor change --- best_practices/business-logic.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/best_practices/business-logic.rst b/best_practices/business-logic.rst index ce12825a4e9..4798e37066b 100644 --- a/best_practices/business-logic.rst +++ b/best_practices/business-logic.rst @@ -125,7 +125,7 @@ library or strategy you want for this. In practice, many Symfony applications rely on the independent `Doctrine project`_ to define their model using entities and repositories. Just like with business logic, we recommend storing Doctrine entities in the -``src/`` directory. +``src/Entity/`` directory. The three entities defined by our sample blog application are a good example: From 5088d0ea51fb6ae5795c966c51efb6bd98b6896b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 15 Nov 2017 09:39:14 +0100 Subject: [PATCH 0067/2437] Lots of fixes --- workflow/state-machines.rst | 10 ++++++++-- workflow/usage.rst | 7 ++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/workflow/state-machines.rst b/workflow/state-machines.rst index 0f9c70cdd07..a076dce55f0 100644 --- a/workflow/state-machines.rst +++ b/workflow/state-machines.rst @@ -198,11 +198,17 @@ you can get this state machine by injecting the Workflow registry service:: class SomeService { - private $stateMachine; + private $workflows; public function __constructor(Registry $workflows) { - $this->stateMachine = $workflows->get('pull_request'); + $this->workflows = $workflows; + } + + public function someMethod() + { + $stateMachine = $this->workflows->get('pull_request'); + // ... } // ... diff --git a/workflow/usage.rst b/workflow/usage.rst index c68528a5884..eff574a43cc 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -170,12 +170,13 @@ you can get the workflow by injecting the Workflow registry service:: // ... use Symfony\Component\Workflow\Registry; + use App\Entity\BlogPost; class BlogController { public function edit(Registry $workflows) { - $post = new \App\Entity\BlogPost(); + $post = new BlogPost(); $workflow = $workflows->get($post); // if there are multiple workflows for the same class, @@ -192,7 +193,7 @@ you can get the workflow by injecting the Workflow registry service:: // ... } - // See all the available transition for the post in the current state + // See all the available transitions for the post in the current state $transitions = $workflow->getEnabledTransitions($post); } } @@ -272,7 +273,7 @@ order: * ``workflow.[workflow name].announce`` * ``workflow.[workflow name].announce.[transition name]`` -Here is an example how to enable logging for every time the ``blog_publishing`` +Here is an example of how to enable logging for every time the ``blog_publishing`` workflow leaves a place:: use Psr\Log\LoggerInterface; From 8c540ce5515e159b58d41b550230f8f49d331876 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 15 Nov 2017 10:40:20 +0100 Subject: [PATCH 0068/2437] Removed an unneeded comment (Flex now includes Console by default) --- workflow/dumping-workflows.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow/dumping-workflows.rst b/workflow/dumping-workflows.rst index fd323f7efeb..f6ab01c4d0c 100644 --- a/workflow/dumping-workflows.rst +++ b/workflow/dumping-workflows.rst @@ -20,8 +20,8 @@ The result will look like this: .. image:: /_images/components/workflow/blogpost.png -Inside a Symfony application with both Workflow and Console support, you can -dump the dot file with the ``workflow:dump`` command: +Inside a Symfony application, you can dump the dot file with the +``workflow:dump`` command: .. code-block:: terminal From b95af09b01229c9356232a85339543af3d80c654 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 15 Nov 2017 11:53:11 +0100 Subject: [PATCH 0069/2437] Updated controller/* articles to Symfony 4 --- controller/argument_value_resolver.rst | 7 +-- controller/csrf_token_validation.rst | 2 +- controller/error_pages.rst | 60 ++++++++++++-------------- controller/forwarding.rst | 8 ++-- controller/service.rst | 18 ++++---- controller/soap_web_service.rst | 8 ++-- controller/upload_file.rst | 24 ++++++----- 7 files changed, 58 insertions(+), 69 deletions(-) diff --git a/controller/argument_value_resolver.rst b/controller/argument_value_resolver.rst index 8ca6af7179d..811d226bc64 100644 --- a/controller/argument_value_resolver.rst +++ b/controller/argument_value_resolver.rst @@ -42,11 +42,6 @@ Symfony ships with five value resolvers in the HttpKernel component: argument list. When the action is called, the last (variadic) argument will contain all the values of this array. -.. note:: - - Prior to Symfony 3.1, this logic was resolved within the ``ControllerResolver``. - The old functionality is rewritten to the aforementioned value resolvers. - Adding a Custom Value Resolver ------------------------------ @@ -62,7 +57,7 @@ controller:: class UserController { - public function indexAction(User $user) + public function index(User $user) { return new Response('Hello '.$user->getUsername().'!'); } diff --git a/controller/csrf_token_validation.rst b/controller/csrf_token_validation.rst index 8775362a63d..e9db3189a56 100644 --- a/controller/csrf_token_validation.rst +++ b/controller/csrf_token_validation.rst @@ -9,7 +9,7 @@ want to use the Symfony Form component. If, for example, you are implementing a DELETE action, you can use the :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::isCsrfTokenValid` method to check the validity of a CSRF token:: - public function deleteAction() + public function delete() { if ($this->isCsrfTokenValid('token_id', $submittedToken)) { // ... do something, like deleting an object diff --git a/controller/error_pages.rst b/controller/error_pages.rst index f247c168d01..c8bcc65b6b2 100644 --- a/controller/error_pages.rst +++ b/controller/error_pages.rst @@ -67,33 +67,32 @@ logic to determine the template filename: To override these templates, simply rely on the standard Symfony method for :doc:`overriding templates that live inside a bundle `: -put them in the ``app/Resources/TwigBundle/views/Exception/`` directory. +put them in the ``templates/bundles/TwigBundle/Exception/`` directory. A typical project that returns HTML and JSON pages, might look like this: .. code-block:: text - app/ - └─ Resources/ + templates/ + └─ bundles/ └─ TwigBundle/ - └─ views/ - └─ Exception/ - ├─ error404.html.twig - ├─ error403.html.twig - ├─ error.html.twig # All other HTML errors (including 500) - ├─ error404.json.twig - ├─ error403.json.twig - └─ error.json.twig # All other JSON errors (including 500) + └─ Exception/ + ├─ error404.html.twig + ├─ error403.html.twig + ├─ error.html.twig # All other HTML errors (including 500) + ├─ error404.json.twig + ├─ error403.json.twig + └─ error.json.twig # All other JSON errors (including 500) Example 404 Error Template -------------------------- To override the 404 error template for HTML pages, create a new -``error404.html.twig`` template located at ``app/Resources/TwigBundle/views/Exception/``: +``error404.html.twig`` template located at ``templates/bundles/TwigBundle/Exception/``: .. code-block:: html+twig - {# app/Resources/TwigBundle/views/Exception/error404.html.twig #} + {# templates/bundles/TwigBundle/Exception/error404.html.twig #} {% extends 'base.html.twig' %} {% block body %} @@ -139,21 +138,22 @@ what it looks like and debug it? Fortunately, the default ``ExceptionController`` allows you to preview your *error* pages during development. -To use this feature, you need to have a definition in your -``routing_dev.yml`` file like so: +To use this feature, you need to load some special routes provided by TwigBundle +(if the application uses :doc:`Symfony Flex ` they are loaded +automatically when installing Twig support): .. configuration-block:: .. code-block:: yaml - # app/config/routing_dev.yml + # config/routes/dev/twig.yaml _errors: - resource: "@TwigBundle/Resources/config/routing/errors.xml" + resource: '@TwigBundle/Resources/config/routing/errors.xml' prefix: /_error .. code-block:: xml - + + - AppBundle:Exception:showException + App\Controller\ExceptionController::showException .. code-block:: php - // app/config/config.php + // config/packages/twig.php $container->loadFromExtension('twig', array( - 'exception_controller' => 'AppBundle:Exception:showException', + 'exception_controller' => 'App\Controller\ExceptionController::showException', // ... )); diff --git a/controller/forwarding.rst b/controller/forwarding.rst index df8a4c685b1..47ec70e9425 100644 --- a/controller/forwarding.rst +++ b/controller/forwarding.rst @@ -11,9 +11,9 @@ sub-request and calls the defined controller. The ``forward()`` method returns the :class:`Symfony\\Component\\HttpFoundation\\Response` object that is returned from *that* controller:: - public function indexAction($name) + public function index($name) { - $response = $this->forward('AppBundle:Something:fancy', array( + $response = $this->forward('App\Controller\OtherController::fancy', array( 'name' => $name, 'color' => 'green', )); @@ -26,10 +26,10 @@ from *that* controller:: The array passed to the method becomes the arguments for the resulting controller. The target controller method might look something like this:: - public function fancyAction($name, $color) + public function fancy($name, $color) { // ... create and return a Response object } Just like when creating a controller for a route, the order of the arguments -of ``fancyAction()`` doesn't matter: the matching is done by name. +of the ``fancy()`` method doesn't matter: the matching is done by name. diff --git a/controller/service.rst b/controller/service.rst index cc2c6450a73..6fffddd1711 100644 --- a/controller/service.rst +++ b/controller/service.rst @@ -15,12 +15,12 @@ Referencing your Service from Routing Registering your controller as a service is great, but you also need to make sure that your routing references the service properly, so that Symfony knows to use it. -If the service id is the fully-qualified class name (FQCN) of your controller, you're -done! You can use the normal ``AppBundle:Hello:index`` syntax in your routing and -it will find your service. +If the service id is the fully-qualified class name (FQCN) of your controller, +you're done! You can use the normal ``App\Controller\HelloController::index`` +syntax in your routing and it will find your service. -But, if your service has a different id, you can use a special ``SERVICEID:METHOD`` -syntax: +But, if your service has a different id, you can use a special +``service_id:method_name`` syntax: .. configuration-block:: @@ -31,8 +31,6 @@ syntax: // You need to use Sensio's annotation to specify a service id use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; // ... - - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; /** * @Route(service="app.hello_controller") @@ -73,8 +71,8 @@ syntax: .. note:: - You cannot drop the ``Action`` part of the method name when using the - single colon notation. + When using the ``service_id:method_name`` syntax, the method name must + end with the ``Action`` suffix. .. _controller-service-invoke: @@ -114,7 +112,7 @@ service and use it directly:: $this->twig = $twig; } - public function indexAction($name) + public function index($name) { $content = $this->twig->render( 'hello/index.html.twig', diff --git a/controller/soap_web_service.rst b/controller/soap_web_service.rst index d3375bcd37e..d1b9ec72c5b 100644 --- a/controller/soap_web_service.rst +++ b/controller/soap_web_service.rst @@ -54,7 +54,7 @@ the :ref:`default services configuration setObject($helloService); @@ -96,8 +96,8 @@ into the content of the Response and clear the output buffer. Finally, you're ready to return the ``Response``. Below is an example calling the service using a `NuSOAP`_ client. This example -assumes that the ``indexAction()`` in the controller above is accessible via the -route ``/soap``:: +assumes that the ``index()`` method in the controller above is accessible via +the route ``/soap``:: $client = new \Soapclient('http://example.com/index.php/soap?wsdl'); diff --git a/controller/upload_file.rst b/controller/upload_file.rst index 8fde4da9b56..dc207c31e03 100644 --- a/controller/upload_file.rst +++ b/controller/upload_file.rst @@ -108,7 +108,7 @@ to :doc:`customize form rendering `): Finally, you need to update the code of the controller that handles the form:: // src/Controller/ProductController.php - namespace App\ProductController; + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; @@ -121,7 +121,7 @@ Finally, you need to update the code of the controller that handles the form:: /** * @Route("/product/new", name="app_product_new") */ - public function newAction(Request $request) + public function new(Request $request) { $product = new Product(); $form = $this->createForm(ProductType::class, $product); @@ -161,7 +161,7 @@ controller to specify the directory in which the brochures should be stored: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml # ... parameters: @@ -294,7 +294,7 @@ Now you're ready to use this service in the controller:: use App\Service\FileUploader; // ... - public function newAction(Request $request, FileUploader $fileUploader) + public function new(Request $request, FileUploader $fileUploader) { // ... @@ -393,14 +393,16 @@ Now, register this class as a Doctrine listener: xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> - - - + + + + - - - - + + + + + .. code-block:: php From bcdeeac6eabed64c28342ccaef37adb5c3e3606f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 15 Nov 2017 13:22:59 +0100 Subject: [PATCH 0070/2437] Updated the email/* articles --- email/cloud.rst | 88 ++++------------------------------- email/dev_environment.rst | 47 ++++++++----------- email/gmail.rst | 97 ++------------------------------------- email/spool.rst | 36 +++++++-------- email/testing.rst | 4 +- 5 files changed, 55 insertions(+), 217 deletions(-) diff --git a/email/cloud.rst b/email/cloud.rst index d7ddbd33f3b..3166405141f 100644 --- a/email/cloud.rst +++ b/email/cloud.rst @@ -18,86 +18,18 @@ This article shows how easy it is to integrate .. note:: You can use the same technique for other mail services, as most of the - time there is nothing more to it than configuring an SMTP endpoint for - Swift Mailer. - -In the Symfony configuration, change the Swift Mailer settings ``transport``, -``host``, ``port`` and ``encryption`` according to the information provided in -the `SES console`_. Create your individual SMTP credentials in the SES console -and complete the configuration with the provided ``username`` and ``password``: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - swiftmailer: - transport: smtp - host: email-smtp.us-east-1.amazonaws.com - port: 587 # different ports are available, see SES console - encryption: tls # TLS encryption is required - username: AWS_SES_SMTP_USERNAME # to be created in the SES console - password: AWS_SES_SMTP_PASSWORD # to be created in the SES console - - .. code-block:: xml - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('swiftmailer', array( - 'transport' => 'smtp', - 'host' => 'email-smtp.us-east-1.amazonaws.com', - 'port' => 587, - 'encryption' => 'tls', - 'username' => 'AWS_SES_SMTP_USERNAME', - 'password' => 'AWS_SES_SMTP_PASSWORD', - )); - -The ``port`` and ``encryption`` keys are not present in the Symfony Standard -Edition configuration by default, but you can simply add them as needed. + time there is nothing more to it than configuring an SMTP endpoint. -And that's it, you're ready to start sending emails through the cloud! +Symfony's mailer uses the ``MAILER_URL`` environment variable to store the +SMTP connection parameters, including the security credentials. Get those +parameters from the `SES console`_ and update the value of ``MAILER_URL`` in +the ``.env`` file: + +.. code-block:: bash -.. tip:: - - If you are using the Symfony Standard Edition, configure the parameters in - ``parameters.yml`` and use them in your configuration files. This allows - for different Swift Mailer configurations for each installation of your - application. For instance, use Gmail during development and the cloud in - production. - - .. code-block:: yaml - - # app/config/parameters.yml - parameters: - # ... - mailer_transport: smtp - mailer_host: email-smtp.us-east-1.amazonaws.com - mailer_port: 587 # different ports are available, see SES console - mailer_encryption: tls # TLS encryption is required - mailer_user: AWS_SES_SMTP_USERNAME # to be created in the SES console - mailer_password: AWS_SES_SMTP_PASSWORD # to be created in the SES console + MAILER_URL=smtp://email-smtp.us-east-1.amazonaws.com:587?encryption=tls&username=YOUR_SES_USERNAME&password=YOUR_SES_PASSWORD + +And that's it, you're ready to start sending emails through the cloud! .. note:: diff --git a/email/dev_environment.rst b/email/dev_environment.rst index ebb0a46024f..ce659a533aa 100644 --- a/email/dev_environment.rst +++ b/email/dev_environment.rst @@ -6,7 +6,7 @@ How to Work with Emails during Development When developing an application which sends email, you will often not want to actually send the email to the specified recipient during -development. If you are using the SwiftmailerBundle with Symfony, you +development. If you are using the default Symfony mailer, you can easily achieve this through configuration settings without having to make any changes to your application's code at all. There are two main choices when it comes to handling email during development: (a) disabling the @@ -16,23 +16,21 @@ address (with optional exceptions). Disabling Sending ----------------- -You can disable sending email by setting the ``disable_delivery`` option -to ``true``. This is the default in the ``test`` environment in the Standard -distribution. If you do this in the ``test`` specific config then email -will not be sent when you run tests, but will continue to be sent in the -``prod`` and ``dev`` environments: +You can disable sending email by setting the ``disable_delivery`` option to +``true``, which is the default value used by Symfony in the ``test`` environment +(email messages will continue to be sent in the other environments): .. configuration-block:: .. code-block:: yaml - # app/config/config_test.yml + # config/packages/test/swiftmailer.yaml swiftmailer: disable_delivery: true .. code-block:: xml - + loadFromExtension('swiftmailer', array( 'disable_delivery' => "true", )); -If you'd also like to disable deliver in the ``dev`` environment, simply -add this same configuration to the ``config_dev.yml`` file. - .. _sending-to-a-specified-address: Sending to a Specified Address(es) @@ -67,13 +62,13 @@ via the ``delivery_addresses`` option: .. code-block:: yaml - # app/config/config_dev.yml + # config/packages/dev/swiftmailer.yaml swiftmailer: delivery_addresses: ['dev@example.com'] .. code-block:: xml - + loadFromExtension('swiftmailer', array( 'delivery_addresses' => array("dev@example.com"), )); -Now, suppose you're sending an email to ``recipient@example.com``. - -.. code-block:: php +Now, suppose you're sending an email to ``recipient@example.com`` in a controller:: - public function indexAction($name, \Swift_Mailer $mailer) + public function index($name, \Swift_Mailer $mailer) { $message = (new \Swift_Message('Hello Email')) ->setFrom('send@example.com') @@ -143,7 +136,7 @@ by adding the ``delivery_whitelist`` option: .. code-block:: yaml - # app/config/config_dev.yml + # config/packages/dev/swiftmailer.yaml swiftmailer: delivery_addresses: ['dev@example.com'] delivery_whitelist: @@ -154,7 +147,7 @@ by adding the ``delivery_whitelist`` option: .. code-block:: xml - + loadFromExtension('swiftmailer', array( 'delivery_addresses' => array("dev@example.com"), 'delivery_whitelist' => array( @@ -207,20 +200,20 @@ the web debug toolbar will not display an email icon or a report on the next page. Instead, you can set the ``intercept_redirects`` option to ``true`` in the -``config_dev.yml`` file, which will cause the redirect to stop and allow -you to open the report with details of the sent emails. +``dev`` environment, which will cause the redirect to stop and allow you to open +the report with details of the sent emails. .. configuration-block:: .. code-block:: yaml - # app/config/config_dev.yml + # config/packages/dev/swiftmailer.yaml web_profiler: intercept_redirects: true .. code-block:: xml - + loadFromExtension('web_profiler', array( 'intercept_redirects' => 'true', )); diff --git a/email/gmail.rst b/email/gmail.rst index e34604bae0a..a8d456edaa4 100644 --- a/email/gmail.rst +++ b/email/gmail.rst @@ -5,102 +5,15 @@ How to Use Gmail to Send Emails =============================== During development, instead of using a regular SMTP server to send emails, you -might find using Gmail easier and more practical. The SwiftmailerBundle makes +might find using Gmail easier and more practical. The Symfony mailer makes it really easy. -In the development configuration file, change the ``transport`` setting to -``gmail`` and set the ``username`` and ``password`` to the Google credentials: +In the ``.env`` file used in your development machine, change the ``MAILER_URL`` +environment variable to this: -.. configuration-block:: +.. code-block:: bash - .. code-block:: yaml - - # app/config/config_dev.yml - swiftmailer: - transport: gmail - username: your_gmail_username - password: your_gmail_password - - .. code-block:: xml - - - - - - - - - - .. code-block:: php - - // app/config/config_dev.php - $container->loadFromExtension('swiftmailer', array( - 'transport' => 'gmail', - 'username' => 'your_gmail_username', - 'password' => 'your_gmail_password', - )); - -.. tip:: - - It's more convenient to configure these options in the ``parameters.yml`` - file: - - .. code-block:: yaml - - # app/config/parameters.yml - parameters: - # ... - mailer_user: your_gmail_username - mailer_password: your_gmail_password - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/config_dev.yml - swiftmailer: - transport: gmail - username: '%mailer_user%' - password: '%mailer_password%' - - .. code-block:: xml - - - - - - - - - - .. code-block:: php - - // app/config/config_dev.php - $container->loadFromExtension('swiftmailer', array( - 'transport' => 'gmail', - 'username' => '%mailer_user%', - 'password' => '%mailer_password%', - )); + MAILER_URL=gmail://YOUR_GMAIL_USERNAME:YOUR_GMAIL_PASSWORD@localhost Redefining the Default Configuration Parameters ----------------------------------------------- diff --git a/email/spool.rst b/email/spool.rst index f7827bb8ff5..d8afa6ba88d 100644 --- a/email/spool.rst +++ b/email/spool.rst @@ -4,16 +4,16 @@ How to Spool Emails =================== -When you are using the SwiftmailerBundle to send an email from a Symfony -application, it will default to sending the email immediately. You may, however, -want to avoid the performance hit of the communication between Swift Mailer -and the email transport, which could cause the user to wait for the next -page to load while the email is sending. This can be avoided by choosing -to "spool" the emails instead of sending them directly. This means that Swift Mailer -does not attempt to send the email but instead saves the message to somewhere -such as a file. Another process can then read from the spool and take care -of sending the emails in the spool. Currently only spooling to file or memory is supported -by Swift Mailer. +The default behavior of the Symfony mailer is to send the email messages +immediately. You may, however, want to avoid the performance hit of the +communication to the email server, which could cause the user to wait for the +next page to load while the email is sending. This can be avoided by choosing to +"spool" the emails instead of sending them directly. + +This makes the mailer to not attempt to send the email message but instead save +it somewhere such as a file. Another process can then read from the spool and +take care of sending the emails in the spool. Currently only spooling to file or +memory is supported. Spool Using Memory ------------------ @@ -21,20 +21,20 @@ Spool Using Memory When you use spooling to store the emails to memory, they will get sent right before the kernel terminates. This means the email only gets sent if the whole request got executed without any unhandled exception or any errors. To configure -swiftmailer with the memory option, use the following configuration: +this spool, use the following configuration: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/swiftmailer.yaml swiftmailer: # ... spool: { type: memory } .. code-block:: xml - + loadFromExtension('swiftmailer', array( // ... 'spool' => array('type' => 'memory') @@ -71,7 +71,7 @@ In order to use the spool with files, use the following configuration: .. code-block:: yaml - # app/config/config.yml + # config/packages/swiftmailer.yaml swiftmailer: # ... spool: @@ -80,7 +80,7 @@ In order to use the spool with files, use the following configuration: .. code-block:: xml - + loadFromExtension('swiftmailer', array( // ... @@ -117,7 +117,7 @@ In order to use the spool with files, use the following configuration: .. code-block:: yaml - path: '%kernel.project_dir%/app/spool' + path: '%kernel.project_dir%/var/spool' Now, when your app sends an email, it will not actually be sent but instead added to the spool. Sending the messages from the spool is done separately. diff --git a/email/testing.rst b/email/testing.rst index 9e9597f5e58..477db8f5474 100644 --- a/email/testing.rst +++ b/email/testing.rst @@ -10,9 +10,9 @@ SwiftmailerBundle, which leverages the power of the `Swift Mailer`_ library. To functionally test that an email was sent, and even assert the email subject, content or any other headers, you can use :doc:`the Symfony Profiler `. -Start with an easy controller action that sends an email:: +Start with a simple controller action that sends an email:: - public function sendEmailAction($name, \Swift_Mailer $mailer) + public function sendEmail($name, \Swift_Mailer $mailer) { $message = (new \Swift_Message('Hello Email')) ->setFrom('send@example.com') From 419353b2541f506a3820e06d3586618a1fa4eb01 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 15 Nov 2017 13:31:36 +0100 Subject: [PATCH 0071/2437] Used the modern "controller" key in YAML routes --- routing/conditions.rst | 6 ++-- routing/extra_information.rst | 8 ++--- routing/hostname_pattern.rst | 40 ++++++++++++------------ routing/optional_placeholders.rst | 13 ++++---- routing/redirect_in_config.rst | 4 +-- routing/redirect_trailing_slash.rst | 2 +- routing/requirements.rst | 19 +++++------ routing/scheme.rst | 6 ++-- routing/service_container_parameters.rst | 8 ++--- routing/slash_in_parameter.rst | 4 +-- 10 files changed, 56 insertions(+), 54 deletions(-) diff --git a/routing/conditions.rst b/routing/conditions.rst index b9658d6388a..735effa4459 100644 --- a/routing/conditions.rst +++ b/routing/conditions.rst @@ -14,9 +14,9 @@ define arbitrary matching logic, use the ``conditions`` routing option: # config/routes.yaml contact: - path: /contact - defaults: { _controller: 'App\Controller\DefaultController::contact' } - condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'" + path: /contact + controller: 'App\Controller\DefaultController::contact' + condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'" .. code-block:: xml diff --git a/routing/extra_information.rst b/routing/extra_information.rst index 6feb31e195e..85d09f22777 100644 --- a/routing/extra_information.rst +++ b/routing/extra_information.rst @@ -15,11 +15,11 @@ to your controller, and as attributes of the ``Request`` object: # config/routes.yaml blog: - path: /blog/{page} + path: /blog/{page} + controller: App\Controller\BlogController::index defaults: - _controller: App\Controller\BlogController::index - page: 1 - title: "Hello world!" + page: 1 + title: "Hello world!" .. code-block:: xml diff --git a/routing/hostname_pattern.rst b/routing/hostname_pattern.rst index 66fd98ff3aa..a1086c1a3b6 100644 --- a/routing/hostname_pattern.rst +++ b/routing/hostname_pattern.rst @@ -39,13 +39,13 @@ You can also match on the HTTP *host* of the incoming request. # config/routes.yaml mobile_homepage: - path: / - host: m.example.com - defaults: { _controller: App\Controller\MainController::mobileHomepage } + path: / + host: m.example.com + controller: App\Controller\MainController::mobileHomepage homepage: - path: / - defaults: { _controller: App\Controller\MainController::homepage } + path: / + controller: App\Controller\MainController::homepage .. code-block:: xml @@ -124,13 +124,13 @@ you can use placeholders in your hostname: # config/routes.yaml projects_homepage: - path: / - host: "{project_name}.example.com" - defaults: { _controller: App\Controller\MainController::projectsHomepage } + path: / + host: "{project_name}.example.com" + controller: App\Controller\MainController::projectsHomepage homepage: - path: / - defaults: { _controller: App\Controller\MainController::homepage } + path: / + controller: App\Controller\MainController::homepage .. code-block:: xml @@ -210,17 +210,17 @@ instance, if you want to match both ``m.example.com`` and # config/routes.yaml mobile_homepage: - path: / - host: "{subdomain}.example.com" + path: / + host: "{subdomain}.example.com" + controller: App\Controller\MainController::mobileHomepage defaults: - _controller: App\Controller\MainController::mobileHomepage subdomain: m requirements: subdomain: m|mobile homepage: - path: / - defaults: { _controller: App\Controller\MainController::homepage } + path: / + controller: App\Controller\MainController::homepage .. code-block:: xml @@ -306,17 +306,17 @@ instance, if you want to match both ``m.example.com`` and # config/routes.yaml mobile_homepage: - path: / - host: "m.{domain}" + path: / + host: "m.{domain}" + controller: App\Controller\MainController::mobileHomepage defaults: - _controller: App\Controller\MainController::mobileHomepage domain: '%domain%' requirements: domain: '%domain%' homepage: - path: / - defaults: { _controller: App\Controller\MainController::homepage } + path: / + controller: App\Controller\MainController::homepage .. code-block:: xml diff --git a/routing/optional_placeholders.rst b/routing/optional_placeholders.rst index 7c3c4288c49..e34bad57989 100644 --- a/routing/optional_placeholders.rst +++ b/routing/optional_placeholders.rst @@ -31,8 +31,8 @@ the available blog posts for this imaginary blog application: # config/routes.yaml blog: - path: /blog - defaults: { _controller: App\Controller\BlogController::index } + path: /blog + controller: App\Controller\BlogController::index .. code-block:: xml @@ -86,8 +86,8 @@ entries? Update the route to have a new ``{page}`` placeholder: # config/routes.yaml blog: - path: /blog/{page} - defaults: { _controller: App\Controller\BlogController::index } + path: /blog/{page} + controller: App\Controller\BlogController::index .. code-block:: xml @@ -146,8 +146,9 @@ This is done by including it in the ``defaults`` collection: # config/routes.yaml blog: - path: /blog/{page} - defaults: { _controller: App\Controller\BlogController::index, page: 1 } + path: /blog/{page} + controller: App\Controller\BlogController::index + defaults: { page: 1 } .. code-block:: xml diff --git a/routing/redirect_in_config.rst b/routing/redirect_in_config.rst index c6cbcadef44..89864c4c06c 100644 --- a/routing/redirect_in_config.rst +++ b/routing/redirect_in_config.rst @@ -35,8 +35,8 @@ action to redirect to this new url: # redirecting the homepage homepage: path: / + controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction defaults: - _controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::urlRedirectAction path: /app permanent: true @@ -110,8 +110,8 @@ action: admin: path: /wp-admin + controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction defaults: - _controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction route: sonata_admin_dashboard permanent: true diff --git a/routing/redirect_trailing_slash.rst b/routing/redirect_trailing_slash.rst index 720bd019890..99a9552ac0c 100644 --- a/routing/redirect_trailing_slash.rst +++ b/routing/redirect_trailing_slash.rst @@ -63,7 +63,7 @@ system, as explained below: # config/routes.yaml remove_trailing_slash: path: /{url} - defaults: { _controller: App\Controller\RedirectingController::removeTrailingSlash } + controller: App\Controller\RedirectingController::removeTrailingSlash requirements: url: .*/$ methods: [GET] diff --git a/routing/requirements.rst b/routing/requirements.rst index 92deb348c7a..7b75bd723a1 100644 --- a/routing/requirements.rst +++ b/routing/requirements.rst @@ -34,7 +34,7 @@ a routing ``{wildcard}`` to only match some regular expression: # config/routes.yaml blog_list: path: /blog/{page} - defaults: { _controller: App\Controller\BlogController::list } + controller: App\Controller\BlogController::list requirements: page: '\d+' @@ -110,8 +110,9 @@ URL: # config/routes.yaml homepage: - path: /{_locale} - defaults: { _controller: App\Controller\MainController::homepage, _locale: en } + path: /{_locale} + controller: App\Controller\MainController::homepage + defaults: { _locale: en } requirements: _locale: en|fr @@ -218,14 +219,14 @@ accomplished with the following route configuration: # config/routes.yaml api_post_show: - path: /api/posts/{id} - defaults: { _controller: App\Controller\BlogApiController::show } - methods: [GET, HEAD] + path: /api/posts/{id} + controller: App\Controller\BlogApiController::show + methods: [GET, HEAD] api_post_edit: - path: /api/posts/{id} - defaults: { _controller: App\Controller\BlogApiController::edit } - methods: [PUT] + path: /api/posts/{id} + controller: App\Controller\BlogApiController::edit + methods: [PUT] .. code-block:: xml diff --git a/routing/scheme.rst b/routing/scheme.rst index 8deff6c7cd9..2185db4463c 100644 --- a/routing/scheme.rst +++ b/routing/scheme.rst @@ -33,9 +33,9 @@ the URI scheme via schemes: # config/routes.yaml secure: - path: /secure - defaults: { _controller: App\Controller\MainController::secure } - schemes: [https] + path: /secure + controller: App\Controller\MainController::secure + schemes: [https] .. code-block:: xml diff --git a/routing/service_container_parameters.rst b/routing/service_container_parameters.rst index a5e2fcff816..ffc6cf205f6 100644 --- a/routing/service_container_parameters.rst +++ b/routing/service_container_parameters.rst @@ -20,8 +20,8 @@ inside your routing configuration: # config/routes.yaml contact: - path: /{_locale}/contact - defaults: { _controller: App\Controller\MainController::contact } + path: /{_locale}/contact + controller: App\Controller\MainController::contact requirements: _locale: '%app.locales%' @@ -94,8 +94,8 @@ path): # config/routes.yaml some_route: - path: /%app.route_prefix%/contact - defaults: { _controller: App\Controller\MainController::contact } + path: /%app.route_prefix%/contact + controller: App\Controller\MainController::contact .. code-block:: xml diff --git a/routing/slash_in_parameter.rst b/routing/slash_in_parameter.rst index 08371caec16..a97d33135ec 100644 --- a/routing/slash_in_parameter.rst +++ b/routing/slash_in_parameter.rst @@ -43,8 +43,8 @@ a more permissive regular expression for it: # config/routes.yaml share: - path: /share/{token} - defaults: { _controller: App\Controller\DefaultController::share } + path: /share/{token} + controller: App\Controller\DefaultController::share requirements: token: .+ From 8dc70ec3882aa4d6661da83b5456c3c714cb2908 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 15 Nov 2017 16:57:48 +0100 Subject: [PATCH 0072/2437] Updated the event dispatcher articles for Symfony 4 --- event_dispatcher.rst | 4 ++-- event_dispatcher/before_after_filters.rst | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/event_dispatcher.rst b/event_dispatcher.rst index 16130767d7c..49afea1508f 100644 --- a/event_dispatcher.rst +++ b/event_dispatcher.rst @@ -258,6 +258,6 @@ Learn more .. toctree:: :maxdepth: 1 - :glob: - event_dispatcher/* + event_dispatcher/before_after_filters + event_dispatcher/method_behavior diff --git a/event_dispatcher/before_after_filters.rst b/event_dispatcher/before_after_filters.rst index bb1d7f2f755..066b495e79c 100644 --- a/event_dispatcher/before_after_filters.rst +++ b/event_dispatcher/before_after_filters.rst @@ -33,14 +33,13 @@ token. Before Filters with the ``kernel.controller`` Event --------------------------------------------------- -First, store some basic token configuration using ``config.yml`` and the -parameters key: +First, define some token configuration as parameters: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml parameters: tokens: client1: pass1 @@ -48,7 +47,7 @@ parameters key: .. code-block:: xml - + setParameter('tokens', array( 'client1' => 'pass1', 'client2' => 'pass2', @@ -98,7 +97,7 @@ A controller that implements this interface simply looks like this:: class FooController extends Controller implements TokenAuthenticatedController { // An action that needs authentication - public function barAction() + public function bar() { // ... } From f9bb4122ce6031894924ba7d2a71a970cd5d82ca Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 16 Nov 2017 11:23:57 +0200 Subject: [PATCH 0073/2437] minor tweaks --- workflow/usage.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/workflow/usage.rst b/workflow/usage.rst index eff574a43cc..e7c1c4a4406 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -171,8 +171,9 @@ you can get the workflow by injecting the Workflow registry service:: // ... use Symfony\Component\Workflow\Registry; use App\Entity\BlogPost; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; - class BlogController + class BlogController extends Controller { public function edit(Registry $workflows) { @@ -190,7 +191,7 @@ you can get the workflow by injecting the Workflow registry service:: try { $workflow->apply($post, 'to_review'); } catch (LogicException $e) { - // ... + // ... if the transition is not allowed } // See all the available transitions for the post in the current state From 70dda7cffabd940d1d089a723672f377cb542424 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 16 Nov 2017 11:25:06 +0200 Subject: [PATCH 0074/2437] adding use --- workflow/usage.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow/usage.rst b/workflow/usage.rst index e7c1c4a4406..283b13df434 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -172,6 +172,7 @@ you can get the workflow by injecting the Workflow registry service:: use Symfony\Component\Workflow\Registry; use App\Entity\BlogPost; use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\Workflow\Exception\LogicException; class BlogController extends Controller { From 9e6d75d2f71aae78c02b6b9204d928fdc03425ca Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 16 Nov 2017 15:21:58 +0100 Subject: [PATCH 0075/2437] Fixes by reviewers --- bundles/best_practices.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bundles/best_practices.rst b/bundles/best_practices.rst index 553523aeacf..2e997beefe8 100644 --- a/bundles/best_practices.rst +++ b/bundles/best_practices.rst @@ -169,9 +169,12 @@ the ``Tests/`` directory. Tests should follow the following principles: Installation ------------ -Bundles must define a `Symfony Flex recipe`_ to automate their integration -in Symfony applications. If some initial configuration is needed to execute -the bundle, including some environment variables, provide them in the recipe. +Bundles should set ``"type": "symfony-bundle"`` in their ``composer.json`` file. +With this, :doc:`Symfony Flex ` will be able to automatically +enable your bundle when it's installed. + +If your bundle requires any setup (e.g. configuration, new files, changes to +`.gitignore`, etc), then you should create a `Symfony Flex recipe`_. Documentation ------------- @@ -260,7 +263,7 @@ following standardized instructions in your ``README.md`` file. Open a command console, enter your project directory and execute: - .. code-block:: terminal + .. code-block:: bash $ composer require From 9f32377f6add0e86bd15ad0b0f7d18428d7ae56d Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 16 Nov 2017 15:53:02 +0200 Subject: [PATCH 0076/2437] removing bundle removing article --- _build/redirection_map | 3 +- bundles.rst | 1 - bundles/index.rst | 1 - bundles/remove.rst | 96 ------------------------------------------ 4 files changed, 2 insertions(+), 99 deletions(-) delete mode 100644 bundles/remove.rst diff --git a/_build/redirection_map b/_build/redirection_map index e3c33de6f47..89d6cfaa510 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -100,7 +100,8 @@ /cookbook/bundles/installation /bundles /cookbook/bundles/override /bundles/override /cookbook/bundles/prepend_extension /bundles/prepend_extension -/cookbook/bundles/remove /bundles/remove +/cookbook/bundles/remove /bundles +/bundles/remove /bundles /cookbook/cache/form_csrf_caching /http_cache/form_csrf_caching /cookbook/cache/varnish /http_cache/varnish /cookbook/composer /setup/composer diff --git a/bundles.rst b/bundles.rst index d84d9d831dd..34487bca99b 100644 --- a/bundles.rst +++ b/bundles.rst @@ -44,7 +44,6 @@ file:: Learn more ---------- -* :doc:`/bundles/remove` * :doc:`/bundles/override` * :doc:`/bundles/best_practices` * :doc:`/bundles/configuration` diff --git a/bundles/index.rst b/bundles/index.rst index c6da8e269e2..78dd8c6d4fb 100644 --- a/bundles/index.rst +++ b/bundles/index.rst @@ -6,7 +6,6 @@ Bundles .. toctree:: :maxdepth: 2 - remove override inheritance best_practices diff --git a/bundles/remove.rst b/bundles/remove.rst deleted file mode 100644 index 525b3c7787a..00000000000 --- a/bundles/remove.rst +++ /dev/null @@ -1,96 +0,0 @@ -.. index:: - single: Bundle; Removing a bundle - -How to Remove a Bundle -====================== - -1. Unregister the Bundle in the ``AppKernel`` ---------------------------------------------- - -To disconnect the bundle from the framework, you should remove the bundle from -the ``AppKernel::registerBundles()`` method. The bundle will likely be found in -the ``$bundles`` array declaration or added to it in a later statement if the -bundle is only registered in the development environment:: - - // app/AppKernel.php - - // ... - class AppKernel extends Kernel - { - public function registerBundles() - { - $bundles = array( - new Acme\DemoBundle\AcmeDemoBundle(), - ); - - if (in_array($this->getEnvironment(), array('dev', 'test'))) { - // comment or remove this line: - // $bundles[] = new Acme\DemoBundle\AcmeDemoBundle(); - // ... - } - } - } - -2. Remove Bundle Configuration ------------------------------- - -Now that Symfony doesn't know about the bundle, you need to remove any -configuration and routing configuration inside the ``app/config`` directory -that refers to the bundle. - -2.1 Remove Bundle Routing -~~~~~~~~~~~~~~~~~~~~~~~~~ - -*Some* bundles require you to import routing configuration. Check for references -to the bundle in the routing configuration (inside ``config/routes/``). If you -find any references, remove them completely. - -2.2 Remove Bundle Configuration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Some bundles contain configuration in one of the ``app/config/config*.yml`` -files. Be sure to remove the related configuration from these files. You can -quickly spot bundle configuration by looking for an ``acme_demo`` (or whatever -the name of the bundle is, e.g. ``fos_user`` for the FOSUserBundle) string in -the configuration files. - -3. Remove the Bundle from the Filesystem ----------------------------------------- - -Now you have removed every reference to the bundle in your application, you -should remove the bundle from the filesystem. The bundle will be located in -`src/` for example the ``src/Acme/DemoBundle`` directory. You should remove this -directory, and any parent directories that are now empty (e.g. ``src/Acme/``). - -.. tip:: - - If you don't know the location of a bundle, you can use the - :method:`Symfony\\Component\\HttpKernel\\Bundle\\BundleInterface::getPath` method - to get the path of the bundle:: - - dump($this->container->get('kernel')->getBundle('AcmeDemoBundle')->getPath()); - die(); - -3.1 Remove Bundle Assets -~~~~~~~~~~~~~~~~~~~~~~~~ - -Remove the assets of the bundle in the public/ directory (e.g. -``public/bundles/acmedemo`` for the AcmeDemoBundle). - -4. Remove Integration in other Bundles --------------------------------------- - -Some bundles rely on other bundles, if you remove one of the two, the other -will probably not work. Be sure that no other bundles, third party or self-made, -rely on the bundle you are about to remove. - -.. tip:: - - If one bundle relies on another, in most cases it means that it uses - some services from the bundle. Searching for the bundle alias string may - help you spot them (e.g. ``acme_demo`` for bundles depending on AcmeDemoBundle). - -.. tip:: - - If a third party bundle relies on another bundle, you can find that bundle - mentioned in the ``composer.json`` file included in the bundle directory. From d51287520174de78c460b59f7fd4090a6e4b22bc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 16 Nov 2017 16:10:57 +0100 Subject: [PATCH 0077/2437] Updated http_cache/* articles to Symfony 4 --- http_cache.rst | 26 ++++++++++++-------------- http_cache/cache_invalidation.rst | 2 +- http_cache/esi.rst | 16 ++++++++-------- http_cache/validation.rst | 6 +++--- 4 files changed, 24 insertions(+), 26 deletions(-) diff --git a/http_cache.rst b/http_cache.rst index 21375c4dcee..9b42e54a966 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -81,18 +81,15 @@ Enabling the proxy is easy: each application comes with a caching kernel (``AppC that wraps the default one (``AppKernel``). The caching Kernel *is* the reverse proxy. -To enable caching, modify the code of your front controller. You can also make these -changes to ``index.php`` to add caching to the ``dev`` environment:: +To enable caching, modify the code of your ``index.php`` front controller:: // public/index.php use Symfony\Component\HttpFoundation\Request; // ... - $kernel = new AppKernel('prod', false); - $kernel->loadClassCache(); + $kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', $_SERVER['APP_DEBUG'] ?? false); - // add (or uncomment) this new line! - // wrap the default Kernel with the AppCache one + // add (or uncomment) this line to wrap the default Kernel with the AppCache one $kernel = new AppCache($kernel); $request = Request::createFromGlobals(); @@ -120,7 +117,9 @@ finely tuned via a set of options you can set by overriding the :method:`Symfony\\Bundle\\FrameworkBundle\\HttpCache\\HttpCache::getOptions` method:: - // app/AppCache.php + // src/AppCache.php + namespace App; + use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; class AppCache extends HttpCache @@ -137,10 +136,9 @@ method:: For a full list of the options and their meaning, see the :method:`HttpCache::__construct() documentation `. -When you're in debug mode (either because your booting a ``debug`` kernel, like -in ``index.php`` *or* you manually set the ``debug`` option to true), Symfony -automatically adds an ``X-Symfony-Cache`` header to the response. Use this to get -information about cache hits and misses. +When you're in debug mode (the second argument of ``Kernel`` constructor in the +front controller is ``true``), Symfony automatically adds an ``X-Symfony-Cache`` +header to the response. Use this to get information about cache hits and misses. .. _http-cache-symfony-versus-varnish: @@ -150,7 +148,7 @@ information about cache hits and misses. website or when you deploy your website to a shared host where you cannot install anything beyond PHP code. But being written in PHP, it cannot be as fast as a proxy written in C. - + Fortunately, since all reverse proxies are effectively the same, you should be able to switch to something more robust - like Varnish - without any problems. See :doc:`How to use Varnish ` @@ -192,7 +190,7 @@ These four headers are used to help cache your responses via *two* different mod All of the HTTP headers you'll read about are *not* invented by Symfony! They're part of an HTTP specification that's used by sites all over the web. To dig deeper - into HTTP Caching, check out the documents `RFC 7234 - Caching`_ and + into HTTP Caching, check out the documents `RFC 7234 - Caching`_ and `RFC 7232 - Conditional Requests`_. As a web developer, you are strongly urged to read the specification. Its @@ -214,7 +212,7 @@ The *easiest* way to cache a response is by caching it for a specific amount of use Symfony\Component\HttpFoundation\Response; // ... - public function indexAction() + public function index() { // somehow create a Response object, like by rendering a template $response = $this->render('blog/index.html.twig', []); diff --git a/http_cache/cache_invalidation.rst b/http_cache/cache_invalidation.rst index a67adb470c4..1cd44c00813 100644 --- a/http_cache/cache_invalidation.rst +++ b/http_cache/cache_invalidation.rst @@ -50,7 +50,7 @@ cache instead of going to the application to get a response. Here is how you can configure the Symfony reverse proxy to support the ``PURGE`` HTTP method:: - // app/AppCache.php + // src/AppCache.php use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; use Symfony\Component\HttpFoundation\Request; diff --git a/http_cache/esi.rst b/http_cache/esi.rst index 6276bf5110e..e5a7d46eac9 100644 --- a/http_cache/esi.rst +++ b/http_cache/esi.rst @@ -62,14 +62,14 @@ First, to use ESI, be sure to enable it in your application configuration: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... esi: { enabled: true } .. code-block:: xml - + loadFromExtension('framework', array( // ... 'esi' => array('enabled' => true), @@ -104,7 +104,7 @@ independent of the rest of the page. // ... class DefaultController extends Controller { - public function aboutAction() + public function about() { $response = $this->render('static/about.html.twig'); // set the shared max age - which also marks the response as public @@ -195,7 +195,7 @@ of the master page. // ... class NewsController extends Controller { - public function latestAction($maxPerPage) + public function latest($maxPerPage) { // ... $response->setSharedMaxAge(60); @@ -220,14 +220,14 @@ that must be enabled in your configuration: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... fragments: { path: /_fragment } .. code-block:: xml - + loadFromExtension('framework', array( // ... 'fragments' => array('path' => '/_fragment'), diff --git a/http_cache/validation.rst b/http_cache/validation.rst index 97dff6f41a0..260c7667eb5 100644 --- a/http_cache/validation.rst +++ b/http_cache/validation.rst @@ -66,7 +66,7 @@ To see a simple implementation, generate the ETag as the md5 of the content:: class DefaultController extends Controller { - public function homepageAction(Request $request) + public function homepage(Request $request) { $response = $this->render('static/homepage.html.twig'); $response->setEtag(md5($response->getContent())); @@ -131,7 +131,7 @@ header value:: class ArticleController extends Controller { - public function showAction(Article $article, Request $request) + public function show(Article $article, Request $request) { $author = $article->getAuthor(); @@ -190,7 +190,7 @@ exposing a simple and efficient pattern:: class ArticleController extends Controller { - public function showAction($articleSlug, Request $request) + public function show($articleSlug, Request $request) { // Get the minimum information to compute // the ETag or the Last-Modified value From 9e1057756c91925b30281e6511e4c9f67f25c326 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 16 Nov 2017 16:26:51 +0100 Subject: [PATCH 0078/2437] Changes after Ryan's review (thanks!) --- email.rst | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/email.rst b/email.rst index 56ac022f8c2..29e91fa7dac 100644 --- a/email.rst +++ b/email.rst @@ -4,12 +4,10 @@ How to Send an Email ==================== -Sending emails is a common task for any web application and one that has -special complications and potential pitfalls. Symfony provides a mailer feature -based on the popular `Swift Mailer`_ library via the `SwiftMailerBundle`_. - -The Symfony mailer supports sending messages with your own mail servers as well -as using popular email providers like `Mandrill`_, `SendGrid`_, and `Amazon SES`_. +Symfony provides a mailer feature based on the popular `Swift Mailer`_ library +via the `SwiftMailerBundle`_. This mailer supports sending messages with your +own mail servers as well as using popular email providers like `Mandrill`_, +`SendGrid`_, and `Amazon SES`_. Installation ------------ @@ -22,21 +20,21 @@ install and enable the mailer: $ composer require mailer If your application doesn't use Symfony Flex, follow the installation -instructions of the `SwiftMailerBundle`_. +instructions on `SwiftMailerBundle`_. .. _swift-mailer-configuration: Configuration ------------- -The ``config/packages/swiftmailer.yaml`` file created when installing the mailer -provides all the initial config needed to make it work, except the parameters -required to connect to the mail server. Those parameters are defined in the -``MAILER_URL`` environment variable in the ``.env`` file: +The ``config/packages/swiftmailer.yaml`` file that's created when installing the +mailer provides all the initial config needed to send emails, except your mail +server connection details. Those parameters are defined in the ``MAILER_URL`` +environment variable in the ``.env`` file: .. code-block:: bash - # use this to disable the email delivery + # use this to disable email delivery MAILER_URL=null://localhost # use this to send emails via Gmail (don't use this in production) From eee0a11f815738be357a43cac97ada1828ec2dc4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 16 Nov 2017 17:21:33 +0100 Subject: [PATCH 0079/2437] Updated logging/* articles to Symfony 4 --- logging.rst | 51 +++++++++++------------ logging/channels_handlers.rst | 15 ++++--- logging/disable_microsecond_precision.rst | 27 +++--------- logging/formatter.rst | 9 ++-- logging/monolog_console.rst | 25 ++++++----- logging/monolog_email.rst | 18 ++++---- logging/monolog_regex_based_excludes.rst | 6 +-- logging/processors.rst | 33 +++++++-------- 8 files changed, 83 insertions(+), 101 deletions(-) diff --git a/logging.rst b/logging.rst index 8b1e2b6b111..8f81925243f 100644 --- a/logging.rst +++ b/logging.rst @@ -7,19 +7,16 @@ logs that can be stored in a variety of different places. Logging a Message ----------------- -To log a message, fetch the ``logger`` service from the container in -your controller:: +If the application uses the :ref:`default services.yaml configuration `, +you can get the logger service injecting the ``LoggerInterface`` class:: use Psr\Log\LoggerInterface; - public function indexAction(LoggerInterface $logger) + public function index(LoggerInterface $logger) { - // alternative way of getting the logger - // $logger = $this->get('logger'); - $logger->info('I just got the logger'); $logger->error('An error occurred'); - + $logger->critical('I left the oven on!', array( // include extra "context" info in your logs 'cause' => 'in_hurry', @@ -28,7 +25,7 @@ your controller:: // ... } -The ``logger`` service has different methods for different logging levels/priorities. +The logger service has different methods for different logging levels/priorities. You can configure the logger to do different things based on the *level* of a message (e.g. :doc:`send an email when an error occurs `). @@ -37,10 +34,6 @@ See LoggerInterface_ for a list of all of the methods on the logger. Where Logs are Stored --------------------- -The configuration for *where* logs are stored lives in the specific -:doc:`environment ` configuration files: ``config_dev.yml`` -and ``config_prod.yml``. - By default, log entries are written to the ``var/log/dev.log`` file when you're in the ``dev`` environment. In the ``prod`` environment, logs are written to ``var/log/prod.log``, but *only* during a request where an error or high-priority log entry was made @@ -61,8 +54,8 @@ to different locations (e.g. files, database, Slack, etc). channel can have its *own* handlers, which means you can store different log messages in different places. See :doc:`/logging/channels_handlers`. -Symfony pre-configures some basic handlers in the ``config_dev.yml`` and ``config_prod.yml`` -files. Check these out for some real-world examples. +Symfony pre-configures some basic handlers in the default ``monolog.yaml`` +config files. Check these out for some real-world examples. This example uses *two* handlers: ``stream`` (to write to a file) and ``syslog`` to write logs using the :phpfunction:`syslog` function: @@ -71,7 +64,7 @@ to write logs using the :phpfunction:`syslog` function: .. code-block:: yaml - # app/config/config.yml + # config/packcages/monolog.yaml monolog: handlers: # this "file_log" key could be anything @@ -89,7 +82,7 @@ to write logs using the :phpfunction:`syslog` function: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'file_log' => array( @@ -147,7 +140,7 @@ one of the messages reaches an ``action_level``. Take this example: .. code-block:: yaml - # app/config/config.yml + # config/packcages/monolog.yaml monolog: handlers: filter_for_errors: @@ -168,7 +161,7 @@ one of the messages reaches an ``action_level``. Take this example: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'filter_for_errors' => array( @@ -261,7 +254,7 @@ option of your handler to ``rotating_file``: .. code-block:: yaml - # app/config/config_dev.yml + # config/packcages/dev/monolog.yaml monolog: handlers: main: @@ -274,7 +267,7 @@ option of your handler to ``rotating_file``: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'main' => array( @@ -315,8 +308,7 @@ option of your handler to ``rotating_file``: Using a Logger inside a Service ------------------------------- -To use a logger in your own services, add the ``@logger`` service as an argument -of those services. If you want to use a pre-configured logger which uses a +If you want to use in your own services a pre-configured logger which uses a specific channel (``app`` by default), use the ``monolog.logger`` tag with the ``channel`` property as explained in the :ref:`Dependency Injection reference `. @@ -334,9 +326,14 @@ Learn more .. toctree:: :maxdepth: 1 - :glob: - logging/* + logging/monolog_regex_based_excludes + logging/monolog_email + logging/channels_handlers + logging/monolog_console + logging/disable_microsecond_precision + logging/formatter + logging/processors .. _Monolog: https://github.com/Seldaek/monolog .. _LoggerInterface: https://github.com/php-fig/log/blob/master/Psr/Log/LoggerInterface.php diff --git a/logging/channels_handlers.rst b/logging/channels_handlers.rst index 48a11f405be..d0b05d57333 100644 --- a/logging/channels_handlers.rst +++ b/logging/channels_handlers.rst @@ -25,14 +25,13 @@ Switching a Channel to a different Handler Now, suppose you want to log the ``security`` channel to a different file. To do this, just create a new handler and configure it to log only messages -from the ``security`` channel. You might add this in ``config.yml`` to log -in all environments, or just ``config_prod.yml`` to happen only in ``prod``: +from the ``security`` channel: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/monolog.yaml monolog: handlers: security: @@ -49,7 +48,7 @@ in all environments, or just ``config_prod.yml`` to happen only in ``prod``: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'security' => array( @@ -138,13 +137,13 @@ You can also configure additional channels without the need to tag your services .. code-block:: yaml - # app/config/config.yml + # config/packages/monolog.yaml monolog: channels: ['foo', 'bar'] .. code-block:: xml - + loadFromExtension('monolog', array( 'channels' => array( 'foo', diff --git a/logging/disable_microsecond_precision.rst b/logging/disable_microsecond_precision.rst index 5e090b45072..d7b922d7cca 100644 --- a/logging/disable_microsecond_precision.rst +++ b/logging/disable_microsecond_precision.rst @@ -11,18 +11,14 @@ log generation. This is recommended for systems that generate a large number of .. code-block:: yaml - # app/config/config.yml + # config/packages/monolog.yaml monolog: use_microseconds: false - handlers: - applog: - type: stream - path: /var/log/symfony.log - level: error + # ... .. code-block:: xml - + - + .. code-block:: php - // app/config/config.php + // config/packages/monolog.php $container->loadFromExtension('monolog', array( 'use_microseconds' => false, - 'handlers' => array( - 'applog' => array( - 'type' => 'stream', - 'path' => '/var/log/symfony.log', - 'level' => 'error', - ), - ), + // ... )); diff --git a/logging/formatter.rst b/logging/formatter.rst index 3131b8c79f1..e5ce61af0bb 100644 --- a/logging/formatter.rst +++ b/logging/formatter.rst @@ -20,7 +20,7 @@ configure your handler to use it: Monolog\Formatter\JsonFormatter: ~ - # app/config/config_prod.yml (and/or config_dev.yml) + # config/packages/prod/monolog.yaml (and/or config/packages/dev/monolog.yaml) monolog: handlers: file: @@ -44,7 +44,7 @@ configure your handler to use it: - + register(JsonFormatter::class); - // app/config/config_prod.php (or config_dev.php) + // config/packages/prod/monolog.php (and/or config/packages/dev/monolog.php) $container->loadFromExtension('monolog', array( 'handlers' => array( 'file' => array( diff --git a/logging/monolog_console.rst b/logging/monolog_console.rst index b0f0e40760f..435a933bb1f 100644 --- a/logging/monolog_console.rst +++ b/logging/monolog_console.rst @@ -35,16 +35,22 @@ current log level and the console verbosity. The example above could then be rewritten as:: + use Psr\Log\LoggerInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; - protected function execute(InputInterface $input, OutputInterface $output) + private $logger; + + public function __constructor(LoggerInterface $logger) { - // assuming the Command extends ContainerAwareCommand... - $logger = $this->getContainer()->get('logger'); - $logger->debug('Some info'); + $this->logger = $logger; + } - $logger->notice('Some more info'); + protected function execute(InputInterface $input, OutputInterface $output) + { + $this->logger->debug('Some info'); + // ... + $this->logger->notice('Some more info'); } Depending on the verbosity level that the command is run in and the user's @@ -53,14 +59,13 @@ the console. If they are displayed, they are timestamped and colored appropriate Additionally, error logs are written to the error output (php://stderr). There is no need to conditionally handle the verbosity settings anymore. -The Monolog console handler is enabled by default in the Symfony Framework. For -example, in ``config_dev.yml``: +The Monolog console handler is enabled by default: .. configuration-block:: .. code-block:: yaml - # app/config/config_dev.yml + # config/packages/dev/monolog.yaml monolog: handlers: # ... @@ -75,7 +80,7 @@ example, in ``config_dev.yml``: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'console' => array( diff --git a/logging/monolog_email.rst b/logging/monolog_email.rst index 59eb032d739..4ff3ff4dc58 100644 --- a/logging/monolog_email.rst +++ b/logging/monolog_email.rst @@ -14,7 +14,7 @@ it is broken down. .. code-block:: yaml - # app/config/config_prod.yml + # config/packages/prod/monolog.yaml monolog: handlers: mail: @@ -42,7 +42,7 @@ it is broken down. .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'mail' => array( @@ -149,7 +149,7 @@ You can adjust the time period using the ``time`` option: .. code-block:: yaml - # app/config/config_prod.yml + # config/packages/prod/monolog.yaml monolog: handlers: # ... @@ -161,7 +161,7 @@ You can adjust the time period using the ``time`` option: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( // ... @@ -194,7 +194,7 @@ get logged on the server as well as the emails being sent: .. code-block:: yaml - # app/config/config_prod.yml + # config/packages/prod/monolog.yaml monolog: handlers: main: @@ -222,7 +222,7 @@ get logged on the server as well as the emails being sent: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'main' => array( diff --git a/logging/monolog_regex_based_excludes.rst b/logging/monolog_regex_based_excludes.rst index 51df5adf716..2537565c945 100644 --- a/logging/monolog_regex_based_excludes.rst +++ b/logging/monolog_regex_based_excludes.rst @@ -16,7 +16,7 @@ configuration: .. code-block:: yaml - # app/config/config.yml + # config/packages/monolog.yaml monolog: handlers: main: @@ -28,7 +28,7 @@ configuration: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'main' => array( diff --git a/logging/processors.rst b/logging/processors.rst index 309115aa068..ce63343d7ae 100644 --- a/logging/processors.rst +++ b/logging/processors.rst @@ -63,7 +63,6 @@ information: - "[%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%% %%context%% %%extra%%\n" App\Logger\SessionRequestProcessor: - autowire: true tags: - { name: monolog.processor, method: processRecord } @@ -86,7 +85,7 @@ information: [%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%% %%context%% %%extra%% - + @@ -103,7 +102,7 @@ information: ->addArgument('[%%datetime%%] [%%extra.token%%] %%channel%%.%%level_name%%: %%message%% %%context%% %%extra%%\n'); $container - ->autowire(SessionRequestProcessor::class) + ->register(SessionRequestProcessor::class) ->addTag('monolog.processor', array('method' => 'processRecord')); Finally, set the formatter to be used on whatever handler you want: @@ -112,7 +111,7 @@ Finally, set the formatter to be used on whatever handler you want: .. code-block:: yaml - # app/config/config.yml + # config/packages/monolog.yaml monolog: handlers: main: @@ -123,7 +122,7 @@ Finally, set the formatter to be used on whatever handler you want: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'main' => array( @@ -172,16 +171,15 @@ the ``monolog.processor`` tag: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml services: App\Logger\SessionRequestProcessor: - autowire: true tags: - { name: monolog.processor, method: processRecord, handler: main } .. code-block:: xml - + - + @@ -200,11 +198,11 @@ the ``monolog.processor`` tag: .. code-block:: php - // app/config/config.php + // config/services.php // ... $container - ->autowire(SessionRequestProcessor::class) + ->register(SessionRequestProcessor::class) ->addTag('monolog.processor', array('method' => 'processRecord', 'handler' => 'main')); Registering Processors per Channel @@ -217,16 +215,15 @@ the ``monolog.processor`` tag: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml services: App\Logger\SessionRequestProcessor: - autowire: true tags: - { name: monolog.processor, method: processRecord, channel: main } .. code-block:: xml - + - + @@ -245,9 +242,9 @@ the ``monolog.processor`` tag: .. code-block:: php - // app/config/config.php + // config/services.php // ... $container - ->autowire(SessionRequestProcessor::class) + ->register(SessionRequestProcessor::class) ->addTag('monolog.processor', array('method' => 'processRecord', 'channel' => 'main')); From f769069fe6156800a76776b1b171682ba4a3d17a Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 16 Nov 2017 17:47:42 +0100 Subject: [PATCH 0080/2437] Updated the profiler/* articles to Symfony 4 --- profiler.rst | 6 ++++-- profiler/data_collector.rst | 32 +++++++++++--------------------- profiler/profiling_data.rst | 11 +++++------ profiler/storage.rst | 12 ++++-------- 4 files changed, 24 insertions(+), 37 deletions(-) diff --git a/profiler.rst b/profiler.rst index 496b86fbf62..e62434c52cb 100644 --- a/profiler.rst +++ b/profiler.rst @@ -3,6 +3,8 @@ Profiler .. toctree:: :maxdepth: 1 - :glob: - profiler/* + profiler/storage + profiler/data_collector + profiler/matchers + profiler/profiling_data diff --git a/profiler/data_collector.rst b/profiler/data_collector.rst index 1e84d95a05d..16647b48fbd 100644 --- a/profiler/data_collector.rst +++ b/profiler/data_collector.rst @@ -122,8 +122,8 @@ block and set the value of two variables called ``icon`` and ``text``: {% block toolbar %} {% set icon %} {# this is the content displayed as a panel in the toolbar #} - - Request + ... + Request {% endset %} {% set text %} @@ -147,23 +147,15 @@ block and set the value of two variables called ``icon`` and ``text``: .. tip:: - Built-in collector templates define all their images as embedded base64-encoded - images. This makes them work everywhere without having to mess with web assets - links: - - .. code-block:: html - - - - Another solution is to define the images as SVG files. In addition to being - resolution-independent, these images can be easily embedded in the Twig - template or included from an external file to reuse them in several templates: + Built-in collector templates define all their images as embedded SVG files. + This makes them work everywhere without having to mess with web assets links: .. code-block:: twig - {{ include('data_collector/icon.svg') }} - - You are encouraged to use the latter technique for your own toolbar panels. + {% set icon %} + {{ include('data_collector/icon.svg') }} + {# ... #} + {% endset %} If the toolbar panel includes extended web profiler information, the Twig template must also define additional blocks: @@ -174,8 +166,7 @@ must also define additional blocks: {% block toolbar %} {% set icon %} - - Request + {# ... #} {% endset %} {% set text %} @@ -275,6 +266,5 @@ to specify a tag that contains the template: )) ; -The position of each panel in the toolbar is determined by the priority defined -by each collector. Most built-in collectors use ``255`` as their priority. If you -want your collector to be displayed before them, use a higher value (like 300). +The position of each panel in the toolbar is determined by the collector priority +(the higher the priority, the earlier the panel is displayed in the toolbar). diff --git a/profiler/profiling_data.rst b/profiler/profiling_data.rst index 427d2e28d09..824267eb358 100644 --- a/profiler/profiling_data.rst +++ b/profiler/profiling_data.rst @@ -21,7 +21,7 @@ Using this token, you can access the profile of any past response thanks to the :method:`Symfony\\Component\\HttpKernel\\Profiler\\Profiler::loadProfile` method:: $token = $response->headers->get('X-Debug-Token'); - $profile = $container->get('profiler')->loadProfile($token); + $profile = $profiler->loadProfile($token); .. tip:: @@ -34,14 +34,13 @@ The ``profiler`` service also provides the look for tokens based on some criteria:: // get the latest 10 tokens - $tokens = $container->get('profiler')->find('', '', 10, '', '', ''); + $tokens = $profiler->find('', '', 10, '', '', ''); // get the latest 10 tokens for all URL containing /admin/ - $tokens = $container->get('profiler')->find('', '/admin/', 10, '', '', ''); + $tokens = $profiler->find('', '/admin/', 10, '', '', ''); // get the latest 10 tokens for local POST requests - $tokens = $container->get('profiler')->find('127.0.0.1', '', 10, 'POST', '', ''); + $tokens = $profiler->find('127.0.0.1', '', 10, 'POST', '', ''); // get the latest 10 tokens for requests that happened between 2 and 4 days ago - $tokens = $container->get('profiler') - ->find('', '', 10, '', '4 days ago', '2 days ago'); + $tokens = $profiler->find('', '', 10, '', '4 days ago', '2 days ago'); diff --git a/profiler/storage.rst b/profiler/storage.rst index f4bdaaca061..fc9d31d528b 100644 --- a/profiler/storage.rst +++ b/profiler/storage.rst @@ -4,11 +4,7 @@ Switching the Profiler Storage ============================== -In Symfony versions prior to 3.0, profiles could be stored in files, databases, -services like Redis and Memcache, etc. Starting from Symfony 3.0, the only storage -mechanism with built-in support is the filesystem. - -By default the profile stores the collected data in the ``%kernel.cache_dir%/profiler/`` +The profiler stores the collected data in the ``%kernel.cache_dir%/profiler/`` directory. If you want to use another location to store the profiles, define the ``dsn`` option of the ``framework.profiler``: @@ -16,14 +12,14 @@ directory. If you want to use another location to store the profiles, define the .. code-block:: yaml - # app/config/config.yml + # config/packages/dev/web_profiler.yaml framework: profiler: dsn: 'file:/tmp/symfony/profiler' .. code-block:: xml - + loadFromExtension('framework', array( From 453884f8a48ffc9e2024e4f49fe7bc5be954504f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 16 Nov 2017 18:06:43 +0100 Subject: [PATCH 0081/2437] Updated the serializer/* articles to Symfony 4 --- serializer.rst | 36 +++++++++++++++------------- serializer/custom_encoders.rst | 10 ++++---- service_container/3.3-di-changes.rst | 2 ++ 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/serializer.rst b/serializer.rst index e79c8446ff7..8cabbd1ba2e 100644 --- a/serializer.rst +++ b/serializer.rst @@ -4,19 +4,23 @@ How to Use the Serializer ========================= -Serializing and deserializing to and from objects and different formats (e.g. -JSON or XML) is a very complex topic. Symfony comes with a -:doc:`Serializer Component `, which gives you some -tools that you can leverage for your solution. +Symfony provides a serializer to serialize/deserialize to and from objects and +different formats (e.g. JSON or XML). Before using it, read the +:doc:`Serializer component docs ` to get familiar with +its philosophy and the normalizers and encoders terminology. -In fact, before you start, get familiar with the serializer, normalizers -and encoders by reading the :doc:`Serializer Component `. +.. _activating_the_serializer: -Activating the Serializer +Installing the Serializer ------------------------- -The ``serializer`` service is not available by default. To turn it on, activate -it in your configuration: +Before using the serializer, run this command to install it in your application: + +.. code-block:: terminal + + $ composer require serializer + +Then, enable the serializer in the framework config: .. configuration-block:: @@ -65,7 +69,7 @@ it in your configuration: Using the Serializer Service ---------------------------- -Once enabled, the ``serializer`` service can be injected in any service where +Once enabled, the serializer service can be injected in any service where you need it or it can be used in a controller:: // src/Controller/DefaultController.php @@ -85,7 +89,7 @@ you need it or it can be used in a controller:: Adding Normalizers and Encoders ------------------------------- -Once enabled, the ``serializer`` service will be available in the container +Once enabled, the serializer service will be available in the container and will be loaded with four :ref:`encoders ` (:class:`Symfony\\Component\\Serializer\\Encoder\\JsonEncoder`, :class:`Symfony\\Component\\Serializer\\Encoder\\XmlEncoder`, @@ -193,12 +197,12 @@ to your class and choose which groups to use when serializing:: ); In addition to the ``@Groups`` annotation, the Serializer component also -supports Yaml or XML files. These files are automatically loaded when being +supports YAML or XML files. These files are automatically loaded when being stored in one of the following locations: -* The ``serialization.yml`` or ``serialization.xml`` file in +* The ``serialization.yaml`` or ``serialization.xml`` file in the ``Resources/config/`` directory of a bundle; -* All ``*.yml`` and ``*.xml`` files in the ``Resources/config/serialization/`` +* All ``*.yaml`` and ``*.xml`` files in the ``Resources/config/serialization/`` directory of a bundle. .. _serializer-enabling-metadata-cache: @@ -302,9 +306,9 @@ take a look at how this bundle works. .. toctree:: :maxdepth: 1 - :glob: - serializer/* + serializer/encoders + serializer/custom_encoder .. _`APCu`: https://github.com/krakjoe/apcu .. _`ApiPlatform`: https://github.com/api-platform/core diff --git a/serializer/custom_encoders.rst b/serializer/custom_encoders.rst index a63b27efdf0..24ca040292e 100644 --- a/serializer/custom_encoders.rst +++ b/serializer/custom_encoders.rst @@ -15,7 +15,7 @@ to use another structure that's not supported. Creating a new encoder ---------------------- -Imagine you want to serialize and deserialize Yaml. For that you'll have to +Imagine you want to serialize and deserialize YAML. For that you'll have to create your own encoder that uses the :doc:`Yaml Component `:: @@ -53,13 +53,13 @@ Registering it in your app If you use the Symfony Framework. then you probably want to register this encoder as a service in your app. If you're using the :ref:`default services.yml configuration `, -that's done automatically! +that's done automatically! .. tip:: - If you're not using autoconfigure, make sure to register your class as a service - and tag it with ``serializer.encoder``. + If you're not using :ref:`autoconfigure `, make sure + to register your class as a service and tag it with ``serializer.encoder``. -Now you'll be able to serialize and deserialize Yaml! +Now you'll be able to serialize and deserialize YAML! .. _tracker: https://github.com/symfony/symfony/issues diff --git a/service_container/3.3-di-changes.rst b/service_container/3.3-di-changes.rst index b5ba004db6c..414fee368bd 100644 --- a/service_container/3.3-di-changes.rst +++ b/service_container/3.3-di-changes.rst @@ -408,6 +408,8 @@ In general, the new best practice is to use normal constructor dependency inject (or "action" injection in controllers) instead of fetching public services via ``$this->get()`` (though that does still work). +_service_autoconfigure: + 4) Auto-tagging with autoconfigure ---------------------------------- From 333a9217b2bb96cffcf04cb751b8fadc8f63877b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 16 Nov 2017 22:48:59 +0100 Subject: [PATCH 0082/2437] remove outdated note --- setup/new_project_git.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/setup/new_project_git.rst b/setup/new_project_git.rst index 599939fe0ab..26047a58268 100644 --- a/setup/new_project_git.rst +++ b/setup/new_project_git.rst @@ -66,12 +66,6 @@ changes to your Git repository. You can continue to follow along with the :doc:`/page_creation` article to learn more about how to configure and develop inside your application. -.. tip:: - - The Symfony Standard Edition comes with some example functionality. To - remove the sample code, follow the instructions in the - ":doc:`/bundles/remove`" article. - .. include:: _vendor_deps.rst.inc Storing your Project on a remote Server From d53d72a3075f86ddf95a04677d618bb0b3c47dd6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 16 Nov 2017 22:55:41 +0100 Subject: [PATCH 0083/2437] remove another outdated note --- setup/new_project_svn.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/setup/new_project_svn.rst b/setup/new_project_svn.rst index beb81b39175..937fc37d1ec 100644 --- a/setup/new_project_svn.rst +++ b/setup/new_project_svn.rst @@ -109,12 +109,6 @@ repository. You can continue to follow along with the :doc:`/page_creation` article to learn more about how to configure and develop inside your application. -.. tip:: - - The Symfony Standard Edition comes with some example functionality. To - remove the sample code, follow the instructions in the - ":doc:`/bundles/remove`" article. - .. include:: _vendor_deps.rst.inc .. _svn-hosting: From 1a3be4386f60f9c2e88995406bf82b12397d8759 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 16 Nov 2017 23:13:18 +0100 Subject: [PATCH 0084/2437] fix namespaces --- service_container/tags.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/service_container/tags.rst b/service_container/tags.rst index 19fd550dfdc..0ca73e7b829 100644 --- a/service_container/tags.rst +++ b/service_container/tags.rst @@ -255,10 +255,13 @@ add the compiler pass to the container in a :doc:`bundle extension Date: Fri, 17 Nov 2017 09:07:05 +0100 Subject: [PATCH 0085/2437] Fixed a reference --- serializer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serializer.rst b/serializer.rst index 8cabbd1ba2e..75b38c49d33 100644 --- a/serializer.rst +++ b/serializer.rst @@ -308,7 +308,7 @@ take a look at how this bundle works. :maxdepth: 1 serializer/encoders - serializer/custom_encoder + serializer/custom_encoders .. _`APCu`: https://github.com/krakjoe/apcu .. _`ApiPlatform`: https://github.com/api-platform/core From 78289f12401a74a0feede62890e1e9cd0fe12bf5 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 17 Nov 2017 10:02:01 +0100 Subject: [PATCH 0086/2437] Updated the session/* articles for Symfony 4 --- session.rst | 9 +++++++-- session/limit_metadata_writes.rst | 3 +++ session/locale_sticky_session.rst | 18 ++++++++++-------- session/php_bridge.rst | 6 ++++++ session/proxy_examples.rst | 6 +++--- session/sessions_directory.rst | 6 +++--- 6 files changed, 32 insertions(+), 16 deletions(-) diff --git a/session.rst b/session.rst index 144f068d34f..33fbbc61745 100644 --- a/session.rst +++ b/session.rst @@ -3,6 +3,11 @@ Sessions .. toctree:: :maxdepth: 1 - :glob: - session/* + session/sessions_directory + session/avoid_session_start + session/locale_sticky_session + session/limit_metadata_writes + session/php_bridge + session/proxy_examples + diff --git a/session/limit_metadata_writes.rst b/session/limit_metadata_writes.rst index de28ccb52a8..ea9b95c9d4a 100644 --- a/session/limit_metadata_writes.rst +++ b/session/limit_metadata_writes.rst @@ -23,12 +23,14 @@ than zero: .. code-block:: yaml + # config/packages/framework.yaml framework: session: metadata_update_threshold: 120 .. code-block:: xml + loadFromExtension('framework', array( 'session' => array( 'metadata_update_threshold' => 120, diff --git a/session/locale_sticky_session.rst b/session/locale_sticky_session.rst index 7a4ae4307cd..9280f8360d5 100644 --- a/session/locale_sticky_session.rst +++ b/session/locale_sticky_session.rst @@ -73,16 +73,18 @@ via some "Change Locale" route & controller), or create a route with a the :ref: .. code-block:: yaml + # config/services.yaml services: # ... App\EventSubscriber\LocaleSubscriber: arguments: ['%kernel.default_locale%'] - # redundant if you're using autoconfigure - tags: [kernel.event_subscriber] + # uncomment the next line if you are not using autoconfigure + # tags: [kernel.event_subscriber] .. code-block:: xml + %kernel.default_locale% - + + .. code-block:: php + // config/services.php use App\EventSubscriber\LocaleSubscriber; $container->register(LocaleSubscriber::class) ->addArgument('%kernel.default_locale%') - ->addTag('kernel.event_subscriber'); + // uncomment the next line if you are not using autoconfigure + // ->addTag('kernel.event_subscriber'); That's it! Now celebrate by changing the user's locale and seeing that it's sticky throughout the request. @@ -115,7 +120,7 @@ method:: // from a controller... use Symfony\Component\HttpFoundation\Request; - public function indexAction(Request $request) + public function index(Request $request) { $locale = $request->getLocale(); } @@ -159,9 +164,6 @@ event: $this->session = $session; } - /** - * @param InteractiveLoginEvent $event - */ public function onInteractiveLogin(InteractiveLoginEvent $event) { $user = $event->getAuthenticationToken()->getUser(); diff --git a/session/php_bridge.rst b/session/php_bridge.rst index f8c161f3ec6..4771fe67e39 100644 --- a/session/php_bridge.rst +++ b/session/php_bridge.rst @@ -15,6 +15,7 @@ for the ``handler_id``: .. code-block:: yaml + # config/packages/framework.yaml framework: session: storage_id: session.storage.php_bridge @@ -22,6 +23,7 @@ for the ``handler_id``: .. code-block:: xml + loadFromExtension('framework', array( 'session' => array( 'storage_id' => 'session.storage.php_bridge', @@ -54,6 +57,7 @@ the example below: .. code-block:: yaml + # config/packages/framework.yaml framework: session: storage_id: session.storage.php_bridge @@ -61,6 +65,7 @@ the example below: .. code-block:: xml + loadFromExtension('framework', array( 'session' => array( 'storage_id' => 'session.storage.php_bridge', diff --git a/session/proxy_examples.rst b/session/proxy_examples.rst index 82f636b7616..2a475cc25c5 100644 --- a/session/proxy_examples.rst +++ b/session/proxy_examples.rst @@ -21,7 +21,7 @@ Symfony to use your session handler instead of the default one: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: session: # ... @@ -29,7 +29,7 @@ Symfony to use your session handler instead of the default one: .. code-block:: xml - + loadFromExtension('framework', array( // ... diff --git a/session/sessions_directory.rst b/session/sessions_directory.rst index c1b91f5472f..9e8d06ea627 100644 --- a/session/sessions_directory.rst +++ b/session/sessions_directory.rst @@ -11,7 +11,7 @@ this path, update the ``framework.session.save_path`` configuration key: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: session: handler_id: session.handler.native_file @@ -19,7 +19,7 @@ this path, update the ``framework.session.save_path`` configuration key: .. code-block:: xml - + loadFromExtension('framework', array( 'session' => array( 'handler_id' => 'session.handler.native_file', From 96ce11e7566ad88d20088c671152f923d01fc161 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Fri, 17 Nov 2017 14:03:35 +0200 Subject: [PATCH 0087/2437] fixing typo --- logging.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/logging.rst b/logging.rst index 8f81925243f..f4bb0f7ef56 100644 --- a/logging.rst +++ b/logging.rst @@ -64,7 +64,7 @@ to write logs using the :phpfunction:`syslog` function: .. code-block:: yaml - # config/packcages/monolog.yaml + # config/packages/monolog.yaml monolog: handlers: # this "file_log" key could be anything @@ -82,7 +82,7 @@ to write logs using the :phpfunction:`syslog` function: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'file_log' => array( @@ -140,7 +140,7 @@ one of the messages reaches an ``action_level``. Take this example: .. code-block:: yaml - # config/packcages/monolog.yaml + # config/packages/monolog.yaml monolog: handlers: filter_for_errors: @@ -161,7 +161,7 @@ one of the messages reaches an ``action_level``. Take this example: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'filter_for_errors' => array( @@ -254,7 +254,7 @@ option of your handler to ``rotating_file``: .. code-block:: yaml - # config/packcages/dev/monolog.yaml + # config/packages/dev/monolog.yaml monolog: handlers: main: @@ -267,7 +267,7 @@ option of your handler to ``rotating_file``: .. code-block:: xml - + loadFromExtension('monolog', array( 'handlers' => array( 'main' => array( From 2ee2ce23b1f803bc14da4f1a1a53cc83552d5f5f Mon Sep 17 00:00:00 2001 From: sgautier Date: Thu, 16 Nov 2017 12:43:08 +0100 Subject: [PATCH 0088/2437] Change web directory with public directory --- setup/web_server_configuration.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/setup/web_server_configuration.rst b/setup/web_server_configuration.rst index 1825a0a0faa..2a21501ced4 100644 --- a/setup/web_server_configuration.rst +++ b/setup/web_server_configuration.rst @@ -42,8 +42,8 @@ The **minimum configuration** to get your application running under Apache is: ServerName domain.tld ServerAlias www.domain.tld - DocumentRoot /var/www/project/web - + DocumentRoot /var/www/project/public + AllowOverride All Order Allow,Deny Allow from All @@ -73,8 +73,8 @@ and increase web server performance: ServerName domain.tld ServerAlias www.domain.tld - DocumentRoot /var/www/project/web - + DocumentRoot /var/www/project/public + AllowOverride None Order Allow,Deny Allow from All @@ -123,7 +123,7 @@ Hence, you need to modify your ``Directory`` permission settings as follows: .. code-block:: apache - + Require all granted # ... @@ -193,8 +193,8 @@ use the ``SetHandler`` directive to pass requests for PHP files to PHP FPM: # regular expression must be changed accordingly: # ProxyPassMatch ^/path-to-app/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/var/www/project/public/$1 - DocumentRoot /var/www/project/web - + DocumentRoot /var/www/project/public + # enable the .htaccess rewrites AllowOverride All Require all granted @@ -228,8 +228,8 @@ should look something like this: Alias /php7-fcgi /usr/lib/cgi-bin/php7-fcgi FastCgiExternalServer /usr/lib/cgi-bin/php7-fcgi -host 127.0.0.1:9000 -pass-header Authorization - DocumentRoot /var/www/project/web - + DocumentRoot /var/www/project/public + # enable the .htaccess rewrites AllowOverride All Order Allow,Deny @@ -264,7 +264,7 @@ The **minimum configuration** to get your application running under Nginx is: server { server_name domain.tld www.domain.tld; - root /var/www/project/web; + root /var/www/project/public; location / { # try to serve file directly, fallback to index.php From d343c01d0f1db5dd6f48e20dc6e58819d491fdb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20Perrin?= Date: Sat, 18 Nov 2017 13:05:04 +0200 Subject: [PATCH 0089/2437] Update server configuration for Symfony 4 --- setup/web_server_configuration.rst | 38 ++++++++---------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/setup/web_server_configuration.rst b/setup/web_server_configuration.rst index 2a21501ced4..9f15c1ac815 100644 --- a/setup/web_server_configuration.rst +++ b/setup/web_server_configuration.rst @@ -15,13 +15,13 @@ When using Apache, you can configure PHP as an :ref:`PHP FPM `. FastCGI also is the preferred way to use PHP :ref:`with Nginx `. -.. sidebar:: The Web Directory +.. sidebar:: The public directory - The web directory is the home of all of your application's public and + The public directory is the home of all of your application's public and static files, including images, stylesheets and JavaScript files. It is - also where the front controllers (``index.php`` and ``index.php``) live. + also where the front controller (``index.php``) lives. - The web directory serves as the document root when configuring your + The public directory serves as the document root when configuring your web server. In the examples below, the ``public/`` directory will be the document root. This directory is ``/var/www/project/public/``. @@ -270,25 +270,8 @@ The **minimum configuration** to get your application running under Nginx is: # try to serve file directly, fallback to index.php try_files $uri /index.php$is_args$args; } - # DEV - # This rule should only be placed on your development environment - # In production, don't include this and don't deploy index.php or config.php - location ~ ^/(app_dev|config)\.php(/|$) { - fastcgi_pass unix:/var/run/php7.1-fpm.sock; - fastcgi_split_path_info ^(.+\.php)(/.*)$; - include fastcgi_params; - # When you are using symlinks to link the document root to the - # current version of your application, you should pass the real - # application path instead of the path to the symlink to PHP - # FPM. - # Otherwise, PHP's OPcache may not properly detect changes to - # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126 - # for more information). - fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; - fastcgi_param DOCUMENT_ROOT $realpath_root; - } - # PROD - location ~ ^/app\.php(/|$) { + + location ~ ^/index\.php(/|$) { fastcgi_pass unix:/var/run/php7.1-fpm.sock; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; @@ -324,17 +307,16 @@ The **minimum configuration** to get your application running under Nginx is: .. tip:: - This executes **only** ``index.php``, ``index.php`` and ``config.php`` in - the web directory. All other files ending in ".php" will be denied. + This executes **only** ``index.php`` in the public directory. All other files + ending in ".php" will be denied. - If you have other PHP files in your web directory that need to be executed, + If you have other PHP files in your public directory that need to be executed, be sure to include them in the ``location`` block above. .. caution:: After you deploy to production, make sure that you **cannot** access the ``index.php`` - or ``config.php`` scripts (i.e. ``http://example.com/index.php`` and ``http://example.com/config.php``). - If you *can* access these, be sure to remove the ``DEV`` section from the above configuration. + script (i.e. ``http://example.com/index.php``). .. note:: From e0fa5cb60aca5b28171c35639a8f45bd6449200f Mon Sep 17 00:00:00 2001 From: fridde Date: Sat, 18 Nov 2017 19:45:00 +0100 Subject: [PATCH 0090/2437] Update flex.rst --- setup/flex.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/flex.rst b/setup/flex.rst index ae3a09202f5..4d88d5d3a7f 100644 --- a/setup/flex.rst +++ b/setup/flex.rst @@ -148,6 +148,7 @@ following directory structure, which is the same used by default in Symfony 4: │   ├── ... │   └── Kernel.php ├── templates/ + ├── translations/ └── vendor/ This means that installing the ``symfony/flex`` dependency in your application From b3ef6c37ecf27c81328e9dd27b73043dd5125cc2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sun, 19 Nov 2017 12:52:42 +0100 Subject: [PATCH 0091/2437] Fixed a RST reference --- service_container/3.3-di-changes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service_container/3.3-di-changes.rst b/service_container/3.3-di-changes.rst index 414fee368bd..ba4445ad42c 100644 --- a/service_container/3.3-di-changes.rst +++ b/service_container/3.3-di-changes.rst @@ -408,7 +408,7 @@ In general, the new best practice is to use normal constructor dependency inject (or "action" injection in controllers) instead of fetching public services via ``$this->get()`` (though that does still work). -_service_autoconfigure: +.. _service_autoconfigure: 4) Auto-tagging with autoconfigure ---------------------------------- From 62228ecbe3bb6716d3ca36dd0d3de826fec86f08 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 20 Nov 2017 16:45:17 +0100 Subject: [PATCH 0092/2437] Updated testing/* articles to Symfony 4 --- testing.rst | 16 +++--- testing/database.rst | 26 +++------- testing/profiling.rst | 113 ++++++++++++++++++++++-------------------- 3 files changed, 76 insertions(+), 79 deletions(-) diff --git a/testing.rst b/testing.rst index 96bc16cdc1b..e3f0ce225d9 100644 --- a/testing.rst +++ b/testing.rst @@ -158,22 +158,26 @@ As an example, a test could look like this:: .. tip:: - To run your functional tests, the ``WebTestCase`` class bootstraps the - kernel of your application. In most cases, this happens automatically. - However, if your kernel is in a non-standard directory, you'll need - to modify your ``phpunit.xml.dist`` file to set the ``KERNEL_DIR`` - environment variable to the directory of your kernel: + To run your functional tests, the ``WebTestCase`` class needs to know which + is the application kernel to bootstrap it. The kernel class is usually + defined in the ``KERNEL_CLASS`` environment variable (included in the + default ``phpunit .xml-dist`` file provided by Symfony): .. code-block:: xml - + + + If your use case is more complex, you can also override the + ``createKernel()`` or ``getKernelClass()`` methods of your functional test, + which take precedence over the ``KERNEL_CLASS`` env var. + The ``createClient()`` method returns a client, which is like a browser that you'll use to crawl your site:: diff --git a/testing/database.rst b/testing/database.rst index 4dd7f511238..b144fd5b7da 100644 --- a/testing/database.rst +++ b/testing/database.rst @@ -113,44 +113,32 @@ not to overwrite data you entered when developing the application and also to be able to clear the database before every test. To do this, you can specify a database configuration which overwrites the default -configuration: +configuration just in the ``test`` environment: .. configuration-block:: .. code-block:: yaml - # app/config/config_test.yml + # config/packages/test/doctrine.yaml doctrine: # ... dbal: - host: localhost - dbname: testdb - user: testdb - password: testdb + url: 'mysql://USERNAME:PASSWORD@127.0.0.1/DB_NAME?charset=utf8mb4&serverVersion=5.7' .. code-block:: xml - + .. code-block:: php - // app/config/config_test.php + // config/packages/test/doctrine.php $container->loadFromExtension('doctrine', array( 'dbal' => array( - 'host' => 'localhost', - 'dbname' => 'testdb', - 'user' => 'testdb', - 'password' => 'testdb', + 'url' => 'mysql://USERNAME:PASSWORD@127.0.0.1/DB_NAME?charset=utf8mb4&serverVersion=5.7', ), )); - -Make sure that your database runs on localhost and has the defined database and -user credentials set up. diff --git a/testing/profiling.rst b/testing/profiling.rst index 7455938594e..fc7ee75cef1 100644 --- a/testing/profiling.rst +++ b/testing/profiling.rst @@ -9,11 +9,65 @@ you write functional tests that monitor your production servers, you might want to write tests on the profiling data as it gives you a great way to check various things and enforce some metrics. -:doc:`The Symfony Profiler ` gathers a lot of data for -each request. Use this data to check the number of database calls, the time -spent in the framework, etc. But before writing assertions, enable the profiler -and check that the profiler is indeed available (it is enabled by default in -the ``test`` environment):: +.. _speeding-up-tests-by-not-collecting-profiler-data: + +Enabling the Profiler in Tests +------------------------------ + +Collecting data with :doc:`the Symfony Profiler ` can slow down your +tests significantly. That's why Symfony disables it by default: + +.. configuration-block:: + + .. code-block:: yaml + + # config/packages/test/web_profiler.yaml + + # ... + framework: + profiler: { collect: false } + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // config/packages/test/web_profiler.php + + // ... + $container->loadFromExtension('framework', array( + // ... + 'profiler' => array( + 'enabled' => true, + 'collect' => false, + ), + )); + +Setting ``collect`` to ``true`` enables the profiler for all tests. However, if +you need the profiler just in a few tests, you can keep it disabled globally and +enable the profiler individually on each test by calling +``$client->enableProfiler()``. + +Testing the Profiler Information +-------------------------------- + +The data collected by the Symfony Profiler can be used to check the number of +database calls, the time spent in the framework, etc. All this information is +provided by the collectors obtained through the ``$client->getProfile()`` call:: class LuckyControllerTest extends WebTestCase { @@ -74,52 +128,3 @@ finish. It's easy to achieve if you embed the token in the error message:: Read the API for built-in :doc:`data collectors ` to learn more about their interfaces. - -Speeding up Tests by not Collecting Profiler Data -------------------------------------------------- - -To avoid collecting data in each test you can set the ``collect`` parameter -to false: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config_test.yml - - # ... - framework: - profiler: - enabled: true - collect: false - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - - // ... - $container->loadFromExtension('framework', array( - 'profiler' => array( - 'enabled' => true, - 'collect' => false, - ), - )); - -In this way only tests that call ``$client->enableProfiler()`` will collect data. From d396d8a599d17437d432ff8bf558b076d77b289f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 20 Nov 2017 17:27:03 +0100 Subject: [PATCH 0093/2437] Fixed everything --- testing.rst | 4 ++-- testing/bootstrap.rst | 2 +- testing/database.rst | 43 +++++++++++++------------------------------ 3 files changed, 16 insertions(+), 33 deletions(-) diff --git a/testing.rst b/testing.rst index e3f0ce225d9..707c95eb8d8 100644 --- a/testing.rst +++ b/testing.rst @@ -161,7 +161,7 @@ As an example, a test could look like this:: To run your functional tests, the ``WebTestCase`` class needs to know which is the application kernel to bootstrap it. The kernel class is usually defined in the ``KERNEL_CLASS`` environment variable (included in the - default ``phpunit .xml-dist`` file provided by Symfony): + default ``phpunit.xml.dist`` file provided by Symfony): .. code-block:: xml @@ -169,7 +169,7 @@ As an example, a test could look like this:: - + diff --git a/testing/bootstrap.rst b/testing/bootstrap.rst index 82f8c3e04c3..9f4b02af19a 100644 --- a/testing/bootstrap.rst +++ b/testing/bootstrap.rst @@ -20,7 +20,7 @@ To do this, first add a file that executes your bootstrap work:: require __DIR__.'/../vendor/autoload.php'; -Then, configure ``phpunit.xml.dist`` to execute this ``bootstra.php`` file +Then, configure ``phpunit.xml.dist`` to execute this ``bootstrap.php`` file before running the tests: .. code-block:: xml diff --git a/testing/database.rst b/testing/database.rst index b144fd5b7da..ed94218b529 100644 --- a/testing/database.rst +++ b/testing/database.rst @@ -112,33 +112,16 @@ Most of the time you want to use a dedicated database connection to make sure not to overwrite data you entered when developing the application and also to be able to clear the database before every test. -To do this, you can specify a database configuration which overwrites the default -configuration just in the ``test`` environment: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/test/doctrine.yaml - doctrine: - # ... - dbal: - url: 'mysql://USERNAME:PASSWORD@127.0.0.1/DB_NAME?charset=utf8mb4&serverVersion=5.7' - - .. code-block:: xml - - - - - - - .. code-block:: php - - // config/packages/test/doctrine.php - $container->loadFromExtension('doctrine', array( - 'dbal' => array( - 'url' => 'mysql://USERNAME:PASSWORD@127.0.0.1/DB_NAME?charset=utf8mb4&serverVersion=5.7', - ), - )); +To do this, you can override the value of the ``DATABASE_URL`` env var in the +``phpunit.xml.dist`` to use a diferent database for your tests: + +.. code-block:: xml + + + + + + + + + From a2cd1fccacd590e3e01c3fa6008ed0746471cc12 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 07:34:26 -0500 Subject: [PATCH 0094/2437] changing order --- profiler.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/profiler.rst b/profiler.rst index e62434c52cb..0f20ead43b8 100644 --- a/profiler.rst +++ b/profiler.rst @@ -4,7 +4,7 @@ Profiler .. toctree:: :maxdepth: 1 - profiler/storage profiler/data_collector - profiler/matchers profiler/profiling_data + profiler/matchers + profiler/storage From cb319009f3bf97b8a7674d00fef7bda62293f0ab Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 07:47:46 -0500 Subject: [PATCH 0095/2437] Fixing serializer config - much is now done automatically --- reference/configuration/framework.rst | 15 --- serializer.rst | 136 ++------------------------ 2 files changed, 7 insertions(+), 144 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 374edd23263..aa33f039851 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -106,7 +106,6 @@ Configuration * `debug`_ * `serializer`_ * :ref:`enabled ` - * :ref:`cache ` * :ref:`enable_annotations ` * :ref:`name_converter ` * :ref:`circular_reference_handler ` @@ -1656,20 +1655,6 @@ enabled Whether to enable the ``serializer`` service or not in the service container. -.. _reference-serializer-cache: - -cache -..... - -**type**: ``string`` - -The service that is used to persist class metadata in a cache. The service -has to implement the ``Doctrine\Common\Cache\Cache`` interface. - -.. seealso:: - - For more information, see :ref:`serializer-enabling-metadata-cache`. - .. _reference-serializer-enable_annotations: enable_annotations diff --git a/serializer.rst b/serializer.rst index 75b38c49d33..c79964d067d 100644 --- a/serializer.rst +++ b/serializer.rst @@ -20,52 +20,6 @@ Before using the serializer, run this command to install it in your application: $ composer require serializer -Then, enable the serializer in the framework config: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - # ... - serializer: { enable_annotations: true } - # Alternatively, if you don't want to use annotations - #serializer: { enabled: true } - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - // config/packages/framework.php - $container->loadFromExtension('framework', array( - // ... - 'serializer' => array( - 'enable_annotations' => true, - // Alternatively, if you don't want to use annotations - //'enabled' => true, - ), - )); - Using the Serializer Service ---------------------------- @@ -147,46 +101,11 @@ Here is an example on how to load the Using Serialization Groups Annotations -------------------------------------- -Enable :ref:`serialization groups annotation ` -with the following configuration: - -.. configuration-block:: - - .. code-block:: yaml - - # config/packages/framework.yaml - framework: - # ... - serializer: - enable_annotations: true - - .. code-block:: xml - - - - - - - - - - +To use annotations, first install the annotations package: - .. code-block:: php +.. code-block:: terminal - // config/packages/framework.php - $container->loadFromExtension('framework', array( - // ... - 'serializer' => array( - 'enable_annotations' => true, - ), - )); + $ composer require annotations Next, add the :ref:`@Groups annotations ` to your class and choose which groups to use when serializing:: @@ -207,52 +126,11 @@ stored in one of the following locations: .. _serializer-enabling-metadata-cache: -Enabling the Metadata Cache ---------------------------- - -Metadata used by the Serializer component such as groups can be cached to -enhance application performance. Any service implementing the ``Doctrine\Common\Cache\Cache`` -interface can be used. - -A service leveraging `APCu`_ (and APC for PHP < 5.5) is built-in. - -.. configuration-block:: - - .. code-block:: yaml +Configruing the Metadata Cache +------------------------------ - # config/packages/prod/framework.yaml - framework: - # ... - serializer: - cache: serializer.mapping.cache.apc - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - // config/packages/prod/framework.php - $container->loadFromExtension('framework', array( - // ... - 'serializer' => array( - 'cache' => 'serializer.mapping.cache.apc', - ), - )); +The metadata for the serializer is automatically cached. To configure the cache, +configure the ``framework.cache.pools`` key in ``config/packages/framework.yaml``. Enabling a Name Converter ------------------------- From 179531f131358407dda0e7cee0ab03d373204ec2 Mon Sep 17 00:00:00 2001 From: Adoni Pavlakis Date: Tue, 21 Nov 2017 13:06:30 +0000 Subject: [PATCH 0096/2437] Fix grammar --- best_practices/creating-the-project.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/best_practices/creating-the-project.rst b/best_practices/creating-the-project.rst index 5784b2fd343..4818bf4b804 100644 --- a/best_practices/creating-the-project.rst +++ b/best_practices/creating-the-project.rst @@ -8,7 +8,7 @@ Installing Symfony Use Composer and Symfony Flex to create and manage Symfony applications. -`Composer`_ is the package manager used by modern PHP application to manage +`Composer`_ is the package manager used by modern PHP applications to manage their dependencies. `Symfony Flex`_ is a Composer plugin designed to automate some of the most common tasks performed in Symfony applications. Using Flex is optional but recommended because it improves your productivity significantly. From 47473060fab7fb32969e77cc31c534258ead04ec Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 21 Nov 2017 15:52:39 +0100 Subject: [PATCH 0097/2437] Mention security voters as the recommended alternative to ACL --- security/acl.rst | 3 +++ security/acl_advanced.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/security/acl.rst b/security/acl.rst index b09c6364b46..9ca61e27b3b 100644 --- a/security/acl.rst +++ b/security/acl.rst @@ -9,4 +9,7 @@ How to Use Access Control Lists (ACLs) ACL support was removed in Symfony 4.0. Install the `Symfony ACL bundle`_ and refer to its documentation if you want to keep using ACL. + Alternatively, consider using :doc:`security voters `, + the alternative to ACLs recommended by Symfony. + .. _`Symfony ACL bundle`: https://github.com/symfony/acl-bundle diff --git a/security/acl_advanced.rst b/security/acl_advanced.rst index 062d69a8b8a..de67c9b43e0 100644 --- a/security/acl_advanced.rst +++ b/security/acl_advanced.rst @@ -9,4 +9,7 @@ How to Use advanced ACL Concepts ACL support was removed in Symfony 4.0. Install the `Symfony ACL bundle`_ and refer to its documentation if you want to keep using ACL. + Alternatively, consider using :doc:`security voters `, + the alternative to ACLs recommended by Symfony. + .. _`Symfony ACL bundle`: https://github.com/symfony/acl-bundle From b563ab29f38fa6a94c57c1697465fd1b7dd7af49 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 09:53:35 -0500 Subject: [PATCH 0098/2437] using different example --- .../dependency_injection/_imports-parameters-note.rst.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/dependency_injection/_imports-parameters-note.rst.inc b/components/dependency_injection/_imports-parameters-note.rst.inc index bcaff4c1bfc..3b479e70ba6 100644 --- a/components/dependency_injection/_imports-parameters-note.rst.inc +++ b/components/dependency_injection/_imports-parameters-note.rst.inc @@ -10,7 +10,7 @@ # app/config/config.yml imports: - - { resource: '%kernel.project_dir%/app/parameters.yml' } + - { resource: '%kernel.project_dir%/somefile.yml' } .. code-block:: xml @@ -22,11 +22,11 @@ http://symfony.com/schema/dic/services/services-1.0.xsd"> - + .. code-block:: php // app/config/config.php - $loader->import('%kernel.project_dir%/app/parameters.yml'); + $loader->import('%kernel.project_dir%/somefile.yml'); From b973f0cda07559f6209cf64431a47b1795dc2137 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 21 Nov 2017 16:51:39 +0100 Subject: [PATCH 0099/2437] Updated the best practice article about config --- best_practices/configuration.rst | 108 ++++++++++--------------------- 1 file changed, 35 insertions(+), 73 deletions(-) diff --git a/best_practices/configuration.rst b/best_practices/configuration.rst index 9c3d1585d50..f87d5336cd4 100644 --- a/best_practices/configuration.rst +++ b/best_practices/configuration.rst @@ -11,33 +11,32 @@ three parts. Infrastructure-Related Configuration ------------------------------------ +These are the options that change from one machine to another (e.g. from your +development machine to the production server) but which don't change the +application behavior. + .. best-practice:: - Define the infrastructure-related configuration options in the - ``app/config/parameters.yml`` file. + Define the infrastructure-related configuration options as environment + variables in the ``.env`` file at the root of the project. -The default ``parameters.yml`` file follows this recommendation and defines the -options related to the database and mail server infrastructure: +By default, Symfony adds this kind of options to the ``.env`` file when +installing new dependencies in the app: -.. code-block:: yaml +.. code-block:: bash - # app/config/parameters.yml - parameters: - database_driver: pdo_mysql - database_host: 127.0.0.1 - database_port: ~ - database_name: symfony - database_user: root - database_password: ~ + # .env + ###> doctrine/doctrine-bundle ### + DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/blog.sqlite + ###< doctrine/doctrine-bundle ### - mailer_transport: smtp - mailer_host: 127.0.0.1 - mailer_user: ~ - mailer_password: ~ + ###> symfony/swiftmailer-bundle ### + MAILER_URL=smtp://localhost?encryption=ssl&auth_mode=login&username=&password= + ###< symfony/swiftmailer-bundle ### - # ... + # ... -These options aren't defined inside the ``app/config/config.yml`` file because +These options aren't defined inside the ``config/services.yaml`` file because they have nothing to do with the application's behavior. In other words, your application doesn't care about the location of your database or the credentials to access to it, as long as the database is correctly configured. @@ -49,19 +48,14 @@ Canonical Parameters .. best-practice:: - Define all your application's parameters in the - ``app/config/parameters.yml.dist`` file. + Define all your application's env vars in the ``.env.dist`` file. -Symfony includes a configuration file called ``parameters.yml.dist``, which -stores the canonical list of configuration parameters for the application. +Symfony includes a configuration file called ``.env.dist`` at the project root, +which stores the canonical list of environment variables for the application. -Whenever a new configuration parameter is defined for the application, you -should also add it to this file and submit the changes to your version control -system. Then, whenever a developer updates the project or deploys it to a server, -Symfony will check if there is any difference between the canonical -``parameters.yml.dist`` file and your local ``parameters.yml`` file. If there -is a difference, Symfony will ask you to provide a value for the new parameter -and it will add it to your local ``parameters.yml`` file. +Whenever a new env var is defined for the application, you should also add it to +this file and submit the changes to your version control system so your +workmates can update their ``.env`` files. Application-Related Configuration --------------------------------- @@ -69,17 +63,17 @@ Application-Related Configuration .. best-practice:: Define the application behavior related configuration options in the - ``app/config/config.yml`` file. + ``config/services.yaml`` file. -The ``config.yml`` file contains the options used by the application to modify -its behavior, such as the sender of email notifications, or the enabled -`feature toggles`_. Defining these values in ``parameters.yml`` file would -add an extra layer of configuration that's not needed because you don't need -or want these configuration values to change on each server. +The ``services.yaml`` file contains the options used by the application to +modify its behavior, such as the sender of email notifications, or the enabled +`feature toggles`_. Defining these values in ``.env`` file would add an extra +layer of configuration that's not needed because you don't need or want these +configuration values to change on each server. -The configuration options defined in the ``config.yml`` file usually vary from -one :doc:`environment ` to another. That's -why Symfony already includes ``app/config/config_dev.yml`` and ``app/config/config_prod.yml`` +The configuration options defined in the ``services.yaml`` may vary from one +:doc:`environment ` to another. That's why Symfony +supports defining ``config/services_dev.yaml`` and ``config/services_prod.yaml`` files so that you can override specific values for each environment. Constants vs Configuration Options @@ -99,7 +93,7 @@ to control the number of posts to display on the blog homepage: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml parameters: homepage.num_items: 10 @@ -167,7 +161,7 @@ just one or two words to describe the purpose of the parameter: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml parameters: # don't do this: 'dir' is too generic and it doesn't convey any meaning app.dir: '...' @@ -178,38 +172,6 @@ just one or two words to describe the purpose of the parameter: app.dir.contents: '...' app.contents-dir: '...' -Semantic Configuration: Don't Do It ------------------------------------ - -.. best-practice:: - - Don't define a semantic dependency injection configuration for your bundles. - -As explained in :doc:`/bundles/extension` article, Symfony bundles -have two choices on how to handle configuration: normal service configuration -through the ``services.yml`` file and semantic configuration through a special -``*Extension`` class. - -Although semantic configuration is much more powerful and provides nice features -such as configuration validation, the amount of work needed to define that -configuration isn't worth it for bundles that aren't meant to be shared as -third-party bundles. - -Moving Sensitive Options Outside of Symfony Entirely ----------------------------------------------------- - -When dealing with sensitive options, like database credentials, we also recommend -that you store them outside the Symfony project and make them available -through environment variables: - -.. code-block:: yaml - - # app/config/config.yml - doctrine: - dbal: - # ... - password: "%env(DB_PASSWORD)%" - ---- Next: :doc:`/best_practices/business-logic` From bbffb1a6977b7ce236ede04f47699a00ed9e158e Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 10:15:53 -0500 Subject: [PATCH 0100/2437] Removing all PAAS deployment articles We cannot maintain these and keep them up to date --- deployment.rst | 28 +-- deployment/azure-website.rst | 455 +---------------------------------- deployment/fortrabbit.rst | 281 +-------------------- deployment/heroku.rst | 327 +------------------------ deployment/platformsh.rst | 192 +-------------- 5 files changed, 26 insertions(+), 1257 deletions(-) diff --git a/deployment.rst b/deployment.rst index 1ff67c815c3..9fff7ce5043 100644 --- a/deployment.rst +++ b/deployment.rst @@ -63,14 +63,16 @@ manually taking other steps (see `Common Post-Deployment Tasks`_). Using Platforms as a Service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The specific deployment steps vary greatly from one service provider to another, -so check out the dedicated article for the service of your choose: +Using a Platform as a Service (PAAS) can be a great way to deploy your Symfony app +quickly and easily. There are many PAAS - below are a few that work well with Symfony: .. toctree:: :maxdepth: 1 - :glob: - deployment/* + deployment/heroku + deployment/platformsh + deployment/azure-website + deployment/fortrabbit Using Build Scripts and other Tools ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -123,18 +125,16 @@ Check if your server meets the requirements by running: .. _b-configure-your-app-config-parameters-yml-file: -B) Configure your Parameters File -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +B) Configure your Environment Variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Most Symfony applications define configuration parameters in a file called -``app/config/parameters.yml``. This file should *not* be deployed, because -Symfony generates it automatically using the ``app/config/parameters.yml.dist`` -file as a template (that's why ``parameters.yml.dist`` must be committed and -deployed). +Most Symfony applications read their configuration from environment variables. +While developing locally, you'll usually store these in a ``.env`` file. But on +production, instead of creating this file, you should set *real* environment variables. -If your application uses environment variables instead of these parameters, you -must define those env vars in your production server using the tools provided by -your hosting service. +How you set environment variables, depends on your setup: they can be set at the +command line, in your Nginx configuration, or via other methods provided by your +hosting service. C) Install/Update your Vendors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/deployment/azure-website.rst b/deployment/azure-website.rst index b615b8c3c99..2a84df5220e 100644 --- a/deployment/azure-website.rst +++ b/deployment/azure-website.rst @@ -4,456 +4,7 @@ Deploying to Microsoft Azure Website Cloud ========================================== -This step by step article describes how to deploy a small Symfony web -application to the Microsoft Azure Website cloud platform. It will explain how -to set up a new Azure website including configuring the right PHP version and -global environment variables. The document also shows how you can leverage -Git and Composer to deploy your Symfony application to the cloud. +If you want information about deploying to Azure, see their official documentation: +`Create your PHP web application on Azure`_ -Setting up the Azure Website ----------------------------- - -To set up a new Microsoft Azure Website, first `sign up with Azure`_ or sign in -with your credentials. Once you're connected to your `Azure Portal`_ interface, -select the **New** panel. On this panel, use the search bar, search for -**Web App + MySQL** and choose **Web App + MySQL** by **Microsoft** and -click **Create**: - -.. image:: /_images/deployment/azure-website/step-01.png - :alt: Create a new custom Azure Website - -Step 1: Create Web Site -~~~~~~~~~~~~~~~~~~~~~~~ - -Here, you will be prompted to fill in some basic information. - -.. image:: /_images/deployment/azure-website/step-02.png - :alt: Setup the Azure Website - -For the URL, enter the URL that you would like to use for your Symfony -application, then select your **Subscription**, **Create a new Resource Group** -(which is a collection of resources that share the same lifecycle, permissions -and policies). Pick ClearDB as a **Database Provider**. Create a new **App -Service plan/Location** you will be prompted to set up your app service plan -with a name, a region and a pricing tier. Then create a new **Database**, you -will be prompted to set up your MySQL database storage with a database name and -a region. The MySQL database storage is provided by Microsoft in partnership -with ClearDB. Choose the same region you selected for App Service plan. - -Click Create to continue. - -Once you created the web site, select **All resources** in the left menu and -choose the website you just created. - -Step 2: Where Is your Source Code -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now, select **Deployment options** under **APP DEPLOYMENT**, select **Choose -Source** and choose **Local Git repository** to configure your Azure Website -credentials. If you choose a different source like GitHub or Bitbucket you can -ignore the next step. - -.. image:: /_images/deployment/azure-website/step-03.png - :alt: Setup a local Git repository - -Once you selected **Local Git repository**, click **Setup connection** you will -be prompted to create a username and a secure password: these will become -essential identifiers to connect to the FTP server and also to push your -application code to the Git repository. - -.. image:: /_images/deployment/azure-website/step-04.png - :alt: Configure Azure Website credentials - -Congratulations! Your Azure Website is now up and running. You can check -it by browsing to the Website url you configured in the first step. You should -see the following display in your web browser: - -.. image:: /_images/deployment/azure-website/step-05.png - :alt: Azure Website is running - -The Microsoft Azure portal also provides a complete control panel for the Azure -Website. - -.. image:: /_images/deployment/azure-website/step-06.png - :alt: Azure Website Control Panel - -Your Azure Website is ready! But to run a Symfony site, you need to configure -just a few additional things. - -Configuring the Azure Website for Symfony ------------------------------------------ - -This section of the tutorial details how to configure the correct version of PHP -to run Symfony. It also shows you how to enable some mandatory PHP extensions -and how to properly configure PHP for a production environment. - -Configuring the latest PHP Runtime -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Even though Symfony only requires PHP 5.5.9 to run, it's always recommended -to use the most recent PHP version whenever possible. Earlier versions are no longer -supported by the PHP core team, but you can update it easily in Azure. - -To update your PHP version on Azure, go to the **Application settings** under -**SETTINGS** and select the version you want. - -.. image:: /_images/deployment/azure-website/step-07.png - :alt: Enabling the most recent PHP runtime from Azure Website Control Panel - -Click the **Save** button in the bottom bar to save your changes and restart -the web server. - -.. note:: - - Choosing a more recent PHP version can greatly improve runtime performance. - PHP 5.5 ships with a new built-in PHP accelerator called OPCache that - replaces APC. On an Azure Website, OPCache is already enabled and there - is no need to install and set up APC. - - The following screenshot shows the output of a :phpfunction:`phpinfo` script - run from an Azure Website to verify that PHP 7.0 is running with - OPCache enabled. - - .. image:: /_images/deployment/azure-website/step-08.png - :alt: OPCache Configuration - -Tweaking php.ini Configuration Settings -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Microsoft Azure allows you to override the ``php.ini`` global configuration -settings by creating a custom ``.user.ini`` file under the project root -directory (``site/wwwroot``). - -.. code-block:: ini - - ; .user.ini - expose_php = Off - memory_limit = 256M - upload_max_filesize = 10M - -None of these settings *needs* to be overridden. The default PHP configuration -is already pretty good, so this is just an example to show how you can easily -tweak PHP internal settings by uploading your custom ``.ini`` file. - -You can either manually create this file on your Azure Website FTP server under -the ``site/wwwroot`` directory or deploy it with Git. You can get your FTP -server credentials from the Azure Website Control panel under the **Dashboard** -tab on the right sidebar. If you want to use Git, simply put your ``.user.ini`` -file at the root of your local repository and push your commits to your Azure -Website repository. - -.. note:: - - `Deploying from Git`_ is dedicated to explaining how to configure your - Azure Website Git repository and how to push the commits to be deployed. - You can also learn more about configuring PHP internal settings on the - official `PHP MSDN documentation`_ page. - -Enabling the PHP intl Extension -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -**The** ``intl`` **extension is now enabled by default. The following steps are -no longer necessary.** You can check if the ``intl`` extension is enabled in the -:phpfunction:`phpinfo` page. - -However if the ``intl`` extension is not enabled you can follow these steps. - -This is the tricky part of the guide! To enable the ``intl`` extension, there is -no need to upload any DLL files as the ``php_intl.dll`` file already exists on -Azure. In fact, this file just needs to be moved into the custom website -extension directory. - -To get the ``php_intl.dll`` file under your ``site/wwwroot`` directory, simply -access the online **Kudu** tool by browsing to the following URL: - -.. code-block:: text - - https://[your-website-name].scm.azurewebsites.net - -**Kudu** is a set of tools to manage your application. It comes with a file -explorer, a command line prompt, a log stream and a configuration settings summary -page. Of course, this section can only be accessed if you're logged in to -your main Azure Website account. - -.. image:: /_images/deployment/azure-website/step-09.png - :alt: The Kudu Panel - -From the Kudu front page, click on the **Debug Console** navigation item in the -main menu and choose **CMD**. This should open the **Debug Console** page -that shows a file explorer and a console prompt below. - -In the console prompt, type the following three commands to copy the original -``php_intl.dll`` extension file into a custom website ``ext/`` directory. This -new directory must be created under the main directory ``site/wwwroot``. - -.. code-block:: terminal - - $ cd site\wwwroot - $ mkdir ext - $ copy "D:\Program Files (x86)\PHP\v5.5\ext\php_intl.dll" ext - -The whole process and output should look like this: - -.. image:: /_images/deployment/azure-website/step-10.png - :alt: Executing commands in the online Kudu Console prompt - -To complete the activation of the ``php_intl.dll`` extension, you must tell -Azure Website to load it from the newly created ``ext`` directory. This can be -done by registering a global ``PHP_EXTENSIONS`` environment variable from -the **Application settings** page of the main Azure Website control panel. - -In the **app settings** section, register the ``PHP_EXTENSIONS`` environment -variable with the value ``ext\php_intl.dll`` as shown in the screenshot below: - -.. image:: /_images/deployment/azure-website/step-11.png - :alt: Registering custom PHP extensions - -Hit "save" to confirm your changes and restart the web server. The PHP ``Intl`` -extension should now be available in your web server environment. The following -screenshot of a :phpfunction:`phpinfo` page verifies the ``intl`` extension is -properly enabled: - -.. image:: /_images/deployment/azure-website/step-12.png - :alt: Intl extension is enabled - -Great! The PHP environment setup is now complete. Next, you'll learn how -to configure the Git repository and push code to production. You'll also -learn how to install and configure the Symfony app after it's deployed. - -Deploying from Git -~~~~~~~~~~~~~~~~~~ - -First, make sure Git is correctly installed on your local machine using the -following command in your terminal: - -.. code-block:: terminal - - $ git --version - -.. note:: - - Get your Git from the `git-scm.com`_ website and follow the instructions - to install and configure it on your local machine. - -In the Azure Website Control panel, browse the **Overview** tab to get the -Git repository URL where you should push your code: - -.. image:: /_images/deployment/azure-website/step-13.png - :alt: Git deployment panel - -Now, you'll want to connect your local Symfony application with this remote -Git repository on Azure Website. If your Symfony application is not yet stored -with Git, you must first create a Git repository in your Symfony application -directory with the ``git init`` command and commit to it with the ``git commit`` -command. - -Also, make sure your Symfony repository has a ``.gitignore`` file at its root -directory with at least the following contents: - -.. code-block:: text - - /var/bootstrap.php.cache - /var/cache/* - /app/config/parameters.yml - /var/log/* - !var/cache/.gitkeep - !var/log/.gitkeep - /var/SymfonyRequirements.php - /build/ - /vendor/ - /bin/ - /composer.phar - /public/index.php - /public/bundles/ - /public/config.php - -The ``.gitignore`` file asks Git not to track any of the files and directories -that match these patterns. This means these files won't be deployed to the Azure -Website. - -Now, from the command line on your local machine, type the following at the -root of your Symfony project: - -.. code-block:: terminal - - $ git remote add azure https://@.scm.azurewebsites.net:443/.git - $ git push azure master - -Don't forget to replace the values enclosed by ``<`` and ``>`` with your custom -settings displayed in the **Deployment** tab of your Azure Website panel. The -``git remote`` command connects the Azure Website remote Git repository and -assigns an alias to it with the name ``azure``. The second ``git push`` command -pushes all your commits to the remote ``master`` branch of your remote ``azure`` -Git repository. - -The deployment with Git should produce an output similar to the screenshot -below: - -.. image:: /_images/deployment/azure-website/step-14.png - :alt: Deploying files to the Git Azure Website repository - -The code of the Symfony application has now been deployed to the Azure Website -which you can browse from the file explorer of the Kudu application. You should -see the ``config/``, ``src/`` and ``public/`` directories under your ``site/wwwroot`` -directory on the Azure Website filesystem. - -Configure the Symfony Application -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -PHP has been configured and your code has been pushed with Git. The last -step is to configure the application and install the third party dependencies -it requires that aren't tracked by Git. Switch back to the online **Console** -of the Kudu application and execute the following commands in it: - -.. code-block:: terminal - - $ cd site\wwwroot - $ curl -sS https://getcomposer.org/installer | php - $ php composer.phar install - -The ``curl`` command retrieves and downloads the Composer command line tool and -installs it at the root of the ``site/wwwroot`` directory. Then, running -the Composer ``install`` command downloads and installs all necessary third-party -libraries. - -This may take a while depending on the number of third-party dependencies -you've configured in your ``composer.json`` file. - - -At the end of the ``composer install`` command, you will be prompted to fill in -the values of some Symfony settings like database credentials, locale, mailer -credentials, CSRF token protection, etc. These parameters come from the -``app/config/parameters.yml.dist`` file. - -.. image:: /_images/deployment/azure-website/step-15.png - :alt: Configuring Symfony global parameters - -The most important thing in this article is to correctly set up your database -settings. You can get your MySQL database settings in the **Application -settings** page. Simply click on the **Show connection string values** link to -make them appear. - -.. image:: /_images/deployment/azure-website/step-16.png - :alt: MySQL database settings - -The displayed MySQL database settings should be something similar to the code -below. Of course, each value depends on what you've already configured. - -.. code-block:: text - - Database=mysymfonyMySQL;Data Source=eu-cdbr-azure-north-c.cloudapp.net;User Id=bff2481a5b6074;Password=bdf50b42 - -Switch back to the console and answer the prompted questions and provide the -following answers. Don't forget to adapt the values below with your real values -from the MySQL connection string. - -.. code-block:: text - - database_driver: pdo_mysql - database_host: u-cdbr-azure-north-c.cloudapp.net - database_port: null - database_name: mysymfonyMySQL - database_user: bff2481a5b6074 - database_password: bdf50b42 - // ... - -Don't forget to answer all the questions. It's important to set a unique random -string for the ``secret`` variable. For the mailer configuration, Azure Website -doesn't provide a built-in mailer service. You should consider configuring -the host-name and credentials of some other third-party mailing service if -your application needs to send emails. - -Your Symfony application is now configured and should be almost operational. The -final step is to build the database schema. This can easily be done with the -command line interface if you're using Doctrine. In the online **Console** tool -of the Kudu application, run the following command to mount the tables into your -MySQL database. - -.. code-block:: terminal - - $ php bin/console doctrine:schema:update --force - -This command builds the tables and indexes for your MySQL database. If your -Symfony application is more complex than a basic Symfony Standard Edition, you -may have additional commands to execute for setup (see :doc:`/deployment`). - -Make sure that your application is running by browsing the ``index.php`` front -controller with your web browser and the following URL: - -.. code-block:: terminal - - http://.azurewebsites.net/public/index.php - -If Symfony is correctly installed, you should see the front page of your Symfony -application showing. - -Configure the Web Server -~~~~~~~~~~~~~~~~~~~~~~~~ - -At this point, the Symfony application has been deployed and works perfectly on -the Azure Website. However, the ``web`` folder is still part of the URL, which -you definitely don't want. But don't worry! You can easily configure the web -server to point to the ``web`` folder and remove the ``web`` in the URL (and -guarantee that nobody can access files outside of the ``web`` directory.) - -To do this, create and deploy (see previous section about Git) the following -``web.config`` file. This file must be located at the root of your project -next to the ``composer.json`` file. This file is the Microsoft IIS Server -equivalent to the well-known ``.htaccess`` file from Apache. For a Symfony -application, configure it with the following content: - -.. code-block:: xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -As you can see, the latest rule ``RewriteRequestsToPublic`` is responsible for -rewriting any URLs to the ``public/index.php`` front controller which allows you to -skip the ``public/`` folder in the URL. The first rule called ``BlockAccessToPublic`` -matches all URL patterns that contain the ``public/`` folder and serves a -``403 Forbidden`` HTTP response instead. This example is based on Benjamin -Eberlei's sample you can find on GitHub in the `SymfonyAzureEdition`_ bundle. - -Deploy this file under the ``site/wwwroot`` directory of the Azure Website and -browse to your application without the ``public/index.php`` segment in the URL. - -Conclusion ----------- - -Nice work! You've now deployed your Symfony application to the Microsoft -Azure Website Cloud platform. You also saw that Symfony can be easily configured -and executed on a Microsoft IIS web server. The process is simple and easy -to implement. And as a bonus, Microsoft is continuing to reduce the number -of steps needed so that deployment becomes even easier. - -.. _`sign up with Azure`: https://azure.microsoft.com/free/ -.. _`Azure Portal`: https://portal.azure.com -.. _`PHP MSDN documentation`: http://blogs.msdn.com/b/silverlining/archive/2012/07/10/configuring-php-in-windows-azure-websites-with-user-ini-files.aspx -.. _`git-scm.com`: http://git-scm.com/download -.. _`SymfonyAzureEdition`: https://github.com/beberlei/symfony-azure-edition/ +.. _`Create your PHP web application on Azure`: https://azure.microsoft.com/en-us/develop/php/ diff --git a/deployment/fortrabbit.rst b/deployment/fortrabbit.rst index 8e2028ee821..49907599f37 100644 --- a/deployment/fortrabbit.rst +++ b/deployment/fortrabbit.rst @@ -4,282 +4,7 @@ Deploying to fortrabbit ======================= -This step-by-step article describes how to deploy a Symfony web application to -`fortrabbit`_. You can read more about using Symfony with fortrabbit on the -official fortrabbit `Symfony install guide`_. +For details on deploying to fortrabbit, see their official documentation: +`Install Symfony`_ -Setting up fortrabbit ---------------------- - -Before getting started, you should have done a few things on the fortrabbit side: - -* `Sign up`_; -* Add an SSH key to your Account (to deploy via Git); -* Create an App. - -Preparing your Application --------------------------- - -You don't need to change any code to deploy a Symfony application to fortrabbit. -But it requires some minor tweaks to its configuration. - -Configure Logging -~~~~~~~~~~~~~~~~~ - -Per default Symfony logs to a file. Modify the ``app/config/config_prod.yml`` file -to redirect it to :phpfunction:`error_log`: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config_prod.yml - monolog: - # ... - handlers: - nested: - type: error_log - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - // app/config/config_prod.php - $container->loadFromExtension('monolog', array( - // ... - 'handlers' => array( - 'nested' => array( - 'type' => 'error_log', - ), - ), - )); - -Configuring Database Access & Session Handler -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You can use the fortrabbit App Secrets to attain your database credentials. -Create the file ``app/config/config_prod_secrets.php`` with the following -contents:: - - // get the path to the secrects.json file - $secrets = getenv("APP_SECRETS") - if (!$secrets) { - return; - } - - // read the file and decode json to an array - $secrets = json_decode(file_get_contents($secrets), true); - - // set database parameters to the container - if (isset($secrets['MYSQL'])) { - $container->setParameter('database_driver', 'pdo_mysql'); - $container->setParameter('database_host', $secrets['MYSQL']['HOST']); - $container->setParameter('database_name', $secrets['MYSQL']['DATABASE']); - $container->setParameter('database_user', $secrets['MYSQL']['USER']); - $container->setParameter('database_password', $secrets['MYSQL']['PASSWORD']); - } - - // check if the Memcache component is present - if (isset($secrets['MEMCACHE'])) { - $memcache = $secrets['MEMCACHE']; - $handlers = array(); - - foreach (range(1, $memcache['COUNT']) as $num) { - $handlers[] = $memcache['HOST'.$num].':'.$memcache['PORT'.$num]; - } - - // apply ini settings - ini_set('session.save_handler', 'memcached'); - ini_set('session.save_path', implode(',', $handlers)); - - if ("2" === $memcache['COUNT']) { - ini_set('memcached.sess_number_of_replicas', 1); - ini_set('memcached.sess_consistent_hash', 1); - ini_set('memcached.sess_binary', 1); - } - } - -Make sure this file is imported into the main config file: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config_prod.yml - imports: - - { resource: config.yml } - - { resource: config_prod_secrets.php } - - # .. - framework: - session: - # set handler_id to null to use default session handler from php.ini (memcached) - handler_id: ~ - # .. - - .. code-block:: xml - - - - - - - - - - - - - - - - - - .. code-block:: php - - // app/config/config_prod.php - $loader->import('config.php'); - $loader->import('config_prod_secrets.php'); - - $container->loadFromExtension('framework', array( - 'session' => array( - 'handler_id' => null, - ), - )); - - // ... - -Configuring the Environment in the Dashboard --------------------------------------------- - -PHP Settings -~~~~~~~~~~~~ - -The PHP version and enabled extensions are configurable under the PHP settings -of your App within the fortrabbit Dashboard. - -Environment Variables -~~~~~~~~~~~~~~~~~~~~~ - -Set the ``SYMFONY_ENV`` environment variable to ``prod`` to make sure the right -config files get loaded. ENV vars are configuable in fortrabbit Dashboard as well. - -Document Root -~~~~~~~~~~~~~ - -The document root is configurable for every custom domain you setup for your App. -The default is ``/htdocs``, but for Symfony you probably want to change it to -``/htdocs/web``. You also do so in the fortrabbit Dashboard under ``Domain`` settings. - -Deploying to fortrabbit ------------------------ - -It is assumed that your codebase is under version-control with Git and dependencies -are managed with Composer (locally). - -Every time you push to fortrabbit composer install runs before your code gets -deployed. To finetune the deployment behavior put a `fortrabbit.yml`_. deployment -file (optional) in the project root. - -Add fortrabbit as a (additional) Git remote and add your configuration changes: - -.. code-block:: terminal - - $ git remote add fortrabbit git@deploy.eu2.frbit.com:.git - $ git add composer.json composer.lock - $ git add app/config/config_prod_secrets.php - -Commit and push - -.. code-block:: terminal - - $ git commit -m 'fortrabbit config' - $ git push fortrabbit master -u - -.. note:: - - Replace ```` with the name of your fortrabbit App. - -.. code-block:: terminal - - Commit received, starting build of branch master - - ––––––––––––––––––––––– ∙ƒ ––––––––––––––––––––––– - - B U I L D - - Checksum: - def1bb29911a62de26b1ddac6ef97fc76a5c647b - - Deployment file: - fortrabbit.yml - - Pre-script: - not found - 0ms - - Composer: - - - - - Loading composer repositories with package information - Installing dependencies (including require-dev) from lock file - Nothing to install or update - Generating autoload files - - - - - - 172ms - - Post-script: - not found - 0ms - - R E L E A S E - - Packaging: - 930ms - - Revision: - 1455788127289043421.def1bb29911a62de26b1ddac6ef97fc76a5c647b - - Size: - 9.7MB - - Uploading: - 500ms - - Build & release done in 1625ms, now queued for final distribution. - - -.. note:: - - The first ``git push`` takes much longer as all composer dependencies get - downloaded. All subsequent deploys are done within seconds. - -That's it! Your application is being deployed on fortrabbit. More information -about `database migrations and tunneling`_ can be found in the fortrabbit -documentation. - -.. _`fortrabbit`: https://www.fortrabbit.com -.. _`Symfony install guide`: https://help.fortrabbit.com/install-symfony -.. _`fortrabbit.yml`: https://help.fortrabbit.com/deployment-file-v2 -.. _`database migrations and tunneling`: https://help.fortrabbit.com/install-symfony-2#toc-migrate-amp-other-database-commands -.. _`Sign up`: https://dashboard.fortrabbit.com +.. _`Install Symfony`: https://help.fortrabbit.com/install-symfony-3-uni diff --git a/deployment/heroku.rst b/deployment/heroku.rst index d34024af5f3..d4827b12930 100644 --- a/deployment/heroku.rst +++ b/deployment/heroku.rst @@ -4,328 +4,7 @@ Deploying to Heroku Cloud ========================= -This step by step article describes how to deploy a Symfony web application to -the Heroku cloud platform. Its contents are based on `the original article`_ -published by Heroku. +To deploy to Heroku, see their official documentation: +`Getting Started with Symfony on Heroku`_. -Setting up ----------- - -To set up a new Heroku website, first `sign up with Heroku`_ or sign in -with your credentials. Then download and install the `Heroku Toolbelt`_ on your -local computer. - -You can also check out the `getting Started with PHP on Heroku`_ guide to gain -more familiarity with the specifics of working with PHP applications on Heroku. - -Preparing your Application -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Deploying a Symfony application to Heroku doesn't require any change in its -code, but it requires some minor tweaks to its configuration. - -By default, the Symfony app will log into your application's ``var/log/`` -directory. This is not ideal as Heroku uses an `ephemeral file system`_. On -Heroku, the best way to handle logging is using `Logplex`_. And the best way to -send log data to Logplex is by writing to ``STDERR`` or ``STDOUT``. Luckily, -Symfony uses the excellent Monolog library for logging. So, a new log -destination is just a change to a config file away. - -Open the ``app/config/config_prod.yml`` file, locate the -``monolog/handlers/nested`` section (or create it if it doesn't exist yet) and -change the value of ``path`` from -``"%kernel.logs_dir%/%kernel.environment%.log"`` to ``"php://stderr"``: - -.. code-block:: yaml - - # app/config/config_prod.yml - monolog: - # ... - handlers: - # ... - nested: - # ... - path: 'php://stderr' - -Once the application is deployed, run ``heroku logs --tail`` to keep the -stream of logs from Heroku open in your terminal. - -Creating a new Application on Heroku ------------------------------------- - -To create a new Heroku application that you can push to, use the CLI ``create`` -command: - -.. code-block:: terminal - - $ heroku create - - Creating mighty-hamlet-1981 in organization heroku... done, stack is cedar - http://mighty-hamlet-1981.herokuapp.com/ | git@heroku.com:mighty-hamlet-1981.git - Git remote heroku added - -You are now ready to deploy the application as explained in the next section. - -Deploying your Application on Heroku ------------------------------------- - -Before your first deploy, you need to do just three more things, which are explained -below: - -#. :ref:`Create a Procfile ` - -#. :ref:`Set the Environment to prod ` - -#. :ref:`Push your Code to Heroku ` - -.. _heroku-procfile: -.. _creating-a-procfile: - -1) Create a Procfile -~~~~~~~~~~~~~~~~~~~~ - -By default, Heroku will launch an Apache web server together with PHP to serve -applications. However, a special circumstance apply to Symfony applications: -the document root is in the ``public/`` directory and not in the root directory -of the application. - -Create a new file called ``Procfile`` (without any extension) at the root -directory of the application and add just the following content: - -.. code-block:: text - - web: vendor/bin/heroku-php-apache2 public/ - -.. note:: - - If you prefer to use Nginx, which is also available on Heroku, you can create - a configuration file for it and point to it from your Procfile as described - in the `Heroku documentation`_: - - .. code-block:: text - - web: vendor/bin/heroku-php-nginx -C nginx_app.conf public/ - -If you prefer working on the command console, execute the following commands to -create the ``Procfile`` file and to add it to the repository: - -.. code-block:: terminal - - $ echo "web: vendor/bin/heroku-php-apache2 public/" > Procfile - $ git add . - $ git commit -m "Procfile for Apache and PHP" - [master 35075db] Procfile for Apache and PHP - 1 file changed, 1 insertion(+) - -.. _heroku-setting-env-to-prod: -.. _setting-the-prod-environment: - -2) Set the Environment to prod -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -During a deployment, Heroku runs ``composer install --no-dev`` to install all the -dependencies your application requires. However, typical `post-install-commands`_ -in ``composer.json``, e.g. to install assets or clear (or pre-warm) caches, run -using Symfony's ``dev`` environment by default. - -This is clearly not what you want - the app runs in "production" (even if you -use it just for an experiment, or as a staging environment), and so any build -steps should use the same ``prod`` environment as well. - -Thankfully, the solution to this problem is very simple: Symfony will pick up an -environment variable named ``SYMFONY_ENV`` and use that environment if nothing -else is explicitly set. As Heroku exposes all `config vars`_ as environment -variables, you can issue a single command to prepare your app for a deployment: - -.. code-block:: terminal - - $ heroku config:set SYMFONY_ENV=prod - -.. caution:: - - Be aware that dependencies from ``composer.json`` listed in the ``require-dev`` - section are never installed during a deploy on Heroku. This may cause problems - if your Symfony environment relies on such packages. The solution is to move these - packages from ``require-dev`` to the ``require`` section. - -.. _heroku-push-code: -.. _pushing-to-heroku: - -3) Push your Code to Heroku -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Next up, it's finally time to deploy your application to Heroku. If you are -doing this for the very first time, you may see a message such as the following: - -.. code-block:: text - - The authenticity of host 'heroku.com (50.19.85.132)' can't be established. - RSA key fingerprint is 8b:48:5e:67:0e:c9:16:47:32:f2:87:0c:1f:c8:60:ad. - Are you sure you want to continue connecting (yes/no)? - -In this case, you need to confirm by typing ``yes`` and hitting ```` key -- ideally after you've `verified that the RSA key fingerprint is correct`_. - -Then, deploy your application executing this command: - -.. code-block:: terminal - - $ git push heroku master - - Initializing repository, done. - Counting objects: 130, done. - Delta compression using up to 4 threads. - Compressing objects: 100% (107/107), done. - Writing objects: 100% (130/130), 70.88 KiB | 0 bytes/s, done. - Total 130 (delta 17), reused 0 (delta 0) - - -----> PHP app detected - - -----> Setting up runtime environment... - - PHP 5.5.12 - - Apache 2.4.9 - - Nginx 1.4.6 - - -----> Installing PHP extensions: - - opcache (automatic; bundled, using 'ext-opcache.ini') - - -----> Installing dependencies... - Composer version 64ac32fca9e64eb38e50abfadc6eb6f2d0470039 2014-05-24 20:57:50 - Loading composer repositories with package information - Installing dependencies from lock file - - ... - - Generating optimized autoload files - Creating the "app/config/parameters.yml" file - Clearing the cache for the dev environment with debug true - Installing assets using the hard copy option - Installing assets for Symfony\Bundle\FrameworkBundle into public/bundles/framework - Installing assets for Acme\DemoBundle into public/bundles/acmedemo - Installing assets for Sensio\Bundle\DistributionBundle into public/bundles/sensiodistribution - - -----> Building runtime environment... - - -----> Discovering process types - Procfile declares types -> web - - -----> Compressing... done, 61.5MB - - -----> Launching... done, v3 - http://mighty-hamlet-1981.herokuapp.com/ deployed to Heroku - - To git@heroku.com:mighty-hamlet-1981.git - * [new branch] master -> master - -And that's it! If you now open your browser, either by manually pointing -it to the URL ``heroku create`` gave you, or by using the Heroku Toolbelt, the -application will respond: - -.. code-block:: terminal - - $ heroku open - Opening mighty-hamlet-1981... done - -You should be seeing your Symfony application in your browser. - -.. caution:: - - If you take your first steps on Heroku using a fresh installation of - the Symfony Standard Edition, you may run into a 404 page not found error. - This is because the route for ``/`` is defined by the AcmeDemoBundle, but the - AcmeDemoBundle is only loaded in the dev environment (check out your - ``AppKernel`` class). Try opening ``/app/example`` from the AppBundle. - -Custom Compile Steps -~~~~~~~~~~~~~~~~~~~~ - -If you wish to execute additional custom commands during a build, you can leverage -Heroku's `custom compile steps`_. Imagine you want to remove the ``dev`` front controller -from your production environment on Heroku in order to avoid a potential vulnerability. -Adding a command to remove ``public/index.php`` to Composer's `post-install-commands`_ would -work, but it also removes the controller in your local development environment on each -``composer install`` or ``composer update`` respectively. Instead, you can add a -`custom Composer command`_ named ``compile`` (this key name is a Heroku convention) to the -``scripts`` section of your ``composer.json``. The listed commands hook into Heroku's deploy -process: - -.. code-block:: json - - { - "scripts": { - "compile": [ - "rm public/index.php" - ] - } - } - -This is also very useful to build assets on the production system, e.g. with Assetic: - -.. code-block:: json - - { - "scripts": { - "compile": [ - "bin/console assetic:dump" - ] - } - } - -.. sidebar:: Node.js Dependencies - - Building assets may depend on node packages, e.g. ``uglifyjs`` or ``uglifycss`` - for asset minification. Installing node packages during the deploy requires a node - installation. But currently, Heroku compiles your app using the PHP buildpack, which - is auto-detected by the presence of a ``composer.json`` file, and does not include a - node installation. Because the Node.js buildpack has a higher precedence than the PHP - buildpack (see `Heroku buildpacks`_), adding a ``package.json`` listing your node - dependencies makes Heroku opt for the Node.js buildpack instead: - - .. code-block:: json - - { - "name": "myApp", - "engines": { - "node": "0.12.x" - }, - "dependencies": { - "uglifycss": "*", - "uglify-js": "*" - } - } - - With the next deploy, Heroku compiles your app using the Node.js buildpack and - your npm packages become installed. On the other hand, your ``composer.json`` is - now ignored. To compile your app with both buildpacks, Node.js *and* PHP, you need - to use both buildpacks. To override buildpack auto-detection, you - need to explicitly set the buildpack: - - .. code-block:: terminal - - $ heroku buildpacks:set heroku/nodejs - Buildpack set. Next release on your-application will use heroku/nodejs. - Run git push heroku master to create a new release using this buildpack. - $ heroku buildpacks:set heroku/php --index 2 - Buildpack set. Next release on your-application will use: - 1. heroku/nodejs - 2. heroku/php - Run git push heroku master to create a new release using these buildpacks. - - With the next deploy, you can benefit from both buildpacks. This setup also enables - your Heroku environment to make use of node based automatic build tools like - `Grunt`_ or `gulp`_. - -.. _`the original article`: https://devcenter.heroku.com/articles/getting-started-with-symfony2 -.. _`sign up with Heroku`: https://signup.heroku.com/signup/dc -.. _`Heroku Toolbelt`: https://devcenter.heroku.com/articles/getting-started-with-php#set-up -.. _`getting Started with PHP on Heroku`: https://devcenter.heroku.com/articles/getting-started-with-php -.. _`ephemeral file system`: https://devcenter.heroku.com/articles/dynos#ephemeral-filesystem -.. _`Logplex`: https://devcenter.heroku.com/articles/logplex -.. _`verified that the RSA key fingerprint is correct`: https://devcenter.heroku.com/articles/git-repository-ssh-fingerprints -.. _`post-install-commands`: https://getcomposer.org/doc/articles/scripts.md -.. _`config vars`: https://devcenter.heroku.com/articles/config-vars -.. _`custom compile steps`: https://devcenter.heroku.com/articles/php-support#custom-compile-step -.. _`custom Composer command`: https://getcomposer.org/doc/articles/scripts.md#writing-custom-commands -.. _`Heroku buildpacks`: https://devcenter.heroku.com/articles/buildpacks -.. _`Grunt`: http://gruntjs.com -.. _`gulp`: http://gulpjs.com -.. _`Heroku documentation`: https://devcenter.heroku.com/articles/custom-php-settings#nginx +.. _`Getting Started with Symfony on Heroku`: https://devcenter.heroku.com/articles/getting-started-with-symfony diff --git a/deployment/platformsh.rst b/deployment/platformsh.rst index 6d9d622a714..3eafcbc6af7 100644 --- a/deployment/platformsh.rst +++ b/deployment/platformsh.rst @@ -4,193 +4,7 @@ Deploying to Platform.sh ======================== -This step-by-step article describes how to deploy a Symfony web application to -`Platform.sh`_. You can read more about using Symfony with Platform.sh on the -official `Platform.sh documentation`_. +To deploy to Platform.sh, see their official documentation: +`Symfony Platform.sh Documentation`_. -Deploy an Existing Site ------------------------ - -In this guide, it is assumed your codebase is already versioned with Git. - -Get a Project on Platform.sh -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You need to `subscribe to a Platform.sh plan`_ and go through the checkout process. -Once your project is ready, give it a name and choose: **Import an existing site**. - -Prepare Your Application -~~~~~~~~~~~~~~~~~~~~~~~~ - -To deploy your Symfony application on Platform.sh, you simply need to add a -``.platform.app.yaml`` at the root of your Git repository which will tell -Platform.sh how to deploy your application (read more about -`Platform.sh configuration files`_). - -.. code-block:: yaml - - # .platform.app.yaml - - # This file describes an application. You can have multiple applications - # in the same project. - - # The name of this app. Must be unique within a project. - name: myphpproject - - # The type of the application to build. - type: php:5.6 - build: - flavor: composer - - # The relationships of the application with services or other applications. - # The left-hand side is the name of the relationship as it will be exposed - # to the application in the PLATFORM_RELATIONSHIPS variable. The right-hand - # side is in the form `:`. - relationships: - database: 'mysql:mysql' - - # The configuration of app when it is exposed to the web. - web: - # The public directory of the app, relative to its root. - document_root: '/web' - # The front-controller script to send non-static requests to. - passthru: '/index.php' - - # The size of the persistent disk of the application (in MB). - disk: 2048 - - # The mounts that will be performed when the package is deployed. - mounts: - '/var/cache': 'shared:files/cache' - '/var/log': 'shared:files/log' - '/var/sessions': 'shared:files/sessions' - - # The hooks that will be performed when the package is deployed. - hooks: - build: | - rm public/index.php - bin/console --env=prod assetic:dump --no-debug - deploy: | - bin/console --env=prod cache:clear - -For best practices, you should also add a ``.platform`` folder at the root of -your Git repository which contains the following files: - -.. code-block:: yaml - - # .platform/routes.yaml - "http://{default}/": - type: upstream - # the first part should be your project name - upstream: 'myphpproject:php' - -.. code-block:: yaml - - # .platform/services.yaml - mysql: - type: mysql - disk: 2048 - -An example of these configurations can be found on `GitHub`_. The list of -`available services`_ can be found on the Platform.sh documentation. - -Configure Database Access -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Platform.sh overrides your database specific configuration via importing the -following file (it's your role to add this file to your code base):: - - // app/config/parameters_platform.php - setParameter('database_driver', 'pdo_' . $endpoint['scheme']); - $container->setParameter('database_host', $endpoint['host']); - $container->setParameter('database_port', $endpoint['port']); - $container->setParameter('database_name', $endpoint['path']); - $container->setParameter('database_user', $endpoint['username']); - $container->setParameter('database_password', $endpoint['password']); - $container->setParameter('database_path', ''); - } - - # Store session into /tmp. - ini_set('session.save_path', '/tmp/sessions'); - -Make sure this file is listed in your *imports* (after the default ``parameters.yml`` -file): - -.. code-block:: yaml - - # app/config/config.yml - imports: - - { resource: parameters.yml } - - { resource: parameters_platform.php } - -Deploy your Application -~~~~~~~~~~~~~~~~~~~~~~~ - -Now you need to add a remote to Platform.sh in your Git repository (copy the -command that you see on the Platform.sh web UI): - -.. code-block:: terminal - - $ git remote add platform [PROJECT-ID]@git.[CLUSTER].platform.sh:[PROJECT-ID].git - -``PROJECT-ID`` - Unique identifier of your project. Something like ``kjh43kbobssae`` -``CLUSTER`` - Server location where your project is deployed. It can be ``eu`` or ``us`` - -Commit the Platform.sh specific files created in the previous section: - -.. code-block:: terminal - - $ git add .platform.app.yaml .platform/* - $ git add app/config/config.yml app/config/parameters_platform.php - $ git commit -m "Adding Platform.sh configuration files." - -Push your code base to the newly added remote: - -.. code-block:: terminal - - $ git push platform master - -That's it! Your application is being deployed on Platform.sh and you'll soon be -able to access it in your browser. - -Every code change that you do from now on will be pushed to Git in order to -redeploy your environment on Platform.sh. - -More information about `migrating your database and files`_ can be found -on the Platform.sh documentation. - -Deploy a new Site ------------------ - -You can start a new `Platform.sh project`_. Choose the development plan and go -through the checkout process. - -Once your project is ready, give it a name and choose: **Create a new site**. -Choose the *Symfony* stack and a starting point such as *Standard*. - -That's it! Your Symfony application will be bootstrapped and deployed. You'll -soon be able to see it in your browser. - -.. _`Platform.sh`: https://platform.sh -.. _`Platform.sh documentation`: https://docs.platform.sh/frameworks/symfony.html -.. _`Platform.sh project`: https://accounts.platform.sh/platform/buy-now -.. _`subscribe to a Platform.sh plan`: https://accounts.platform.sh/platform/buy-now -.. _`Platform.sh configuration files`: https://docs.platform.sh/configuration/services.html -.. _`GitHub`: https://github.com/platformsh/platformsh-examples -.. _`available services`: https://docs.platform.sh/reference/configuration-files/#configure-services -.. _`migrating your database and files`: https://docs.platform.sh/tutorials/migrating.html +.. _`Symfony Platform.sh Documentation`: https://docs.platform.sh/frameworks/symfony.html From 0941a4915178431ac5a0c94821a7050aa8cc2502 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 13:50:58 -0500 Subject: [PATCH 0101/2437] tweak --- security/acl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/acl.rst b/security/acl.rst index 9ca61e27b3b..ffbf16c7c27 100644 --- a/security/acl.rst +++ b/security/acl.rst @@ -9,7 +9,7 @@ How to Use Access Control Lists (ACLs) ACL support was removed in Symfony 4.0. Install the `Symfony ACL bundle`_ and refer to its documentation if you want to keep using ACL. - Alternatively, consider using :doc:`security voters `, + Consider using :doc:`security voters `, the alternative to ACLs recommended by Symfony. .. _`Symfony ACL bundle`: https://github.com/symfony/acl-bundle From 6e8f7630af24126bd08bde5282df8b387cee5a7b Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 13:51:09 -0500 Subject: [PATCH 0102/2437] tweak --- security/acl_advanced.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/acl_advanced.rst b/security/acl_advanced.rst index de67c9b43e0..ed4b5a5c07a 100644 --- a/security/acl_advanced.rst +++ b/security/acl_advanced.rst @@ -9,7 +9,7 @@ How to Use advanced ACL Concepts ACL support was removed in Symfony 4.0. Install the `Symfony ACL bundle`_ and refer to its documentation if you want to keep using ACL. - Alternatively, consider using :doc:`security voters `, + Consider using :doc:`security voters `, the alternative to ACLs recommended by Symfony. .. _`Symfony ACL bundle`: https://github.com/symfony/acl-bundle From 090e6ad69906f79861cfd41387146235e68bf5ed Mon Sep 17 00:00:00 2001 From: Wouter J Date: Fri, 3 Nov 2017 15:37:19 +0100 Subject: [PATCH 0103/2437] Updated main configuration guide to Flex --- configuration.rst | 364 +++++++++++++--------------------------------- 1 file changed, 99 insertions(+), 265 deletions(-) diff --git a/configuration.rst b/configuration.rst index 1b120db7e1a..b3251d3b600 100644 --- a/configuration.rst +++ b/configuration.rst @@ -6,92 +6,72 @@ Configuring Symfony (and Environments) Every Symfony application consists of a collection of bundles that add useful tools (:doc:`services `) to your project. Each bundle can be customized -via configuration files that live - by default - in the ``app/config`` directory. +via configuration files that live - by default - in the ``config/`` directory. -Configuration: config.yml -------------------------- +Configuration: config/packages/ +------------------------------- -The main configuration file is called ``config.yml``: +The configuration for each package can be found in ``config/packages/``. For +instance, the framework package is configured in ``config/packages/framework.yaml``: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml - imports: - - { resource: parameters.yml } - - { resource: security.yml } - - { resource: services.yml } - + # config/packages/framework.yaml framework: - secret: '%secret%' - router: { resource: '%kernel.project_dir%/app/config/routing.yml' } - # ... - - # Twig Configuration - twig: - debug: '%kernel.debug%' - strict_variables: '%kernel.debug%' - - # ... + secret: '%env(APP_SECRET)%' + #default_locale: en + #csrf_protection: ~ + #http_method_override: true + #trusted_hosts: ~ + # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id + #session: + # # The native PHP session handler will be used + # handler_id: ~ + #esi: ~ + #fragments: ~ + php_errors: + log: true .. code-block:: xml - - - - - - - - - - - - - - - - - - - - + + + + + + + .. code-block:: php - // app/config/config.php - $this->import('parameters.yml'); - $this->import('security.yml'); - $this->import('services.yml'); - - $container->loadFromExtension('framework', array( - 'secret' => '%secret%', - 'router' => array( - 'resource' => '%kernel.project_dir%/app/config/routing.php', - ), - // ... - )); - - // Twig Configuration - $container->loadFromExtension('twig', array( - 'debug' => '%kernel.debug%', - 'strict_variables' => '%kernel.debug%', - )); - - // ... - -Most top-level keys - like ``framework`` and ``twig`` - are configuration for a -specific bundle (i.e. ``FrameworkBundle`` and ``TwigBundle``). + # config/packages/framework.php + $container->loadFromExtension('framework', [ + 'secret' => '%env(APP_SECRET)%', + //'default_locale' => 'en', + //'csrf_protection' => null, + //'http_method_override' => true, + //'trusted_hosts' => null, + // https://symfony.com/doc/current/reference/configuration/framework.html#handler-id + //'session' => [ + // // The native PHP session handler will be used + // 'handler_id' => null, + //], + //'esi' => null, + //'fragments' => null, + 'php_errors' => [ + 'log' => true, + ], + ]); + +The top-level key (here ``framework``) references configuration for a specific +bundle (``FrameworkBundle`` in this case). .. sidebar:: Configuration Formats @@ -100,9 +80,7 @@ specific bundle (i.e. ``FrameworkBundle`` and ``TwigBundle``). choose whatever you like best. There is no performance difference: * :doc:`/components/yaml/yaml_format`: Simple, clean and readable; - * *XML*: More powerful than YAML at times & supports IDE autocompletion; - * *PHP*: Very powerful but less readable than standard configuration formats. Configuration Reference & Dumping @@ -111,15 +89,14 @@ Configuration Reference & Dumping There are *two* ways to know *what* keys you can configure: #. Use the :doc:`Reference Section `; - #. Use the ``config:dump-reference`` command. -For example, if you want to configure something in Twig, you can see an example +For example, if you want to configure something in Framework, you can see an example dump of all available configuration options by running: .. code-block:: terminal - $ php bin/console config:dump-reference twig + $ php bin/console config:dump-reference framework .. index:: single: Environments; Introduction @@ -127,127 +104,68 @@ dump of all available configuration options by running: .. _page-creation-environments: .. _page-creation-prod-cache-clear: -The imports Key: Loading other Configuration Files --------------------------------------------------- +.. _config-parameter-intro: + +The parameters Key: Parameters (Variables) +------------------------------------------ -Symfony's main configuration file is ``app/config/config.yml``. But, for organization, -it *also* loads other configuration files via its ``imports`` key: +The configuration has some special top-level keys. One of them is called +``parameters``: it's used to define *variables* that can be referenced in *any* +other configuration file. For example, when you install the *translation* +package, a ``locale`` parameter is added to ``config/services.yaml``: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml - imports: - - { resource: parameters.yml } - - { resource: security.yml } - - { resource: services.yml } + # config/services.yaml + parameters: + locale: en + # ... .. code-block:: xml - + + http://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony + http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - - - - + + en + .. code-block:: php - // app/config/config.php - $this->import('parameters.yml'); - $this->import('security.yml'); - $this->import('services.yml'); - + // config/services.php + $container->setParameter('locale', 'en'); // ... -The ``imports`` key works a lot like the PHP ``include()`` function: the contents of -``parameters.yml``, ``security.yml`` and ``services.yml`` are read and loaded. You -can also load XML files or PHP files. - -.. tip:: - - If your application uses unconventional file extensions (for example, your - YAML files have a ``.res`` extension) you can set the file type explicitly - with the ``type`` option: - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - imports: - - { resource: parameters.res, type: yml } - # ... - - .. code-block:: xml - - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $this->import('parameters.res', 'yml'); - // ... - -.. _config-parameter-intro: - -The parameters Key: Parameters (Variables) ------------------------------------------- - -Another special key is called ``parameters``: it's used to define *variables* that -can be referenced in *any* other configuration file. For example, in ``config.yml``, -a ``locale`` parameter is defined and then referenced below under the ``framework`` -key: +This parameter is then referenced in the framework config in +``config/packages/translation.yaml``: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml - # ... - - parameters: - locale: en - + # config/packages/translation.yaml framework: - # ... - # any string surrounded by two % is replaced by that parameter value - default_locale: "%locale%" + default_locale: '%locale%' - # ... + # ... .. code-block:: xml - + - - - en - - + - - .. code-block:: php - // app/config/config.php - // ... - - $container->setParameter('locale', 'en'); - + // config/packages/translation.php $container->loadFromExtension('framework', array( + // any string surrounded by two % is replaced by that parameter value 'default_locale' => '%locale%', + // ... )); - // ... - You can define whatever parameter names you want under the ``parameters`` key of any configuration file. To reference a parameter, surround its name with two percent signs - e.g. ``%locale%``. @@ -296,6 +204,7 @@ For more information about parameters - including how to reference them from ins a controller - see :ref:`service-container-parameters`. .. _config-dot-env: +.. _config-parameters-yml: The .env File ~~~~~~~~~~~~~ @@ -304,93 +213,18 @@ There is also a ``.env`` file which is loaded. Its contents become environment v in the dev environment, making it easier to reference environment variables in your code. -.. _config-parameters-yml: - -The Special parameters.yml File -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -On the surface, ``parameters.yml`` is just like any other configuration file: it -is imported by ``config.yml`` and defines several parameters: - -.. code-block:: yaml - - parameters: - # ... - database_user: root - database_password: ~ - -Not surprisingly, these are referenced from inside of ``config.yml`` and help to -configure DoctrineBundle and other parts of Symfony: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - doctrine: - dbal: - driver: pdo_mysql - # ... - user: '%database_user%' - password: '%database_password%' - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('doctrine', array( - 'dbal' => array( - 'driver' => 'pdo_mysql', - // ... - - 'user' => '%database_user%', - 'password' => '%database_password%', - ), - )); - -But the ``parameters.yml`` file *is* special: it defines the values that usually -change on each server. For example, the database credentials on your local -development machine might be different from your workmates. That's why this file -is not committed to the shared repository and is only stored on your machine. - -Because of that, **parameters.yml is not committed to your version control**. In fact, -the ``.gitignore`` file that comes with Symfony prevents it from being committed. - -However, a ``parameters.yml.dist`` file *is* committed (with dummy values). This file -isn't read by Symfony: it's just a reference so that Symfony knows which parameters -need to be defined in the ``parameters.yml`` file. If you add or remove keys to -``parameters.yml``, add or remove them from ``parameters.yml.dist`` too so both -files are always in sync. - -.. sidebar:: The Interactive Parameter Handler - - When you :ref:`install an existing Symfony project `, you - will need to create the ``parameters.yml`` file using the committed ``parameters.yml.dist`` - file as a reference. To help with this, after you run ``composer install``, a - Symfony script will automatically create this file by interactively asking you - to supply the value for each parameter defined in ``parameters.yml.dist``. For - more details - or to remove or control this behavior - see the - `Incenteev Parameter Handler`_ documentation. +The ``.env`` file is special, because it defines the values that usually change +on each server. For example, the database credentials on your local development +machine might be different from your workmates. That's why this file is **not +committed to the shared repository** and is only stored on your machine. In +fact, the ``.gitignore`` file that comes with Symfony prevents it from being +committed. + +However, a ``.env.dist`` file *is* committed (with dummy values). This file +isn't read by Symfony: it's just a reference so that Symfony knows which +variables need to be defined in the ``.env`` file. If you add or remove keys to +``.env``, add or remove them from ``.env.dist`` too, so both files are always +in sync. Environments & the Other Config Files ------------------------------------- From f8baf09a9c483e417ff24503630dee8922562e51 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 21 Nov 2017 19:44:16 +0100 Subject: [PATCH 0104/2437] Some rewords --- configuration.rst | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/configuration.rst b/configuration.rst index b3251d3b600..3c5060ff7ad 100644 --- a/configuration.rst +++ b/configuration.rst @@ -4,15 +4,16 @@ Configuring Symfony (and Environments) ====================================== -Every Symfony application consists of a collection of bundles that add useful tools -(:doc:`services `) to your project. Each bundle can be customized -via configuration files that live - by default - in the ``config/`` directory. +Symfony applications can install third-party packages (bundles, libraries, etc.) +to bring in new features (:doc:`services `) to your project. +Each package can be customized via configuration files that live - by default - +in the ``config/`` directory. Configuration: config/packages/ ------------------------------- The configuration for each package can be found in ``config/packages/``. For -instance, the framework package is configured in ``config/packages/framework.yaml``: +instance, the framework bundle is configured in ``config/packages/framework.yaml``: .. configuration-block:: @@ -91,8 +92,8 @@ There are *two* ways to know *what* keys you can configure: #. Use the :doc:`Reference Section `; #. Use the ``config:dump-reference`` command. -For example, if you want to configure something in Framework, you can see an example -dump of all available configuration options by running: +For example, if you want to configure something related to the framework bundle, +you can see an example dump of all available configuration options by running: .. code-block:: terminal @@ -192,8 +193,8 @@ This parameter is then referenced in the framework config in )); You can define whatever parameter names you want under the ``parameters`` key of -any configuration file. To reference a parameter, surround its name with two percent -signs - e.g. ``%locale%``. +any configuration file. To reference a parameter, surround its name with two +percent signs - e.g. ``%locale%``. .. seealso:: @@ -209,9 +210,9 @@ a controller - see :ref:`service-container-parameters`. The .env File ~~~~~~~~~~~~~ -There is also a ``.env`` file which is loaded. Its contents become environment variables -in the dev environment, making it easier to reference environment variables in your -code. +There is also a ``.env`` file which is loaded. Its contents become environment +variables in the dev environment, making it easier to reference environment +variables in your code. The ``.env`` file is special, because it defines the values that usually change on each server. For example, the database credentials on your local development @@ -229,19 +230,20 @@ in sync. Environments & the Other Config Files ------------------------------------- -You have just *one* app, but whether you realize it or not, you need it to behave -*differently* at different times: +You have just *one* app, but whether you realize it or not, you need it to +behave *differently* at different times: -* While **developing**, you want your app to log everything and expose nice debugging - tools; +* While **developing**, you want your app to log everything and expose nice + debugging tools; -* After deploying to **production**, you want that *same* app to be optimized for - speed and only log errors. +* After deploying to **production**, you want that *same* app to be optimized + for speed and only log errors. -How can you make *one* application behave in two different ways? With *environments*. +How can you make *one* application behave in two different ways? With +*environments*. -You've probably already been using the ``dev`` environment without even knowing it. -After you deploy, you'll use the ``prod`` environment. +You've probably already been using the ``dev`` environment without even knowing +it. After you deploy, you'll use the ``prod`` environment. To learn more about *how* to execute and control each environment, see :doc:`/configuration/environments`. From 9a1695db267548dac8c9d5bebc46defc265b4f1e Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 14:09:09 -0500 Subject: [PATCH 0105/2437] linking to missing article --- deployment.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/deployment.rst b/deployment.rst index 9fff7ce5043..cbd39523fdf 100644 --- a/deployment.rst +++ b/deployment.rst @@ -237,6 +237,14 @@ kernel and return your project's root directory:: } } +Learn More +---------- + +.. toctree:: + :maxdepth: 1 + + deployment/proxies + .. _`Capifony`: https://github.com/everzet/capifony .. _`Capistrano`: http://capistranorb.com/ .. _`sf2debpkg`: https://github.com/liip/sf2debpkg From e15e2f320024a2ca97d5f0c5145ddb11191b1d5b Mon Sep 17 00:00:00 2001 From: Wouter J Date: Mon, 13 Nov 2017 23:10:37 +0100 Subject: [PATCH 0106/2437] Made two configuration sub guides flex-ready --- configuration/configuration_organization.rst | 9 +- configuration/environments.rst | 359 ++++++++---------- configuration/external_parameters.rst | 114 ++---- .../front_controllers_and_kernel.rst | 39 +- 4 files changed, 209 insertions(+), 312 deletions(-) diff --git a/configuration/configuration_organization.rst b/configuration/configuration_organization.rst index 5c22dfc2572..2bb3cbba181 100644 --- a/configuration/configuration_organization.rst +++ b/configuration/configuration_organization.rst @@ -4,10 +4,9 @@ How to Organize Configuration Files =================================== -The default Symfony Standard Edition defines three -:doc:`execution environments ` called -``dev``, ``prod`` and ``test``. An environment simply represents a way to -execute the same codebase with different configurations. +The Symfony skeleton defines three :doc:`execution environments ` +called ``dev``, ``prod`` and ``test``. An environment simply represents a way +to execute the same codebase with different configurations. In order to select the configuration file to load for each environment, Symfony executes the ``registerContainerConfiguration()`` method of the ``AppKernel`` @@ -17,7 +16,7 @@ class:: use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\Config\Loader\LoaderInterface; - class AppKernel extends Kernel + class Kernel extends BaseKernel { // ... diff --git a/configuration/environments.rst b/configuration/environments.rst index c90657f630f..df77a79b73d 100644 --- a/configuration/environments.rst +++ b/configuration/environments.rst @@ -20,128 +20,58 @@ Different Environments, different Configuration Files ----------------------------------------------------- A typical Symfony application begins with three environments: ``dev``, -``prod``, and ``test``. As mentioned, each environment simply represents -a way to execute the same codebase with different configuration. It should -be no surprise then that each environment loads its own individual configuration -file. If you're using the YAML configuration format, the following files -are used: +``prod`` and ``test``. As mentioned, each environment represents a way to +execute the same codebase with different configuration. It should be no +surprise then that each environment loads its own individual configuration +files. These different files are organized by environment: -* for the ``dev`` environment: ``app/config/config_dev.yml`` -* for the ``prod`` environment: ``app/config/config_prod.yml`` -* for the ``test`` environment: ``app/config/config_test.yml`` +* for the ``dev`` environment: ``config/packages/dev/`` +* for the ``prod`` environment: ``config/packages/prod/`` +* for the ``test`` environment: ``config/packages/test/`` -This works via a simple standard that's used by default inside the ``AppKernel`` -class: +In reality, each environment differs only somewhat from others. This means that +all environments share a large base of common configurations. This configuration +is put in files directly in the ``config/packages/`` directory. -.. code-block:: php +The location of these files is defined by the application's Kernel:: - // app/AppKernel.php + // src/Kernel.php // ... - - class AppKernel extends Kernel + class Kernel extends BaseKernel { // ... - public function registerContainerConfiguration(LoaderInterface $loader) + protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader) { - $loader->load($this->getProjectDir().'/app/config/config_'.$this->getEnvironment().'.yml'); - } - } - -As you can see, when Symfony is loaded, it uses the given environment to -determine which configuration file to load. This accomplishes the goal of -multiple environments in an elegant, powerful and transparent way. - -Of course, in reality, each environment differs only somewhat from others. -Generally, all environments will share a large base of common configuration. -Opening the ``config_dev.yml`` configuration file, you can see how this is -accomplished easily and transparently: - -.. configuration-block:: - - .. code-block:: yaml - - imports: - - { resource: config.yml } - - # ... - - .. code-block:: xml - - - - - - - - - - - - - .. code-block:: php - - $loader->import('config.php'); - - // ... - -To share common configuration, each environment's configuration file -simply first imports from a central configuration file (``config.yml``). -The remainder of the file can then deviate from the default configuration -by overriding individual parameters. For example, by default, the ``web_profiler`` -toolbar is disabled. However, in the ``dev`` environment, the toolbar is -activated by modifying the value of the ``toolbar`` option in the ``config_dev.yml`` -configuration file: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config_dev.yml - imports: - - { resource: config.yml } - - web_profiler: - toolbar: true - # ... - - .. code-block:: xml - - - - - - - - + // ... + $confDir = $this->getProjectDir().'/config'; - + // always load all files in /config/packages/ + $loader->load($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob'); - + // then, if available, load the files in the specific environment directory + if (is_dir($confDir.'/packages/'.$this->environment)) { + $loader->load($confDir.'/packages/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); + } - .. code-block:: php - - // app/config/config_dev.php - $loader->import('config.php'); + // load a special services.(yaml/xml/php) and, if available, services_ENVIRONMENT.(yaml/xml/php) file + $loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/services_'.$this->environment.self::CONFIG_EXTS, 'glob'); + } + } - $container->loadFromExtension('web_profiler', array( - 'toolbar' => true, +Take the framework package, installed by default, as an example: - // ... - )); +* Loaded in all environments, ``config/packages/framework.yaml`` configures the + framework with some ``secret`` setting; +* In the **prod** environment, nothing extra will be set as there is no + ``config/packages/prod/`` directory; +* The same applies to **dev**, as there is no + ``config/packages/framework.yaml``. There are however other packages (e.g. + ``routing.yaml``) with special dev settings; +* At last, during the **test** environment, the framework's test features are + enabled in ``config/packages/test/framework.yaml``. .. index:: single: Environments; Executing different environments @@ -149,77 +79,77 @@ configuration file: Executing an Application in different Environments -------------------------------------------------- -To execute the application in each environment, load up the application using -either ``app.php`` (for the ``prod`` environment) or ``app_dev.php`` -(for the ``dev`` environment) front controller: +To execute the application in each environment, change the ``APP_ENV`` +environment variable. During development, this is done in ``.env``: -.. code-block:: text +.. code-block:: bash + + # .env + APP_ENV=dev + + # or for test: + #APP_ENV=test - http://localhost/app.php -> *prod* environment - http://localhost/app_dev.php -> *dev* environment +Visit the ``http://localhost:8000/index.php`` page in your web browser to see +your application in the configured environment. -If you don't have *either* filename in your URL, then it's up to your web server -to decide *which* file to execute behind the scenes. If you're using the built-in -PHP web server, it knows to use the ``app_dev.php`` file. On production, you'll -:doc:`configure your web server ` to use ``app.php``. -Either way: *one of these two files is always executed*. +.. tip:: + + In production, it is recommended to configure the environment variables in + your :ref:`web server configuration `. .. note:: - The given URLs assume that your web server is configured to use the ``web/`` - directory of the application as its root. Read more in - :doc:`Installing Symfony `. + The given URLs assume that your web server is configured to use the ``public/`` + directory of the application as its root. Read more in :doc:`Installing Symfony `. -If you open up one of these files, you'll quickly see that the environment -used by each is explicitly set:: +If you open the file you just visited (``public/index.php``), you'll see that +the environment variable is passed to the kernel:: - // web/app.php - // ... + // public/index.php - $kernel = new AppKernel('prod', false); + // ... + $kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', $_SERVER['APP_DEBUG'] ?? false); // ... -The ``prod`` key specifies that this application will run in the ``prod`` -environment. A Symfony application can be executed in any environment by using -this code and changing the environment string. +You can also replace ``$_SERVER['APP_ENV'] ?? 'dev'`` by just ``'dev'`` to +always run the application in the dev environment, independent of the +``APP_ENV`` variable. .. note:: The ``test`` environment is used when writing functional tests and is - not accessible in the browser directly via a front controller. In other - words, unlike the other environments, there is no ``app_test.php`` front - controller file. + usually not accessed in the browser directly via a front controller. .. index:: single: Configuration; Debug mode .. sidebar:: *Debug* Mode - Important, but unrelated to the topic of *environments* is the ``false`` - argument as the second argument to the ``AppKernel`` constructor. This - specifies if the application should run in "debug mode". Regardless - of the environment, a Symfony application can be run with debug mode - set to ``true`` or ``false``. This affects many things in the application, - such as displaying stacktraces on error pages or if cache files are - dynamically rebuilt on each request. Though not a requirement, debug mode - is generally set to ``true`` for the ``dev`` and ``test`` environments and - ``false`` for the ``prod`` environment. + Important, but unrelated to the topic of *environments* is the second + argument to the ``Kernel`` constructor. This specifies if the application + should run in "debug mode". Regardless of the environment, a Symfony + application can be run with debug mode set to ``true`` or ``false`` + (respectively ``1`` or ``0`` for the ``APP_ENV`` variable defined in + ``.env``). This affects many things in the application, such as displaying + stacktraces on error pages or if cache files are dynamically rebuilt on + each request. Though not a requirement, debug mode is generally set to + ``true`` for the ``dev`` and ``test`` environments and ``false`` for the + ``prod`` environment. Internally, the value of the debug mode becomes the ``kernel.debug`` parameter used inside the :doc:`service container `. If you look inside the application configuration file, you'll see the - parameter used, for example, to turn logging on or off when using the - Doctrine DBAL: + parameter used, for example, to turn Twig's debug mode on: .. configuration-block:: .. code-block:: yaml - doctrine: - dbal: - logging: '%kernel.debug%' - # ... + # config/packages/twig.yaml + twig: + debug: '%kernel.debug%' .. code-block:: xml @@ -229,20 +159,17 @@ this code and changing the environment string. xmlns:doctrine="http://symfony.com/schema/dic/doctrine" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd - http://symfony.com/schema/dic/doctrine - http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd"> + http://symfony.com/schema/dic/twig + http://symfony.com/schema/dic/twig/twig-1.0.xsd"> - + .. code-block:: php - $container->loadFromExtension('doctrine', array( - 'dbal' => array( - 'logging' => '%kernel.debug%', - // ... - ), + $container->loadFromExtension('twig', array( + 'debug' => '%kernel.debug%', // ... )); @@ -265,15 +192,8 @@ behavior: $ php bin/console command_name --env=test --no-debug In addition to the ``--env`` and ``--no-debug`` options, the behavior of Symfony -commands can also be controlled with environment variables. The Symfony console -application checks the existence and value of these environment variables before -executing any command: - -``SYMFONY_ENV`` - Sets the execution environment of the command to the value of this variable - (``dev``, ``prod``, ``test``, etc.); -``SYMFONY_DEBUG`` - If ``0``, debug mode is disabled. Otherwise, debug mode is enabled. +commands can also be controlled with the same environment variables used by +``public/index.php``. These environment variables are very useful for production servers because they allow you to ensure that commands always run in the ``prod`` environment without @@ -285,10 +205,8 @@ having to add any command option. Creating a new Environment -------------------------- -By default, a Symfony application has three environments that handle most -cases. Of course, since an environment is nothing more than a string that -corresponds to a set of configuration, creating a new environment is quite -easy. +Since an environment is nothing more than a string that corresponds to a set of +configuration, creating a new environment is quite easy. Suppose, for example, that before deployment, you need to benchmark your application. One way to benchmark the application is to use near-production @@ -296,22 +214,20 @@ settings, but with Symfony's ``web_profiler`` enabled. This allows Symfony to record information about your application while benchmarking. The best way to accomplish this is via a new environment called, for example, -``benchmark``. Start by creating a new configuration file: +``benchmark``. Start by creating a new configuration directory and a +configuration file: .. configuration-block:: .. code-block:: yaml - # app/config/config_benchmark.yml - imports: - - { resource: config_prod.yml } - + # config/packages/benchmark/web_profiler.yaml framework: profiler: { only_exceptions: false } .. code-block:: xml - + - - - - @@ -333,50 +245,77 @@ The best way to accomplish this is via a new environment called, for example, .. code-block:: php - // app/config/config_benchmark.php - $loader->import('config_prod.php'); - + // config/packages/benchmark/web_profiler.php $container->loadFromExtension('framework', array( 'profiler' => array('only_exceptions' => false), )); -.. include:: /components/dependency_injection/_imports-parameters-note.rst.inc +And... you're finished! The application now supports a new environment called +``benchmark``. -And with this simple addition, the application now supports a new environment -called ``benchmark``. +Change the ``APP_ENV`` variable to ``benchmark`` to be able to access the new +environment through your browser: -This new configuration file imports the configuration from the ``prod`` environment -and modifies it. This guarantees that the new environment is identical to -the ``prod`` environment, except for any changes explicitly made here. +.. code-block:: bash -Because you'll want this environment to be accessible via a browser, you -should also create a front controller for it. Copy the ``web/app.php`` file -to ``web/app_benchmark.php`` and edit the environment to be ``benchmark``:: + # .env + APP_ENV=benchmark - // web/app_benchmark.php - // ... +.. sidebar:: Importing configuration - // change just this line - $kernel = new AppKernel('benchmark', false); + Besides loading files in the Kernel, you can also import files in the + configuration directly. For instance, to make sure the benchmark + environment is identical to the prod environment, you might want to load + all its configuration as well. - // ... + You can achieve this by using a special ``imports`` key: -The new environment is now accessible via:: + .. configuration-block: - http://localhost/app_benchmark.php + .. code-block:: yaml -.. note:: + # config/packages/benchmark/other.yaml + imports: + - { resource: '../prod/' } - Some environments, like the ``dev`` environment, are never meant to be - accessed on any deployed server by the public. This is because - certain environments, for debugging purposes, may give too much information - about the application or underlying infrastructure. To be sure these environments - aren't accessible, the front controller is usually protected from external - IP addresses via the following code at the top of the controller:: + # other resources are possible as well, like importing other + # files or using globs: + #- { resource: '/etc/myapp/some_special_config.xml' } + #- { resource: '/etc/myapp/*.yaml' } - if (!in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))) { - die('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.'); - } + .. code-block:: xml + + + + + + + + + + + + + + .. code-block:: php + + // config/packages/benchmark/other.php + $loader->import('../prod/'); + + // other resources are possible as well, like importing other + // files or using globs: + //$loader->import('/etc/myapp/some_special_config.yaml'); + //$loader->import('/etc/myapp/*.php'); .. index:: single: Environments; Cache directory @@ -388,7 +327,7 @@ Symfony takes advantage of caching in many ways: the application configuration, routing configuration, Twig templates and more are cached to PHP objects stored in files on the filesystem. -By default, these cached files are largely stored in the ``var/cache`` directory. +By default, these cached files are largely stored in the ``var/cache/`` directory. However, each environment caches its own set of files: .. code-block:: text @@ -402,8 +341,8 @@ However, each environment caches its own set of files: Sometimes, when debugging, it may be helpful to inspect a cached file to understand how something is working. When doing so, remember to look in -the directory of the environment you're using (most commonly ``dev`` while -developing and debugging). While it can vary, the ``var/cache/dev`` directory +the directory of the environment you're using (most commonly ``dev/`` while +developing and debugging). While it can vary, the ``var/cache/dev/`` directory includes the following: ``appDevDebugProjectContainer.php`` diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 8788cb4c47c..a052cacd1e9 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -4,7 +4,7 @@ How to Set external Parameters in the Service Container ======================================================= -In the article :doc:`/configuration`, you learned how to manage your application +In :doc:`/configuration`, you learned how to manage your application configuration. At times, it may benefit your application to store certain credentials outside of your project code. Database configuration is one such example. The flexibility of the Symfony service container allows you to easily @@ -18,22 +18,30 @@ the variables you want to use enclosed between ``env()``. Their actual values will be resolved at runtime (once per request), so that dumped containers can be reconfigured dynamically even after being compiled. -For example, if you want to use the value of the ``DATABASE_HOST`` environment -variable in your service container configuration, you can reference it using -``%env(DATABASE_HOST)%`` in your configuration files: +For example, when installing the ``doctrine`` recipe, database configuration is +put in a ``DATABASE_URL`` environment variable: + +.. code-block:: bash + + # .env + DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" + +This variable is referenced in the service container configuration using +``%env(DATABASE_HOST)%``: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/doctrine.yaml doctrine: dbal: - host: '%env(DATABASE_HOST)%' + url: '%env(DATABASE_URL)%' + # ... .. code-block:: xml - + @@ -53,10 +61,10 @@ variable in your service container configuration, you can reference it using .. code-block:: php - // app/config/config.php + // config/packages/doctrine.php $container->loadFromExtension('doctrine', array( 'dbal' => array( - 'host' => '%env(DATABASE_HOST)%', + 'url' => '%env(DATABASE_URL)%', ) )); @@ -67,34 +75,37 @@ will be used whenever the corresponding environment variable is *not* found: .. code-block:: yaml - # app/config/parameters.yml + # config/services.yaml parameters: - database_host: '%env(DATABASE_HOST)%' env(DATABASE_HOST): localhost .. code-block:: xml - + - %env(DATABASE_HOST)% localhost .. code-block:: php - // app/config/parameters.php - $container->setParameter('database_host', '%env(DATABASE_HOST)%'); + // config/services.php $container->setParameter('env(DATABASE_HOST)', 'localhost'); -Setting environment variables is generally done at the web server level or in the -terminal. If you're using Apache, Nginx or just the console, you can use e.g. one -of the following: +.. _configuration-env-var-in-prod: + +Configuring Environment Variables in Production +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +During development, you'll use the ``.env`` file to configure your environment +variables. On your production server, it is recommended to configure these at +the web server level. If you're using Apache or Nginx, you can use e.g. one of +the following: .. configuration-block:: @@ -103,19 +114,12 @@ of the following: # ... - SetEnv DATABASE_USER user - SetEnv DATABASE_PASSWORD secret + SetEnv DATABASE_URL "mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" .. code-block:: nginx - fastcgi_param DATABASE_USER user; - fastcgi_param DATABASE_PASSWORD secret; - - .. code-block:: terminal - - $ export DATABASE_USER=user - $ export DATABASE_PASSWORD=secret + fastcgi_param DATABASE_URL "mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7"; .. tip:: @@ -135,53 +139,19 @@ See :ref:`component-di-parameters-constants` for more details. Miscellaneous Configuration --------------------------- -The ``imports`` directive can be used to pull in parameters stored elsewhere. -Importing a PHP file gives you the flexibility to add whatever is needed -in the container. The following imports a file named ``parameters.php``. - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - imports: - - { resource: parameters.php } - - .. code-block:: xml - - - - - - - - +You can mix whatever configuration format you like (YAML, XML and PHP) in +``config/packages/``. Importing a PHP file gives you the flexibility to add +whatever is needed in the container. For instance, you can create a +``drupal.php`` file in which you set a database URL based on Drupal's database +configuration:: - + // config/packages/drupal.php - .. code-block:: php - - // app/config/config.php - $loader->import('parameters.php'); - -.. note:: - - A resource file can be one of many types. PHP, XML, YAML, INI, and - closure resources are all supported by the ``imports`` directive. - -In ``parameters.php``, tell the service container the parameters that you wish -to set. This is useful when important configuration is in a non-standard -format. The example below includes a Drupal database configuration in -the Symfony service container. - -.. code-block:: php - - // app/config/parameters.php + // import Drupal's configuration include_once('/path/to/drupal/sites/default/settings.php'); - $container->setParameter('drupal.database.url', $db_url); + + // set a app.database_url parameter + $container->setParameter('app.database_url', $db_url); .. _`SetEnv`: http://httpd.apache.org/docs/current/env.html .. _`fastcgi_param`: http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_param diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index 54cab74072a..a5160a47108 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -27,16 +27,16 @@ three parts that work together: The Front Controller -------------------- -The `front controller`_ is a well-known design pattern; it is a section of -code that *all* requests served by an application run through. +The `front controller`_ is a design pattern; it is a section of code that *all* +requests served by an application run through. -In the `Symfony Standard Edition`_, this role is taken by the `index.php`_ file -in the ``public/`` directory. This is the very first PHP script executed when a +In the Symfony Skeleton, this role is taken by the `index.php`_ file in the +``public/`` directory. This is the very first PHP script executed when a request is processed. The main purpose of the front controller is to create an instance of the -``AppKernel`` (more on that in a second), make it handle the request -and return the resulting response to the browser. +``Kernel`` (more on that in a second), make it handle the request and return +the resulting response to the browser. Because every request is routed through it, the front controller can be used to perform global initialization prior to setting up the kernel or @@ -47,33 +47,23 @@ to `decorate`_ the kernel with additional features. Examples include: :ref:`AppCache `; * Enabling the :doc:`Debug Component `. -The front controller can be chosen by requesting URLs like: +You can choose the front controller that's used by adding it in the URL, like: .. code-block:: text - http://localhost/app_dev.php/some/path/... + http://localhost/index.php/some/path/... As you can see, this URL contains the PHP script to be used as the front -controller. You can use that to easily switch the front controller or use -a custom one by placing it in the ``web/`` directory (e.g. ``app_cache.php``). +controller. You can use that to easily switch to a custom made front controller +that is located in the ``public/`` directory or e.g. access the ``check.php`` +file. -When using Apache and the `RewriteRule shipped with the Symfony Standard Edition`_, -you can omit the filename from the URL and the RewriteRule will use ``app.php`` -as the default one. +.. seealso:: -.. note:: - - Pretty much every other web server should be able to achieve a - behavior similar to that of the RewriteRule described above. - Check your server documentation for details or see + You almost never want to show the front controller in the URL. This is + achieved by configuring the web server, as shown in :doc:`/setup/web_server_configuration`. -.. note:: - - Make sure you appropriately secure your front controllers against unauthorized - access. For example, you don't want to make a debugging environment - available to arbitrary users in your production environment. - Technically, the `bin/console`_ script used when running Symfony on the command line is also a front controller, only that is not used for web, but for command line requests. @@ -164,5 +154,4 @@ way of loading your configuration. .. _bin/console: https://github.com/symfony/symfony-standard/blob/master/bin/console .. _AppKernel: https://github.com/symfony/symfony-standard/blob/master/app/AppKernel.php .. _decorate: https://en.wikipedia.org/wiki/Decorator_pattern -.. _RewriteRule shipped with the Symfony Standard Edition: https://github.com/symfony/symfony-standard/blob/master/web/.htaccess .. _template methods: https://en.wikipedia.org/wiki/Template_method_pattern From 4f628d7959c12780697836076847fe192a63812c Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 14:55:49 -0500 Subject: [PATCH 0107/2437] adding other dirs --- setup/flex.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup/flex.rst b/setup/flex.rst index 4d88d5d3a7f..3608e79d1ab 100644 --- a/setup/flex.rst +++ b/setup/flex.rst @@ -137,6 +137,9 @@ following directory structure, which is the same used by default in Symfony 4: .. code-block:: text your-project/ + ├── assets/ + ├── bin/ + │   └── console ├── config/ │   ├── bundles.php │   ├── packages/ @@ -148,7 +151,9 @@ following directory structure, which is the same used by default in Symfony 4: │   ├── ... │   └── Kernel.php ├── templates/ + ├── tests/ ├── translations/ + ├── var/ └── vendor/ This means that installing the ``symfony/flex`` dependency in your application From 5b6ef2a9cbe2eded17c7c2c3e441605d8a7b6591 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 15:16:53 -0500 Subject: [PATCH 0108/2437] linking directly and marking articles as orphans --- deployment.rst | 19 ++++++++++--------- deployment/azure-website.rst | 6 ++++-- deployment/fortrabbit.rst | 2 ++ deployment/heroku.rst | 6 ++++-- deployment/platformsh.rst | 2 ++ 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/deployment.rst b/deployment.rst index cbd39523fdf..c272b85fdf8 100644 --- a/deployment.rst +++ b/deployment.rst @@ -63,16 +63,13 @@ manually taking other steps (see `Common Post-Deployment Tasks`_). Using Platforms as a Service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Using a Platform as a Service (PAAS) can be a great way to deploy your Symfony app -quickly and easily. There are many PAAS - below are a few that work well with Symfony: +Using a Platform as a Service (PaaS) can be a great way to deploy your Symfony app +quickly and easily. There are many PaaS - below are a few that work well with Symfony: -.. toctree:: - :maxdepth: 1 - - deployment/heroku - deployment/platformsh - deployment/azure-website - deployment/fortrabbit +* `Heroku`_ +* `Platform.sh`_ +* `Azure`_ +* `fortrabbit`_ Using Build Scripts and other Tools ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -257,3 +254,7 @@ Learn More .. _`Symfony plugin`: https://github.com/capistrano/symfony/ .. _`Deployer`: http://deployer.org/ .. _`Git Tagging`: https://git-scm.com/book/en/v2/Git-Basics-Tagging +.. _`Heroku`: https://devcenter.heroku.com/articles/getting-started-with-symfony +.. _`platform.sh`: https://docs.platform.sh/frameworks/symfony.html +.. _`Azure`: https://azure.microsoft.com/en-us/develop/php/ +.. _`fortrabbit`: https://help.fortrabbit.com/install-symfony-3-uni diff --git a/deployment/azure-website.rst b/deployment/azure-website.rst index 2a84df5220e..15361b9e416 100644 --- a/deployment/azure-website.rst +++ b/deployment/azure-website.rst @@ -1,8 +1,10 @@ +:orphan: + .. index:: single: Deployment; Deploying to Microsoft Azure Website Cloud -Deploying to Microsoft Azure Website Cloud -========================================== +Deploying to Microsoft Azure +============================ If you want information about deploying to Azure, see their official documentation: `Create your PHP web application on Azure`_ diff --git a/deployment/fortrabbit.rst b/deployment/fortrabbit.rst index 49907599f37..f13bf4f0ad4 100644 --- a/deployment/fortrabbit.rst +++ b/deployment/fortrabbit.rst @@ -1,3 +1,5 @@ +:orphan: + .. index:: single: Deployment; Deploying to fortrabbit.com diff --git a/deployment/heroku.rst b/deployment/heroku.rst index d4827b12930..a7527805bd2 100644 --- a/deployment/heroku.rst +++ b/deployment/heroku.rst @@ -1,8 +1,10 @@ +:orphan: + .. index:: single: Deployment; Deploying to Heroku Cloud -Deploying to Heroku Cloud -========================= +Deploying to Heroku +=================== To deploy to Heroku, see their official documentation: `Getting Started with Symfony on Heroku`_. diff --git a/deployment/platformsh.rst b/deployment/platformsh.rst index 3eafcbc6af7..c124da18674 100644 --- a/deployment/platformsh.rst +++ b/deployment/platformsh.rst @@ -1,3 +1,5 @@ +:orphan: + .. index:: single: Deployment; Deploying to Platform.sh From c2f8345a4f76f563fc391696aa0cd176b883fa03 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 15:21:06 -0500 Subject: [PATCH 0109/2437] removing need for annotation route import change --- page_creation.rst | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/page_creation.rst b/page_creation.rst index b2e219c3b1c..1f8f7eef88a 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -93,22 +93,13 @@ Annotation Routes ----------------- Instead of defining your route in YAML, Symfony also allows you to use *annotation* -routes. First, install the annotations package: +routes. To do this, install the annotations package: .. code-block:: terminal $ composer require annotations -Then, in ``config/routes.yaml``, remove the route you just created and uncomment -the annotation route import at the bottom: - -.. code-block:: yaml - - controllers: - resource: ../src/Controller/ - type: annotation - -After this one-time setup, you can now add your route directly *above* the controller: +You can now add your route directly *above* the controller: .. code-block:: diff From da666af6d2470d38c5eef8391b5c8ac1d8facb73 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 15:37:12 -0500 Subject: [PATCH 0110/2437] Change service override docs --- bundles/override.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/bundles/override.rst b/bundles/override.rst index a4f6aea787e..a019fee8e7f 100644 --- a/bundles/override.rst +++ b/bundles/override.rst @@ -46,20 +46,19 @@ Services & Configuration If you want to modify service definitions of another bundle, you can use a compiler pass to change the class of the service or to modify method calls. In the following example, the implementing class for the ``original-service-id`` is changed to -``Acme\DemoBundle\YourService``:: +``App\YourService``:: - // src/Acme/DemoBundle/DependencyInjection/Compiler/OverrideServiceCompilerPass.php - namespace Acme\DemoBundle\DependencyInjection\Compiler; + // src/Kernel.php + namespace App; - use Acme\DemoBundle\YourService; - use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; + use App\Service\YourService; use Symfony\Component\DependencyInjection\ContainerBuilder; - class OverrideServiceCompilerPass implements CompilerPassInterface + class Kernel extends BaseKernel { public function process(ContainerBuilder $container) { - $definition = $container->getDefinition('original-service-id'); + $definition = $container->findDefinition('original-service-id'); $definition->setClass(YourService::class); } } From 49386782fa4c8b5707bc853ab893d1baa5c71407 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 16:09:34 -0500 Subject: [PATCH 0111/2437] WIP - starting to upgrade Doctrine doc --- doctrine.rst | 129 ++++++++++++--------------------------------------- 1 file changed, 29 insertions(+), 100 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index 4ff17e75bb4..5b989103197 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -4,112 +4,41 @@ Databases and the Doctrine ORM ============================== -One of the most common and challenging tasks for any application -involves persisting and reading information to and from a database. Although -the Symfony Framework doesn't integrate any component to work with databases, -it provides tight integration with a third-party library called `Doctrine`_. -Doctrine's sole goal is to give you powerful tools to make database interactions -easy and flexible. - -In this chapter, you'll learn how to start leveraging Doctrine in your Symfony projects -to give you rich database interactions. +Symfony doesn't provide a component to work with the database, but it *does* provide +tight integration with a third-party library called `Doctrine`_. .. note:: - Doctrine is totally decoupled from Symfony and using it is optional. - This chapter is all about the Doctrine ORM, which aims to let you map - objects to a relational database (such as *MySQL*, *PostgreSQL* or - *Microsoft SQL*). If you prefer to use raw database queries, this is - easy, and explained in the ":doc:`/doctrine/dbal`" article. - - You can also persist data to `MongoDB`_ using Doctrine ODM library. For - more information, read the "`DoctrineMongoDBBundle`_" - documentation. - -A Simple Example: A Product ---------------------------- + This article is all about using the Doctrine ORM. If you prefer to use raw + database queries, see the ":doc:`/doctrine/dbal`" article instead. -The easiest way to understand how Doctrine works is to see it in action. -In this section, you'll configure your database, create a ``Product`` object, -persist it to the database and fetch it back out. - -Configuring the Database -~~~~~~~~~~~~~~~~~~~~~~~~ + You can also persist data to `MongoDB`_ using Doctrine ODM library. See the + "`DoctrineMongoDBBundle`_" documentation. -Before you really begin, you'll need to configure your database connection -information. By convention, this information is usually configured in an -``app/config/parameters.yml`` file: - -.. code-block:: yaml - - # app/config/parameters.yml - parameters: - database_host: localhost - database_name: test_project - database_user: root - database_password: password - - # ... - -.. note:: +Installing Doctrine +------------------- - Defining the configuration via ``parameters.yml`` is just a convention. - The parameters defined in that file are referenced by the main configuration - file when setting up Doctrine: +First, install Doctrine, as well as the MakerBundle, which will help generate some +code: - .. configuration-block:: - - .. code-block:: yaml +.. code-block:: terminal - # app/config/config.yml - doctrine: - dbal: - driver: pdo_mysql - host: '%database_host%' - dbname: '%database_name%' - user: '%database_user%' - password: '%database_password%' + composer require orm maker - .. code-block:: xml +Configuring the Database +~~~~~~~~~~~~~~~~~~~~~~~~ - - - +The database connection information is stored as an environment variable called +``DATABASE_URL``. For development, you can find and customize this inside ``.env``: - - - - +.. code-block:: text - .. code-block:: php + # .env - // app/config/config.php - $container->loadFromExtension('doctrine', array( - 'dbal' => array( - 'driver' => 'pdo_mysql', - 'host' => '%database_host%', - 'dbname' => '%database_name%', - 'user' => '%database_user%', - 'password' => '%database_password%', - ), - )); + # customize this line! + DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" - By separating the database information into a separate file, you can - easily keep different versions of the file on each server. You can also - easily store database configuration (or any sensitive information) outside - of your project, like inside your Apache configuration, for example. For - more information, see :doc:`/configuration/external_parameters`. +----> HERE Now that Doctrine can connect to your database, the following command can automatically generate an empty ``test_project`` database for you: @@ -242,7 +171,7 @@ can automatically generate an empty ``test_project`` database for you: )); Creating an Entity Class -~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------ Suppose you're building an application where products need to be displayed. Without even thinking about Doctrine or databases, you already know that @@ -280,7 +209,7 @@ just a simple PHP class. .. _doctrine-adding-mapping: Add Mapping Information -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- Doctrine allows you to work with databases in a much more interesting way than just fetching rows of scalar data into an array. Instead, Doctrine @@ -439,7 +368,7 @@ see the :ref:`doctrine-field-types` section. .. _doctrine-generating-getters-and-setters: Generating Getters and Setters -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------------ Even though Doctrine now knows how to persist a ``Product`` object to the database, the class itself isn't really useful yet. Since ``Product`` is just @@ -451,7 +380,7 @@ methods manually or with your own IDE. .. _doctrine-creating-the-database-tables-schema: Creating the Database Tables/Schema -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +----------------------------------- You now have a usable ``Product`` class with mapping information so that Doctrine knows exactly how to persist it. Of course, you don't yet have the @@ -487,7 +416,7 @@ Your database now has a fully-functional ``product`` table with columns that match the metadata you've specified. Persisting Objects to the Database -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------------------------- Now that you have mapped the ``Product`` entity to its corresponding ``product`` table, you're ready to persist ``Product`` objects to the database. From inside @@ -580,7 +509,7 @@ issue an ``UPDATE`` query if the entity already exists in the database. the "`DoctrineFixturesBundle`_" documentation. Fetching Objects from the Database -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +---------------------------------- Fetching an object back out of the database is even easier. For example, suppose you've configured a route to display a specific ``Product`` based @@ -675,7 +604,7 @@ to easily fetch objects based on multiple conditions:: Symfony Profiler and see the exact queries that were executed. Updating an Object -~~~~~~~~~~~~~~~~~~ +------------------ Once you've fetched an object from Doctrine, updating it is easy. Suppose you have a route that maps a product id to an update action in a controller:: @@ -712,7 +641,7 @@ In this case, since you fetched the ``$product`` object from Doctrine, it's already managed. Deleting an Object -~~~~~~~~~~~~~~~~~~ +------------------ Deleting an object is very similar, but requires a call to the ``remove()`` method of the entity manager:: From 0684c4a850b476b7c90c735448cb437c0a034605 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 22 Nov 2017 14:47:38 +0100 Subject: [PATCH 0112/2437] Updated the configuration/* files --- configuration/configuration_organization.rst | 303 ++++-------------- configuration/external_parameters.rst | 15 +- .../front_controllers_and_kernel.rst | 110 +++---- configuration/micro_kernel_trait.rst | 107 +++---- configuration/multiple_kernels.rst | 125 ++++---- configuration/override_dir_structure.rst | 139 +++----- configuration/using_parameters_in_dic.rst | 22 +- 7 files changed, 259 insertions(+), 562 deletions(-) diff --git a/configuration/configuration_organization.rst b/configuration/configuration_organization.rst index 2bb3cbba181..6bc48e12a65 100644 --- a/configuration/configuration_organization.rst +++ b/configuration/configuration_organization.rst @@ -9,199 +9,63 @@ called ``dev``, ``prod`` and ``test``. An environment simply represents a way to execute the same codebase with different configurations. In order to select the configuration file to load for each environment, Symfony -executes the ``registerContainerConfiguration()`` method of the ``AppKernel`` -class:: +executes the ``configureContainer()`` method of the ``Kernel`` class:: - // app/AppKernel.php - use Symfony\Component\HttpKernel\Kernel; + // src/Kernel.php use Symfony\Component\Config\Loader\LoaderInterface; + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\HttpKernel\Kernel as BaseKernel; class Kernel extends BaseKernel { - // ... - - public function registerContainerConfiguration(LoaderInterface $loader) - { - $loader->load($this->getProjectDir().'/app/config/config_'.$this->getEnvironment().'.yml'); - } - } - -This method loads the ``app/config/config_dev.yml`` file for the ``dev`` -environment and so on. In turn, this file loads the common configuration file -located at ``app/config/config.yml``. Therefore, the configuration files of the -default Symfony Standard Edition follow this structure: - -.. code-block:: text - - your-project/ - ├─ app/ - │ ├─ ... - │ └─ config/ - │ ├─ config.yml - │ ├─ config_dev.yml - │ ├─ config_prod.yml - │ ├─ config_test.yml - │ ├─ parameters.yml - │ ├─ parameters.yml.dist - │ ├─ routing.yml - │ ├─ routing_dev.yml - │ └─ security.yml - ├─ ... - -This default structure was chosen for its simplicity — one file per environment. -But as any other Symfony feature, you can customize it to better suit your needs. -The following sections explain different ways to organize your configuration -files. In order to simplify the examples, only the ``dev`` and ``prod`` -environments are taken into account. + const CONFIG_EXTS = '.{php,xml,yaml,yml}'; -Different Directories per Environment -------------------------------------- - -Instead of suffixing the files with ``_dev`` and ``_prod``, this technique -groups all the related configuration files under a directory with the same -name as the environment: - -.. code-block:: text - - your-project/ - ├─ app/ - │ ├─ ... - │ └─ config/ - │ ├─ common/ - │ │ ├─ config.yml - │ │ ├─ parameters.yml - │ │ ├─ routing.yml - │ │ └─ security.yml - │ ├─ dev/ - │ │ ├─ config.yml - │ │ ├─ parameters.yml - │ │ ├─ routing.yml - │ │ └─ security.yml - │ └─ prod/ - │ ├─ config.yml - │ ├─ parameters.yml - │ ├─ routing.yml - │ └─ security.yml - ├─ ... - -To make this work, change the code of the -:method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerContainerConfiguration` -method:: - - // app/AppKernel.php - use Symfony\Component\HttpKernel\Kernel; - use Symfony\Component\Config\Loader\LoaderInterface; - - class AppKernel extends Kernel - { // ... - public function registerContainerConfiguration(LoaderInterface $loader) + public function configureContainer(ContainerBuilder $container, LoaderInterface $loader) { - $loader->load($this->getProjectDir().'/app/config/'.$this->getEnvironment().'/config.yml'); + $confDir = $this->getProjectDir().'/config'; + $loader->load($confDir.'/packages/*'.self::CONFIG_EXTS, 'glob'); + if (is_dir($confDir.'/packages/'.$this->environment)) { + $loader->load($confDir.'/packages/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); + } + $loader->load($confDir.'/services'.self::CONFIG_EXTS, 'glob'); + $loader->load($confDir.'/services_'.$this->environment.self::CONFIG_EXTS, 'glob'); } } -Then, make sure that each ``config.yml`` file loads the rest of the configuration -files, including the common files. For instance, this would be the imports -needed for the ``app/config/dev/config.yml`` file: +For the ``dev`` environment, Symfony loads the following config files and +directories and in this order: -.. configuration-block:: - - .. code-block:: yaml - - # app/config/dev/config.yml - imports: - - { resource: '../common/config.yml' } - - { resource: 'parameters.yml' } - - { resource: 'security.yml' } - - # ... - - .. code-block:: xml - - - - - - - - - - - - - +#. ``config/packages/*`` +#. ``config/packages/dev/*`` +#. ``config/services.yaml`` +#. ``config/services_dev.yaml`` - .. code-block:: php - - // app/config/dev/config.php - $loader->import('../common/config.php'); - $loader->import('parameters.php'); - $loader->import('security.php'); - - // ... - -.. include:: /components/dependency_injection/_imports-parameters-note.rst.inc - -Semantic Configuration Files ----------------------------- - -A different organization strategy may be needed for complex applications with -large configuration files. For instance, you could create one file per bundle -and several files to define all application services: +Therefore, the configuration files of the default Symfony applications follow +this structure: .. code-block:: text your-project/ - ├─ app/ - │ ├─ ... - │ └─ config/ - │ ├─ bundles/ - │ │ ├─ bundle1.yml - │ │ ├─ bundle2.yml - │ │ ├─ ... - │ │ └─ bundleN.yml - │ ├─ environments/ - │ │ ├─ common.yml - │ │ ├─ dev.yml - │ │ └─ prod.yml - │ ├─ routing/ - │ │ ├─ common.yml - │ │ ├─ dev.yml - │ │ └─ prod.yml - │ └─ services/ - │ ├─ frontend.yml - │ ├─ backend.yml - │ ├─ ... - │ └─ security.yml + ├─ config/ + │ └─ packages/ + │ ├─ dev/ + | │ ├─ framework.yaml + │ │ └─ ... + │ ├─ prod/ + │ │ └─ ... + │ ├─ test/ + │ │ └─ ... + | ├─ framework.yaml + │ └─ ... + │ ├─ services.yaml + │ └─ services_dev.yaml ├─ ... -Again, change the code of the ``registerContainerConfiguration()`` method to -make Symfony aware of the new file organization:: - - // app/AppKernel.php - use Symfony\Component\HttpKernel\Kernel; - use Symfony\Component\Config\Loader\LoaderInterface; - - class AppKernel extends Kernel - { - // ... - - public function registerContainerConfiguration(LoaderInterface $loader) - { - $loader->load($this->getProjectDir().'/app/config/environments/'.$this->getEnvironment().'.yml'); - } - } - -Following the same technique explained in the previous section, make sure to -import the appropriate configuration files from each main file (``common.yml``, -``dev.yml`` and ``prod.yml``). +This default structure was chosen for its simplicity — one file per package and +environment. But as any other Symfony feature, you can customize it to better +suit your needs. Advanced Techniques ------------------- @@ -220,18 +84,16 @@ format (``.yml``, ``.xml``, ``.php``, ``.ini``): .. code-block:: yaml - # app/config/config.yml + # config/services.yaml imports: - - { resource: 'parameters.yml' } - - { resource: 'services.xml' } - - { resource: 'security.yml' } + - { resource: 'my_config_file.xml' } - { resource: 'legacy.php' } # ... .. code-block:: xml - + - - - + @@ -252,21 +112,12 @@ format (``.yml``, ``.xml``, ``.php``, ``.ini``): .. code-block:: php - // app/config/config.php - $loader->import('parameters.yml'); - $loader->import('services.xml'); - $loader->import('security.yml'); - $loader->import('legacy.php'); + // config/services.php + $loader->import('my_config_file.yaml'); + $loader->import('legacy.xml'); // ... -.. caution:: - - The ``IniFileLoader`` parses the file contents using the - :phpfunction:`parse_ini_file` function. Therefore, you can only set - parameters to string values. Use one of the other loaders if you want - to use other data types (e.g. boolean, integer, etc.). - If you use any other configuration format, you have to define your own loader class extending it from :class:`Symfony\\Component\\DependencyInjection\\Loader\\FileLoader`. When the configuration values are dynamic, you can use the PHP configuration @@ -278,7 +129,7 @@ Global Configuration Files Some system administrators may prefer to store sensitive parameters in files outside the project directory. Imagine that the database credentials for your -website are stored in the ``/etc/sites/mysite.com/parameters.yml`` file. Loading +website are stored in the ``/etc/sites/mysite.com/parameters.yaml`` file. Loading this file is as simple as indicating the full file path when importing it from any other configuration file: @@ -286,16 +137,15 @@ any other configuration file: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml imports: - - { resource: 'parameters.yml' } - - { resource: '/etc/sites/mysite.com/parameters.yml' } + - { resource: '/etc/sites/mysite.com/parameters.yaml', ignore_errors: true } # ... .. code-block:: xml - + - - + @@ -314,56 +163,18 @@ any other configuration file: .. code-block:: php - // app/config/config.php - $loader->import('parameters.yml'); - $loader->import('/etc/sites/mysite.com/parameters.yml'); + // config/services.php + $loader->import('/etc/sites/mysite.com/parameters.yaml', null, true); // ... -Most of the time, local developers won't have the same files that exist on the -production servers. For that reason, the Config component provides the -``ignore_errors`` option to silently discard errors when the loaded file -doesn't exist: - -.. configuration-block:: - - .. code-block:: yaml +.. tip:: - # app/config/config.yml - imports: - - { resource: 'parameters.yml' } - - { resource: '/etc/sites/mysite.com/parameters.yml', ignore_errors: true } - - # ... - - .. code-block:: xml - - - - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $loader->import('parameters.yml'); - $loader->import('/etc/sites/mysite.com/parameters.yml', null, true); - - // ... + The ``ignore_errors`` option (which is the third optional argument in the + loader's ``import()`` method) silently discards errors when the loaded file + doesn't exist. This is needed in this case because most of the time, local + developers won't have the same files that exist on the production servers. As you've seen, there are lots of ways to organize your configuration files. You can choose one of these or even create your own custom way of organizing the -files. Don't feel limited by the Standard Edition that comes with Symfony. For even -more customization, see ":doc:`/configuration/override_dir_structure`". +files. For even more customization, see ":doc:`/configuration/override_dir_structure`". diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index a052cacd1e9..3dfff4479de 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -24,7 +24,7 @@ put in a ``DATABASE_URL`` environment variable: .. code-block:: bash # .env - DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" + DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name" This variable is referenced in the service container configuration using ``%env(DATABASE_HOST)%``: @@ -114,21 +114,12 @@ the following: # ... - SetEnv DATABASE_URL "mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" + SetEnv DATABASE_URL "mysql://db_user:db_password@127.0.0.1:3306/db_name" .. code-block:: nginx - fastcgi_param DATABASE_URL "mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7"; - -.. tip:: - - You can also define the default value of any existing parameters using - special environment variables named after their corresponding parameter - prefixed with ``SYMFONY__`` after replacing dots by double underscores - (e.g. ``SYMFONY__KERNEL__CHARSET`` to set the default value of the - ``kernel.charset`` parameter). These default values are resolved when - compiling the service container and won't change at runtime once dumped. + fastcgi_param DATABASE_URL "mysql://db_user:db_password@127.0.0.1:3306/db_name"; Constants --------- diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index a5160a47108..df57fa40cf1 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -5,10 +5,10 @@ Understanding how the Front Controller, Kernel and Environments Work together ============================================================================= -The section :doc:`/configuration/environments` explained the basics -on how Symfony uses environments to run your application with different configuration -settings. This section will explain a bit more in-depth what happens when -your application is bootstrapped. To hook into this process, you need to understand +The section :doc:`/configuration/environments` explained the basics on how +Symfony uses environments to run your application with different configuration +settings. This section will explain a bit more in-depth what happens when your +application is bootstrapped. To hook into this process, you need to understand three parts that work together: * `The Front Controller`_ @@ -18,11 +18,8 @@ three parts that work together: .. note:: Usually, you will not need to define your own front controller or - ``AppKernel`` class as the `Symfony Standard Edition`_ provides - sensible default implementations. - - This documentation section is provided to explain what is going on behind - the scenes. + ``Kernel`` class as Symfony provides sensible default implementations. + This article is provided to explain what is going on behind the scenes. The Front Controller -------------------- @@ -55,8 +52,7 @@ You can choose the front controller that's used by adding it in the URL, like: As you can see, this URL contains the PHP script to be used as the front controller. You can use that to easily switch to a custom made front controller -that is located in the ``public/`` directory or e.g. access the ``check.php`` -file. +that is located in the ``public/`` directory. .. seealso:: @@ -72,86 +68,80 @@ The Kernel Class ---------------- The :class:`Symfony\\Component\\HttpKernel\\Kernel` is the core of -Symfony. It is responsible for setting up all the bundles that make up +Symfony. It is responsible for setting up all the bundles used by your application and providing them with the application's configuration. It then creates the service container before serving requests in its :method:`Symfony\\Component\\HttpKernel\\HttpKernelInterface::handle` method. -There are two methods declared in the -:class:`Symfony\\Component\\HttpKernel\\KernelInterface` that are -left unimplemented in :class:`Symfony\\Component\\HttpKernel\\Kernel` -and thus serve as `template methods`_: +The kernel used in Symfony apps extends from :class:`Symfony\\Component\\HttpKernel\\Kernel` +and uses the :class:`Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait`. +The ``Kernel`` class leaves some methods from :class:`Symfony\\Component\\HttpKernel\\KernelInterface` +unimplemented and the ``MicroKernelTrait`` defines several abstract methods, so +you must implement them all: :method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerBundles` It must return an array of all bundles needed to run the application. -:method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerContainerConfiguration` - It loads the application configuration. -To fill these (small) blanks, your application needs to subclass the -Kernel and implement these methods. The resulting class is conventionally -called the ``AppKernel``. +:method:`Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait:configureRoutes` + It adds individual routes or collections of routes to the application (for + example loading the routes defined in some config file). + +:method:`Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait::configureContainer` + It loads the application configuration from config files or using the + ``loadFromExtension()`` method and can also register new container parameters + and services. -Again, the Symfony Standard Edition provides an `AppKernel`_ in the ``app/`` -directory. This class uses the name of the environment - which is passed to -the Kernel's :method:`constructor ` +To fill these (small) blanks, your application needs to extend the Kernel class +and use the MicroKernelTrait to implement these methods. Symfony provides by +default that kernel in the ``src/Kernel.php`` file. + +This class uses the name of the environment - which is passed to the Kernel's +:method:`constructor ` method and is available via :method:`Symfony\\Component\\HttpKernel\\Kernel::getEnvironment` - -to decide which bundles to create. The logic for that is in ``registerBundles()``, -a method meant to be extended by you when you start adding bundles to your -application. +to decide which bundles to enable. The logic for that is in ``registerBundles()``. You are, of course, free to create your own, alternative or additional -``AppKernel`` variants. All you need is to adapt your (or add a new) front +``Kernel`` variants. All you need is to adapt your (or add a new) front controller to make use of the new kernel. .. note:: - The name and location of the ``AppKernel`` is not fixed. When - putting multiple Kernels into a single application, - it might therefore make sense to add additional sub-directories, - for example ``app/admin/AdminKernel.php`` and - ``app/api/ApiKernel.php``. All that matters is that your front - controller is able to create an instance of the appropriate kernel. - -Having different ``AppKernels`` might be useful to enable different front -controllers (on potentially different servers) to run parts of your application -independently (for example, the admin UI, the front-end UI and database migrations). + The name and location of the ``Kernel`` is not fixed. When putting + :doc:`multiple kernels into a single application `, + it might therefore make sense to add additional sub-directories, for example + ``src/admin/AdminKernel.php`` and ``src/api/ApiKernel.php``. All that matters + is that your front controller is able to create an instance of the appropriate kernel. .. note:: - There's a lot more the ``AppKernel`` can be used for, for example + There's a lot more the ``Kernel`` can be used for, for example :doc:`overriding the default directory structure `. But odds are high that you don't need to change things like this on the - fly by having several ``AppKernel`` implementations. + fly by having several ``Kernel`` implementations. The Environments ---------------- -As just mentioned, the ``AppKernel`` has to implement another method - -:method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerContainerConfiguration`. -This method is responsible for loading the application's -configuration from the right *environment*. +As just mentioned, the ``Kernel`` has to implement another method - +:method:`Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait::configureContainer`. +This method is responsible for loading the application's configuration from the +right *environment*. -Environments have been covered extensively -:doc:`in the previous article `, -and you probably remember that the Symfony Standard Edition comes with three -of them - ``dev``, ``prod`` and ``test``. +Environments have been covered extensively :doc:`in the previous article +`, and you probably remember that the Symfony uses +by default three of them - ``dev``, ``prod`` and ``test``. More technically, these names are nothing more than strings passed from the -front controller to the ``AppKernel``'s constructor. This name can then be -used in the :method:`Symfony\\Component\\HttpKernel\\KernelInterface::registerContainerConfiguration` -method to decide which configuration files to load. +front controller to the ``Kernel``'s constructor. This name can then be used in +the ``configureContainer()`` method to decide which configuration files to load. -The Symfony Standard Edition's `AppKernel`_ class implements this method by simply -loading the ``app/config/config_*environment*.yml`` file. You are, of course, -free to implement this method differently if you need a more sophisticated -way of loading your configuration. +Symfony's default ``Kernel`` class implements this method by loading first the +config files found on ``config/packages/*`` and then, the files found on +``config/packages/ENVIRONMENT_NAME/``. You are, of course, free to implement +this method differently if you need a more sophisticated way of loading your +configuration. .. _front controller: https://en.wikipedia.org/wiki/Front_Controller_pattern -.. _Symfony Standard Edition: https://github.com/symfony/symfony-standard -.. _index.php: https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/3.3/public/index.php -.. _app_dev.php: https://github.com/symfony/symfony-standard/blob/master/web/app_dev.php .. _bin/console: https://github.com/symfony/symfony-standard/blob/master/bin/console -.. _AppKernel: https://github.com/symfony/symfony-standard/blob/master/app/AppKernel.php .. _decorate: https://en.wikipedia.org/wiki/Decorator_pattern -.. _template methods: https://en.wikipedia.org/wiki/Template_method_pattern diff --git a/configuration/micro_kernel_trait.rst b/configuration/micro_kernel_trait.rst index 8eb1c90b5db..4d90414ba83 100644 --- a/configuration/micro_kernel_trait.rst +++ b/configuration/micro_kernel_trait.rst @@ -1,40 +1,38 @@ Building your own Framework with the MicroKernelTrait ===================================================== -A traditional Symfony app contains a sensible -directory structure, various configuration files and an ``AppKernel`` with several -bundles already-registered. This is a fully-featured app that's ready to go. +The default ``Kernel`` class included in Symfony applications uses a +:class:`Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait` to configure +the bundles, the routes and the service container in the same class. -But did you know, you can create a fully-functional Symfony application in as little -as one file? This is possible thanks to the new -:class:`Symfony\\Bundle\\FrameworkBundle\\Kernel\\MicroKernelTrait`. This allows -you to start with a tiny application, and then add features and structure as you -need to. +This micro-kernel approach is so flexible that let you control your application +structure and features quite easily. A Single-File Symfony Application --------------------------------- -Start with a completely empty directory. Get ``symfony/symfony`` as a dependency +Start with a completely empty directory and install these Symfony components via Composer: .. code-block:: bash - $ composer require symfony/symfony + $ composer require symfony/config symfony/http-kernel \ + symfony/http-foundation symfony/routing \ + symfony/dependency-injection symfony/framework-bundle -Next, create an ``index.php`` file that creates a kernel class and executes it:: +Next, create an ``index.php`` file that defines the kernel class and executes it:: use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; - use Symfony\Component\HttpKernel\Kernel; + use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\RouteCollectionBuilder; - // require Composer's autoloader require __DIR__.'/vendor/autoload.php'; - class AppKernel extends Kernel + class Kernel extends BaseKernel { use MicroKernelTrait; @@ -47,7 +45,7 @@ Next, create an ``index.php`` file that creates a kernel class and executes it:: protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) { - // PHP equivalent of config.yml + // PHP equivalent of config/packages/framework.yaml $c->loadFromExtension('framework', array( 'secret' => 'S0ME_SECRET' )); @@ -68,7 +66,7 @@ Next, create an ``index.php`` file that creates a kernel class and executes it:: } } - $kernel = new AppKernel('dev', true); + $kernel = new Kernel('dev', true); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); @@ -76,7 +74,7 @@ Next, create an ``index.php`` file that creates a kernel class and executes it:: That's it! To test it, you can start the built-in web server: -.. code-block:: bash +.. code-block:: terminal $ php -S localhost:8000 @@ -96,8 +94,8 @@ that define your bundles, your services and your routes: **configureContainer(ContainerBuilder $c, LoaderInterface $loader)** This method builds and configures the container. In practice, you will use ``loadFromExtension`` to configure different bundles (this is the equivalent - of what you see in a normal ``config.yml`` file). You can also register services - directly in PHP or load external configuration files (shown below). + of what you see in a normal ``config/packages/*`` file). You can also register + services directly in PHP or load external configuration files (shown below). **configureRoutes(RouteCollectionBuilder $routes)** Your job in this method is to add routes to the application. The @@ -122,30 +120,30 @@ your ``composer.json`` file to load from there: }, "autoload": { "psr-4": { - "": "src/" + "App\\": "src/" } } } Now, suppose you want to use Twig and load routes via annotations. Instead of -putting *everything* in ``index.php``, create a new ``app/AppKernel.php`` to +putting *everything* in ``index.php``, create a new ``src/Kernel.php`` to hold the kernel. Now it looks like this:: - // app/AppKernel.php + // src/Kernel.php + namespace App; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; - use Symfony\Component\HttpKernel\Kernel; + use Symfony\Component\HttpKernel\Kernel as BaseKernel; use Symfony\Component\Routing\RouteCollectionBuilder; use Doctrine\Common\Annotations\AnnotationRegistry; - // require Composer's autoloader $loader = require __DIR__.'/../vendor/autoload.php'; // auto-load annotations AnnotationRegistry::registerLoader(array($loader, 'loadClass')); - class AppKernel extends Kernel + class Kernel extends BaseKernel { use MicroKernelTrait; @@ -165,7 +163,7 @@ hold the kernel. Now it looks like this:: protected function configureContainer(ContainerBuilder $c, LoaderInterface $loader) { - $loader->load(__DIR__.'/config/config.yml'); + $loader->load(__DIR__.'/config/framework.yaml'); // configure WebProfilerBundle only if the bundle is enabled if (isset($this->bundles['WebProfilerBundle'])) { @@ -185,7 +183,7 @@ hold the kernel. Now it looks like this:: } // load the annotation routes - $routes->import(__DIR__.'/../src/App/Controller/', '/', 'annotation'); + $routes->import(__DIR__.'/../src/Controller/', '/', 'annotation'); } // optional, to use the standard Symfony cache directory @@ -201,14 +199,14 @@ hold the kernel. Now it looks like this:: } } -Unlike the previous kernel, this loads an external ``app/config/config.yml`` file, +Unlike the previous kernel, this loads an external ``config/framework.yaml`` file, because the configuration started to get bigger: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/framework.yaml framework: secret: S0ME_SECRET templating: @@ -217,7 +215,7 @@ because the configuration started to get bigger: .. code-block:: xml - + loadFromExtension('framework', array( 'secret' => 'S0ME_SECRET', 'templating' => array( @@ -246,10 +244,10 @@ because the configuration started to get bigger: ), )); -This also loads annotation routes from an ``src/App/Controller/`` directory, which +This also loads annotation routes from an ``src/Controller/`` directory, which has one file in it:: - // src/App/Controller/MicroController.php + // src/Controller/MicroController.php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; @@ -270,13 +268,13 @@ has one file in it:: } } -Template files should live in the ``Resources/views`` directory of whatever directory -your *kernel* lives in. Since ``AppKernel`` lives in ``app/``, this template lives -at ``app/Resources/views/micro/random.html.twig``: +Template files should live in the ``Resources/views/`` directory of whatever directory +your *kernel* lives in. Since ``Kernel`` lives in ``src/``, this template lives +at ``src/Resources/views/micro/random.html.twig``: .. code-block:: html+twig - + @@ -288,15 +286,15 @@ at ``app/Resources/views/micro/random.html.twig``: Finally, you need a front controller to boot and run the application. Create a -``web/index.php``:: +``public/index.php``:: - // web/index.php + // public/index.php use Symfony\Component\HttpFoundation\Request; - require __DIR__.'/../app/AppKernel.php'; + require __DIR__.'/../src/Kernel.php'; - $kernel = new AppKernel('dev', true); + $kernel = new Kernel('dev', true); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); @@ -309,38 +307,33 @@ this: .. code-block:: text your-project/ - ├─ app/ - | ├─ AppKernel.php - │ ├─ config/ + ├─ config/ + │ └─ framework.yaml + ├─ public/ + | └─ index.php + ├─ src/ + | ├─ Kernel.php + | ├─ Controller + | | └─ MicroController.php │ └─ Resources | └─ views | └─ micro | └─ random.html.twig - ├─ src/ - │ └─ App - | └─ Controller - | └─ MicroController.php ├─ var/ | ├─ cache/ - │ └─ logs/ + │ └─ log/ ├─ vendor/ │ └─ ... - ├─ web/ - | └─ index.php ├─ composer.json └─ composer.lock As before you can use PHP built-in server: -.. code-block:: bash +.. code-block:: terminal - cd web/ + cd public/ $ php -S localhost:8000 Then see webpage in browser: http://localhost:8000/random/10 - -Hey, that looks a lot like a *traditional* Symfony application! You're right: the -``MicroKernelTrait`` *is* still Symfony: but you can control your structure and -features quite easily. diff --git a/configuration/multiple_kernels.rst b/configuration/multiple_kernels.rst index 078de65adeb..cfdf5c0cf2f 100644 --- a/configuration/multiple_kernels.rst +++ b/configuration/multiple_kernels.rst @@ -4,16 +4,21 @@ How To Create Symfony Applications with Multiple Kernels ======================================================== +.. caution:: + + Creating aplications with multiple kernels is no longer recommended by + Symfony. Consider creating multiple small applications instead. + In most Symfony applications, incoming requests are processed by the -``web/app.php`` front controller, which instantiates the ``app/AppKernel.php`` +``public/index.php`` front controller, which instantiates the ``src/Kernel.php`` class to create the application kernel that loads the bundles and handles the request to generate the response. -This single kernel approach is a convenient default provided by the Symfony -Standard edition, but Symfony applications can define any number of kernels. -Whereas :doc:`environments ` execute the same -application with different configurations, kernels can execute different parts -of the same application. +This single kernel approach is a convenient default, but Symfony applications +can define any number of kernels. Whereas +:doc:`environments ` execute the same application +with different configurations, kernels can execute different parts of the same +application. These are some of the common use cases for creating multiple kernels: @@ -45,45 +50,46 @@ Step 1) Create a new Front Controller ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Instead of creating the new front controller from scratch, it's easier to -duplicate the existing ones. For example, create ``web/api_dev.php`` from -``web/app_dev.php`` and ``web/api.php`` from ``web/app.php``. - -Then, update the code of the new front controllers to instantiate the new kernel -class instead of the usual ``AppKernel`` class:: +duplicate the existing one. For example, create ``public/api.php`` from +``public/index.php``. - // web/api.php - // ... - $kernel = new ApiKernel('prod', false); - // ... +Then, update the code of the new front controller to instantiate the new kernel +class instead of the usual ``Kernel`` class:: - // web/api_dev.php + // public/api.php // ... - $kernel = new ApiKernel('dev', true); + $kernel = new ApiKernel( + $_SERVER['APP_ENV'] ?? 'dev', + $_SERVER['APP_DEBUG'] ?? ('prod' !== ($_SERVER['APP_ENV'] ?? 'dev')) + ); // ... .. tip:: - Another approach is to keep the existing front controller (e.g. ``app.php`` and - ``app_dev.php``), but add an ``if`` statement to load the different kernel based - on the URL (e.g. if the URL starts with ``/api``, use the ``ApiKernel``). + Another approach is to keep the existing ``index.php`` front controller, but + add an ``if`` statement to load the different kernel based on the URL (e.g. + if the URL starts with ``/api``, use the ``ApiKernel``). Step 2) Create the new Kernel Class ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Now you need to define the ``ApiKernel`` class used by the new front controller. -The easiest way to do this is by duplicating the existing ``app/AppKernel.php`` +The easiest way to do this is by duplicating the existing ``src/Kernel.php`` file and make the needed changes. In this example, the ``ApiKernel`` will load less bundles than AppKernel. Be sure to also change the location of the cache, logs and configuration files so they don't collide with the files from ``AppKernel``:: - // app/ApiKernel.php + // src/ApiKernel.php use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\Config\Loader\LoaderInterface; + use Symfony\Component\DependencyInjection\ContainerBuilder; class ApiKernel extends Kernel { + // ... + public function registerBundles() { // load only the bundles strictly needed for the API... @@ -99,57 +105,38 @@ they don't collide with the files from ``AppKernel``:: return dirname(__DIR__).'/var/log/api'; } - public function registerContainerConfiguration(LoaderInterface $loader) + public function configureContainer(ContainerBuilder $container, LoaderInterface $loader) { - $loader->load($this->getProjectDir().'/app/config/api/config_'.$this->getEnvironment().'.yml'); + // load only the config files strictly needed for the API + $confDir = $this->getProjectDir().'/config'; + $loader->load($confDir.'/api/*'.self::CONFIG_EXTS, 'glob'); + if (is_dir($confDir.'/api/'.$this->environment)) { + $loader->load($confDir.'/api/'.$this->environment.'/**/*'.self::CONFIG_EXTS, 'glob'); + } } } -In order for the autoloader to find your new ``ApiKernel``, make sure you add it -to your ``composer.json`` autoload section: - - -.. code-block:: json - - { - "...": "..." - - "autoload": { - "psr-4": { "": "src/" }, - "classmap": [ "app/AppKernel.php", "app/AppCache.php", "app/ApiKernel.php" ] - } - } - -Then, run ``composer install`` to dump your new autoload config. - Step 3) Define the Kernel Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Finally, define the configuration files that the new ``ApiKernel`` will load. -According to the above code, this config will live in the ``app/config/api/`` -directory. +According to the above code, this config will live in one or multiple files +stored in ``config/api/`` and ``config/api/ENVIRONMENT_NAME/`` directories. -The new configuration can be created from scratch when you load just a few +The new configuration files can be created from scratch when you load just a few bundles, because it will be very simple. Otherwise, duplicate the existing -config files or better, import them and override the needed options: - -.. code-block:: yaml - - # app/config/api/config_dev.yml - imports: - - { resource: ../config_dev.yml } - - # override option values ... +config files in ``config/packages/`` or better, import them and override the +needed options. Executing Commands with a Different Kernel ------------------------------------------ The ``bin/console`` script used to run Symfony commands always uses the default -``AppKernel`` class to build the application and load the commands. If you need +``Kernel`` class to build the application and load the commands. If you need to execute console commands using the new kernel, duplicate the ``bin/console`` script and rename it (e.g. ``bin/api``). -Then, replace the ``AppKernel`` instantiation by your own kernel instantiation +Then, replace the ``Kernel`` instantiation by your own kernel instantiation (e.g. ``ApiKernel``) and now you can execute commands using the new kernel (e.g. ``php bin/api cache:clear``) Now you can use execute commands using the new kernel. @@ -164,19 +151,19 @@ Rendering Templates Defined in a Different Kernel ------------------------------------------------- If you follow the Symfony Best Practices, the templates of the default kernel -will be stored in ``app/Resources/views/``. Trying to render those templates in -a different kernel will result in a *There are no registered paths for -namespace "__main__"* error. +will be stored in ``templates/``. Trying to render those templates in a +different kernel will result in a *There are no registered paths for namespace +"__main__"* error. In order to solve this issue, add the following configuration to your kernel: .. code-block:: yaml - # api/config/config.yml + # config/api/twig.yaml twig: paths: - # allows to use app/Resources/views/ templates in the ApiKernel - "%kernel.project_dir%/app/Resources/views": ~ + # allows to use api/templates/ dir in the ApiKernel + "%kernel.project_dir%/api/templates": ~ Running Tests Using a Different Kernel -------------------------------------- @@ -199,7 +186,7 @@ return the fully qualified class name of the kernel to use:: { protected static function getKernelClass() { - return 'ApiKernel'; + return 'App\ApiKernel'; } // this is needed because the KernelTestCase class keeps a reference to @@ -220,23 +207,19 @@ Adding more Kernels to the Application If your application is very complex and you create several kernels, it's better to store them in their own directories instead of messing with lots of files in -the default ``app/`` directory: +the default ``src/`` directory: .. code-block:: text project/ - ├─ app/ + ├─ src/ │ ├─ ... - │ ├─ config/ - │ └─ AppKernel.php + │ └─ Kernel.php ├─ api/ │ ├─ ... - │ ├─ config/ │ └─ ApiKernel.php ├─ ... - └─ web/ + └─ public/ ├─ ... - ├─ app.php - ├─ app_dev.php ├─ api.php - └─ api_dev.php + └─ index.php diff --git a/configuration/override_dir_structure.rst b/configuration/override_dir_structure.rst index 50293fd7eda..60565559355 100644 --- a/configuration/override_dir_structure.rst +++ b/configuration/override_dir_structure.rst @@ -11,39 +11,35 @@ directory structure is: .. code-block:: text your-project/ - ├─ app/ - │ ├─ config/ - │ ├─ Resources/ - │ │ └─ views/ - │ └─ ... + ├─ assets/ ├─ bin/ - │ └─ ... + │ └─ console + ├─ config/ + ├─ public/ + │ └─ index.php ├─ src/ │ └─ ... + ├─ templates/ ├─ tests/ - │ └─ ... + ├─ translations/ ├─ var/ │ ├─ cache/ - │ ├─ logs/ - │ └─ ... - ├─ vendor/ + │ ├─ log/ │ └─ ... - └─ web/ - ├─ app.php - └─ ... + └─ vendor/ .. _override-cache-dir: Override the ``cache`` Directory -------------------------------- -You can change the default cache directory by overriding the ``getCacheDir()`` method -in the ``AppKernel`` class of your application:: +You can change the default cache directory by overriding the ``getCacheDir()`` +method in the ``Kernel`` class of your application:: - // app/AppKernel.php + // src/Kernel.php // ... - class AppKernel extends Kernel + class AppKernel extends BaseKernel { // ... @@ -73,7 +69,7 @@ Overriding the ``logs`` directory is the same as overriding the ``cache`` directory. The only difference is that you need to override the ``getLogDir()`` method:: - // app/AppKernel.php + // src/Kernel.php // ... class AppKernel extends Kernel @@ -93,22 +89,22 @@ Here you have changed the location of the directory to ``var/{environment}/log`` Override the Templates Directory -------------------------------- -If your templates are not stored in the default ``app/Resources/views/`` -directory, use the :ref:`twig.paths ` configuration option to -define your own templates directory (or directories): +If your templates are not stored in the default ``templates/`` directory, use +the :ref:`twig.paths ` configuration option to define your +own templates directory (or directories): .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: # ... - paths: ["%kernel.project_dir%/templates"] + paths: ["%kernel.project_dir%/resources/views"] .. code-block:: xml - + - %kernel.project_dir%/templates + %kernel.project_dir%/resources/views .. code-block:: php - // app/config/config.php + // config/packages/twig.php $container->loadFromExtension('twig', array( 'paths' => array( - '%kernel.project_dir%/templates', + '%kernel.project_dir%/resources/views', ), )); .. _override-web-dir: +.. _override-the-web-directory: -Override the ``web`` Directory ------------------------------- +Override the ``public`` Directory +--------------------------------- -If you need to rename or move your ``web`` directory, the only thing you -need to guarantee is that the path to the ``var`` directory is still correct -in your ``app.php`` and ``app_dev.php`` front controllers. If you simply -renamed the directory, you're fine. But if you moved it in some way, you -may need to modify these paths inside those files:: +If you need to rename or move your ``public`` directory, the only thing you need +to guarantee is that the path to the ``var`` directory is still correct in your +``index.php`` front controller. If you simply renamed the directory, you're +fine. But if you moved it in some way, you may need to modify these paths inside +those files:: - require_once __DIR__.'/../path/to/app/autoload.php'; + require_once __DIR__.'/../path/to/vendor/autoload.php'; -You also need to change the ``extra.symfony-web-dir`` option in the +You also need to change the ``extra.symfony-public-dir`` option in the ``composer.json`` file: .. code-block:: json @@ -155,77 +152,24 @@ You also need to change the ``extra.symfony-web-dir`` option in the "...": "...", "extra": { "...": "...", - "symfony-web-dir": "my_new_web_dir" + "symfony-public-dir": "my_new_public_dir" } } .. tip:: Some shared hosts have a ``public_html`` web directory root. Renaming - your web directory from ``web`` to ``public_html`` is one way to make + your web directory from ``public`` to ``public_html`` is one way to make your Symfony project work on your shared host. Another way is to deploy your application to a directory outside of your web root, delete your ``public_html`` directory, and then replace it with a symbolic link to - the ``web`` in your project. - -.. note:: - - If you use the AsseticBundle, you need to configure the ``read_from`` option - to point to the correct ``web`` directory: - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - - # ... - assetic: - # ... - read_from: '%kernel.project_dir%/../public_html' - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - - // ... - $container->loadFromExtension('assetic', array( - // ... - 'read_from' => '%kernel.project_dir%/../public_html', - )); - - Now you just need to clear the cache and dump the assets again and your - application should work: - - .. code-block:: terminal - - $ php bin/console cache:clear --no-warmup --env=prod - $ php bin/console assetic:dump --env=prod --no-debug + the ``public`` dir in your project. Override the ``vendor`` Directory --------------------------------- -To override the ``vendor`` directory, you need to introduce changes in the -``app/autoload.php`` and ``composer.json`` files. - -The change in the ``composer.json`` will look like this: +To override the ``vendor`` directory, you need to define the ``vendor-dir`` +option in your ``composer.json`` file like this: .. code-block:: json @@ -236,13 +180,6 @@ The change in the ``composer.json`` will look like this: }, } -Then, update the path to the ``autoload.php`` file in ``app/autoload.php``:: - - // app/autoload.php - - // ... - $loader = require '/some/dir/vendor/autoload.php'; - .. tip:: This modification can be of interest if you are working in a virtual environment diff --git a/configuration/using_parameters_in_dic.rst b/configuration/using_parameters_in_dic.rst index 4d45d7738c2..1f3ed6e38f5 100644 --- a/configuration/using_parameters_in_dic.rst +++ b/configuration/using_parameters_in_dic.rst @@ -37,7 +37,7 @@ Now, examine the results to see this closely: my_bundle: logging: '%kernel.debug%' - # true/false (depends on 2nd parameter of AppKernel), + # true/false (depends on 2nd argument of the Kernel class), # as expected, because %kernel.debug% inside configuration # gets evaluated before being passed to the extension @@ -93,7 +93,7 @@ Now, examine the results to see this closely: In order to support this use case, the ``Configuration`` class has to be injected with this parameter via the extension as follows:: - namespace AppBundle\DependencyInjection; + namespace App\DependencyInjection; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -126,7 +126,7 @@ be injected with this parameter via the extension as follows:: And set it in the constructor of ``Configuration`` via the ``Extension`` class:: - namespace AppBundle\DependencyInjection; + namespace App\DependencyInjection; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\DependencyInjection\Extension; @@ -141,16 +141,8 @@ And set it in the constructor of ``Configuration`` via the ``Extension`` class:: } } -.. sidebar:: Setting the Default in the Extension +.. tip:: - There are some instances of ``%kernel.debug%`` usage within a ``Configurator`` - class in TwigBundle and AsseticBundle. However this is because the default - parameter value is set by the Extension class. For example in AsseticBundle, - you can find:: - - $container->setParameter('assetic.debug', $config['debug']); - - The string ``%kernel.debug%`` passed here as an argument handles the - interpreting job to the container which in turn does the evaluation. - Both ways accomplish similar goals. AsseticBundle will not use - ``%kernel.debug%`` but rather the new ``%assetic.debug%`` parameter. + There are some instances of ``%kernel.debug%`` usage within a + ``Configurator`` class for example in TwigBundle. However this is because + the default parameter value is set by the Extension class. From 8fe3cf04d045b1ca7e6b78344abbe2d47219e946 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 22 Nov 2017 16:16:09 +0100 Subject: [PATCH 0113/2437] Updated the translation/* articles to Symfony 4 --- _images/translation/debug_1.png | Bin 22689 -> 0 bytes _images/translation/debug_2.png | Bin 22534 -> 0 bytes _images/translation/debug_3.png | Bin 22381 -> 0 bytes _images/translation/debug_4.png | Bin 22236 -> 0 bytes translation.rst | 77 +++++++++++-------- translation/debug.rst | 126 +++++++++++++++++++++----------- translation/lint.rst | 17 ++--- translation/locale.rst | 17 +++-- 8 files changed, 143 insertions(+), 94 deletions(-) delete mode 100644 _images/translation/debug_1.png delete mode 100644 _images/translation/debug_2.png delete mode 100644 _images/translation/debug_3.png delete mode 100644 _images/translation/debug_4.png diff --git a/_images/translation/debug_1.png b/_images/translation/debug_1.png deleted file mode 100644 index 8f175f4d7fffb76a5834a22b37580c5b8213f2d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22689 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 diff --git a/_images/translation/debug_2.png b/_images/translation/debug_2.png deleted file mode 100644 index 04a57fa41d45ef6bfa7ed755518b5ee1a2178a71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22534 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 D9@U|- diff --git a/_images/translation/debug_3.png b/_images/translation/debug_3.png deleted file mode 100644 index 6ed595e097b7b714b93be70d134cef71ac8b7c9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22381 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�D7=5gk)_W3TkefbFJrdOqir!n0*vrq9t+X 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 diff --git a/translation.rst b/translation.rst index ab9cc438385..74e11e5bfc3 100644 --- a/translation.rst +++ b/translation.rst @@ -51,21 +51,31 @@ to learn even more. Overall, the process has several steps: Configuration ------------- -Translations are handled by a ``translator`` service that uses the user's -locale to lookup and return translated messages. Before using it, enable the -``translator`` in your configuration: +In a :doc:`Symfony Flex ` based application, run this command to +add translation support: + +.. code-block:: terminal + + $ composer require translator + +This command creates an initial config file where you can define the default +locale of the app and the :ref:`fallback locales ` used +when Symfony can't find some translation: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/translation.yaml framework: - translator: { fallbacks: [en] } + default_locale: 'en' + translator: + fallbacks: ['en'] + # ... .. code-block:: xml - + - + en + .. code-block:: php - // app/config/config.php + // config/packages/translation.php $container->loadFromExtension('framework', array( + 'default_locale' => 'en', 'translator' => array('fallbacks' => array('en')), + // ... )); -See :ref:`translation-fallback` for details on the ``fallbacks`` key -and what Symfony does when it doesn't find a translation. - The locale used in translations is the one stored on the request. This is typically set via a ``_locale`` attribute on your routes (see :ref:`translation-locale-url`). @@ -108,10 +118,11 @@ for example, that you're translating a simple message from inside a controller:: // ... use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Translation\Translator; - public function indexAction() + public function index(Translator $translator) { - $translated = $this->get('translator')->trans('Symfony is great'); + $translated = $translator->trans('Symfony is great'); return new Response($translated); } @@ -129,7 +140,7 @@ different formats, XLIFF being the recommended format: .. code-block:: xml - + @@ -144,12 +155,12 @@ different formats, XLIFF being the recommended format: .. code-block:: yaml - # messages.fr.yml + # translations/messages.fr.yml Symfony is great: J'aime Symfony .. code-block:: php - // messages.fr.php + // translations/messages.fr.php return array( 'Symfony is great' => 'J\'aime Symfony', ); @@ -186,10 +197,11 @@ Message Placeholders Sometimes, a message containing a variable needs to be translated:: use Symfony\Component\HttpFoundation\Response; + use Symfony\Component\Translation\Translator; - public function indexAction($name) + public function index(Translator $translator, $name) { - $translated = $this->get('translator')->trans('Hello '.$name); + $translated = $translator->trans('Hello '.$name); return new Response($translated); } @@ -336,14 +348,14 @@ Translation Resource/File Names and Locations Symfony looks for message files (i.e. translations) in the following default locations: -* the ``app/Resources/translations`` directory; +* the ``translations/`` directory; -* the ``app/Resources//translations`` directory; +* the ``src/Resources//translations/`` directory; * the ``Resources/translations/`` directory inside of any bundle. The locations are listed here with the highest priority first. That is, you can -override the translation messages of a bundle in any of the top 2 directories. +override the translation messages of a bundle in any of the top two directories. The override mechanism works at a key level: only the overridden keys need to be listed in a higher priority message file. When a key is not found @@ -359,14 +371,14 @@ must be named according to the following path: ``domain.locale.loader``: * **locale**: The locale that the translations are for (e.g. ``en_GB``, ``en``, etc); * **loader**: How Symfony should load and parse the file (e.g. ``xlf``, - ``php``, ``yml``, etc). + ``php``, ``yaml``, etc). The loader can be the name of any registered loader. By default, Symfony provides many loaders, including: * ``xlf``: XLIFF file; * ``php``: PHP file; -* ``yml``: YAML file. +* ``yaml``: YAML file. The choice of which loader to use is entirely up to you and is a matter of taste. The recommended option is to use ``xlf`` for translations. @@ -381,15 +393,15 @@ For more options, see :ref:`component-translator-message-catalogs`. .. code-block:: yaml - # app/config/config.yml + # config/packages/translation.yaml framework: translator: paths: - - '%kernel.project_dir%/translations' + - '%kernel.project_dir%/custom/path/to/translations' .. code-block:: xml - + - %kernel.project_dir%/translations + %kernel.project_dir%/custom/path/to/translations .. code-block:: php - // app/config/config.php + // config/packages/translation.php $container->loadFromExtension('framework', array( 'translator' => array( 'paths' => array( - '%kernel.project_dir%/translations', + '%kernel.project_dir%/custom/path/to/translations', ), ), )); @@ -455,7 +467,7 @@ checks translation resources for several locales: .. note:: - When Symfony doesn't find a translation in the given locale, it will + When Symfony can't find a translation in the given locale, it will add the missing translation to the log file. For details, see :ref:`reference-framework-translator-logging`. @@ -504,9 +516,10 @@ Learn more .. toctree:: :maxdepth: 1 - :glob: - /translation/* + translation/locale + translation/debug + translation/lint .. _`i18n`: https://en.wikipedia.org/wiki/Internationalization_and_localization .. _`ISO 3166-1 alpha-2`: https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes diff --git a/translation/debug.rst b/translation/debug.rst index 5ff68533669..b669a3197f7 100644 --- a/translation/debug.rst +++ b/translation/debug.rst @@ -8,52 +8,50 @@ How to Find Missing or Unused Translation Messages When maintaining an application or bundle, you may add or remove translation messages and forget to update the message catalogues. The ``debug:translation`` -command helps you to find these missing or unused translation messages. +command helps you to find these missing or unused translation messages templates: -Thanks to the messages extractors, the command will detect the translation -tag or filter usages in Twig templates: - -.. code-block:: jinja +.. configuration-block:: - {% trans %}Symfony is great{% endtrans %} + .. code-block:: twig - {{ 'Symfony is great'|trans }} + {# messages can be found when using the trans/transchoice filters and tags #} + {% trans %}Symfony is great{% endtrans %} - {{ 'Symfony is great'|transchoice(1) }} + {{ 'Symfony is great'|trans }} - {% transchoice 1 %}Symfony is great{% endtranschoice %} + {{ 'Symfony is great'|transchoice(1) }} -It will also detect the following translator usages in PHP templates: + {% transchoice 1 %}Symfony is great{% endtranschoice %} -.. code-block:: php + .. code-block:: php - $view['translator']->trans("Symfony is great"); + // messages can be found when using the trans() and transChoice() methods + $view['translator']->trans("Symfony is great"); - $view['translator']->transChoice('Symfony is great', 1); + $view['translator']->transChoice('Symfony is great', 1); .. caution:: - The extractors are not able to inspect the messages translated outside - templates which means that translator usages in form labels or inside - your controllers won't be detected. Dynamic translations involving variables - or expressions are not detected in templates, which means this example - won't be analyzed: + The extractors can't find messages translated outside templates, like form + labels or controllers. Dynamic translations using variables or expressions + in templates are not detected either: - .. code-block:: jinja + .. code-block:: twig + {# this translation uses a Twig variable, so it won't be detected #} {% set message = 'Symfony is great' %} {{ message|trans }} Suppose your application's default_locale is ``fr`` and you have configured ``en`` as the fallback locale (see :ref:`translation-configuration` and :ref:`translation-fallback` for how to configure these). And suppose -you've already setup some translations for the ``fr`` locale inside an AcmeDemoBundle: +you've already setup some translations for the ``fr`` locale: .. configuration-block:: .. code-block:: xml - + @@ -69,12 +67,12 @@ you've already setup some translations for the ``fr`` locale inside an AcmeDemoB .. code-block:: yaml - # src/Acme/AcmeDemoBundle/Resources/translations/messages.fr.yml + # translations/messages.fr.yaml Symfony is great: J'aime Symfony .. code-block:: php - // src/Acme/AcmeDemoBundle/Resources/translations/messages.fr.php + // translations/messages.fr.php return array( 'Symfony is great' => 'J\'aime Symfony', ); @@ -85,7 +83,7 @@ and for the ``en`` locale: .. code-block:: xml - + @@ -100,26 +98,32 @@ and for the ``en`` locale: .. code-block:: yaml - # src/Acme/AcmeDemoBundle/Resources/translations/messages.en.yml + # translations/messages.en.yaml Symfony is great: Symfony is great .. code-block:: php - // src/Acme/AcmeDemoBundle/Resources/translations/messages.en.php + // translations/messages.en.php return array( 'Symfony is great' => 'Symfony is great', ); -To inspect all messages in the ``fr`` locale for the AcmeDemoBundle, run: +To inspect all messages in the ``fr`` locale for the application, run: .. code-block:: terminal - $ php bin/console debug:translation fr AcmeDemoBundle + $ php bin/console debug:translation fr -You will get this output: + +----------+------------------+----------------------+-------------------------------+ + | State(s) | Id | Message Preview (fr) | Fallback Message Preview (en) | + +----------+------------------+----------------------+-------------------------------+ + | o | Symfony is great | J'aime Symfony | Symfony is great | + +----------+------------------+----------------------+-------------------------------+ -.. image:: /_images/translation/debug_1.png - :align: center + Legend: + x Missing message + o Unused message + = Same as the fallback message It shows you a table with the result when translating the message in the ``fr`` locale and the result when the fallback locale ``en`` would be used. On top @@ -131,8 +135,20 @@ because it is translated, but you haven't used it anywhere yet. Now, if you translate the message in one of your templates, you will get this output: -.. image:: /_images/translation/debug_2.png - :align: center +.. code-block:: terminal + + $ php bin/console debug:translation fr + + +----------+------------------+----------------------+-------------------------------+ + | State(s) | Id | Message Preview (fr) | Fallback Message Preview (en) | + +----------+------------------+----------------------+-------------------------------+ + | | Symfony is great | J'aime Symfony | Symfony is great | + +----------+------------------+----------------------+-------------------------------+ + + Legend: + x Missing message + o Unused message + = Same as the fallback message The state is empty which means the message is translated in the ``fr`` locale and used in one or more templates. @@ -140,8 +156,20 @@ and used in one or more templates. If you delete the message ``Symfony is great`` from your translation file for the ``fr`` locale and run the command, you will get: -.. image:: /_images/translation/debug_3.png - :align: center +.. code-block:: terminal + + $ php bin/console debug:translation fr + + +----------+------------------+----------------------+-------------------------------+ + | State(s) | Id | Message Preview (fr) | Fallback Message Preview (en) | + +----------+------------------+----------------------+-------------------------------+ + | x = | Symfony is great | J'aime Symfony | Symfony is great | + +----------+------------------+----------------------+-------------------------------+ + + Legend: + x Missing message + o Unused message + = Same as the fallback message The state indicates the message is missing because it is not translated in the ``fr`` locale but it is still used in the template. Moreover, the message @@ -152,8 +180,20 @@ the ``en`` locale. If you copy the content of the translation file in the ``en`` locale, to the translation file in the ``fr`` locale and run the command, you will get: -.. image:: /_images/translation/debug_4.png - :align: center +.. code-block:: terminal + + $ php bin/console debug:translation fr + + +----------+------------------+----------------------+-------------------------------+ + | State(s) | Id | Message Preview (fr) | Fallback Message Preview (en) | + +----------+------------------+----------------------+-------------------------------+ + | = | Symfony is great | J'aime Symfony | Symfony is great | + +----------+------------------+----------------------+-------------------------------+ + + Legend: + x Missing message + o Unused message + = Same as the fallback message You can see that the translations of the message are identical in the ``fr`` and ``en`` locales which means this message was probably copied from French @@ -164,13 +204,13 @@ domain: .. code-block:: terminal - $ php bin/console debug:translation en AcmeDemoBundle --domain=messages + $ php bin/console debug:translation en --domain=messages -When bundles have a lot of messages, it is useful to display only the unused -or only the missing messages, by using the ``--only-unused`` or ``--only-missing`` -switches: +When the application has a lot of messages, it is useful to display only the +unused or only the missing messages, by using the ``--only-unused`` or +``--only-missing`` options: .. code-block:: terminal - $ php bin/console debug:translation en AcmeDemoBundle --only-unused - $ php bin/console debug:translation en AcmeDemoBundle --only-missing + $ php bin/console debug:translation en --only-unused + $ php bin/console debug:translation en --only-missing diff --git a/translation/lint.rst b/translation/lint.rst index 0c64e4a427e..9fce4198f8a 100644 --- a/translation/lint.rst +++ b/translation/lint.rst @@ -15,21 +15,16 @@ translation file using the ``lint:yaml`` and ``lint:xliff`` commands: .. code-block:: terminal # lint a single file - $ ./bin/console lint:yaml app/Resources/translations/messages.en.yml - $ ./bin/console lint:xliff app/Resources/translations/messages.en.xlf + $ ./bin/console lint:yaml translations/messages.en.yml + $ ./bin/console lint:xliff translations/messages.en.xlf # lint a whole directory - $ ./bin/console lint:yaml app/Resources/translations - $ ./bin/console lint:xliff app/Resources/translations - - # lint a specific bundle - $ ./bin/console lint:yaml @AppBundle - $ ./bin/console lint:xliff @AppBundle + $ ./bin/console lint:yaml translations + $ ./bin/console lint:xliff translations The linter results can be exported to JSON using the ``--format`` option: .. code-block:: terminal - # lint a single file - $ ./bin/console lint:yaml app/Resources/translations --format=json - $ ./bin/console lint:xliff app/Resources/translations --format=json + $ ./bin/console lint:yaml translations/ --format=json + $ ./bin/console lint:xliff translations/ --format=json diff --git a/translation/locale.rst b/translation/locale.rst index d15e441b608..f81a57911e3 100644 --- a/translation/locale.rst +++ b/translation/locale.rst @@ -9,7 +9,7 @@ via the ``Request`` object:: use Symfony\Component\HttpFoundation\Request; - public function indexAction(Request $request) + public function index(Request $request) { $locale = $request->getLocale(); } @@ -61,8 +61,8 @@ by the routing system using the special ``_locale`` parameter: # config/routes.yaml contact: - path: /{_locale}/contact - defaults: { _controller: AppBundle:Contact:index } + path: /{_locale}/contact + controller: App\Controller\ContactContorller::index requirements: _locale: en|fr|de @@ -76,7 +76,7 @@ by the routing system using the special ``_locale`` parameter: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Contact:index + App\Controller\ContactContorller::index en|fr|de @@ -86,12 +86,13 @@ by the routing system using the special ``_locale`` parameter: // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; + use App\Controller\ContactContorller; $collection = new RouteCollection(); $collection->add('contact', new Route( '/{_locale}/contact', array( - '_controller' => 'AppBundle:Contact:index', + '_controller' => array(ContactController::class, 'index']), ), array( '_locale' => 'en|fr|de', @@ -130,13 +131,13 @@ the framework: .. code-block:: yaml - # app/config/config.yml + # config/packages/translation.yaml framework: default_locale: en .. code-block:: xml - + loadFromExtension('framework', array( 'default_locale' => 'en', )); From b15dba2790607d4881324ad5c0877e4f1cc9cd3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michae=CC=88l=20Perrin?= Date: Sat, 18 Nov 2017 15:23:08 +0200 Subject: [PATCH 0114/2437] Update HttpCache kernel documentation for Symfony 4 --- .../front_controllers_and_kernel.rst | 2 +- http_cache.rst | 36 ++++++++++--------- http_cache/cache_invalidation.rst | 8 ++--- reference/configuration/framework.rst | 6 ++-- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index 54cab74072a..59705b5401b 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -44,7 +44,7 @@ to `decorate`_ the kernel with additional features. Examples include: * Configuring the autoloader or adding additional autoloading mechanisms; * Adding HTTP level caching by wrapping the kernel with an instance of - :ref:`AppCache `; + :ref:`HttpCache `; * Enabling the :doc:`Debug Component `. The front controller can be chosen by requesting URLs like: diff --git a/http_cache.rst b/http_cache.rst index 21375c4dcee..fab88f07f92 100644 --- a/http_cache.rst +++ b/http_cache.rst @@ -77,23 +77,27 @@ but is a great way to start. For details on setting up Varnish, see :doc:`/http_cache/varnish`. -Enabling the proxy is easy: each application comes with a caching kernel (``AppCache``) -that wraps the default one (``AppKernel``). The caching Kernel *is* the reverse -proxy. +To enable the proxy, first create a caching kernel:: -To enable caching, modify the code of your front controller. You can also make these -changes to ``index.php`` to add caching to the ``dev`` environment:: + // src/CacheKernel.php + use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; + + class CacheKernel extends HttpCache + { + } + +Modify the code of your front controller to wrap the default kernel into the +caching kernel: + +.. code-block:: diff // public/index.php - use Symfony\Component\HttpFoundation\Request; // ... - $kernel = new AppKernel('prod', false); - $kernel->loadClassCache(); + $kernel = new Kernel($_SERVER['APP_ENV'] ?? 'dev', $_SERVER['APP_DEBUG'] ?? ('prod' !== ($_SERVER['APP_ENV'] ?? 'dev'))); - // add (or uncomment) this new line! - // wrap the default Kernel with the AppCache one - $kernel = new AppCache($kernel); + + // Wrap the default Kernel with the CacheKernel one + + $kernel = new CacheKernel($kernel); $request = Request::createFromGlobals(); // ... @@ -115,15 +119,15 @@ from your application and returning them to the client. error_log($kernel->getLog()); -The ``AppCache`` object has a sensible default configuration, but it can be +The ``CacheKernel`` object has a sensible default configuration, but it can be finely tuned via a set of options you can set by overriding the :method:`Symfony\\Bundle\\FrameworkBundle\\HttpCache\\HttpCache::getOptions` method:: - // app/AppCache.php + // src/CacheKernel.php use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; - class AppCache extends HttpCache + class CacheKernel extends HttpCache { protected function getOptions() { @@ -150,7 +154,7 @@ information about cache hits and misses. website or when you deploy your website to a shared host where you cannot install anything beyond PHP code. But being written in PHP, it cannot be as fast as a proxy written in C. - + Fortunately, since all reverse proxies are effectively the same, you should be able to switch to something more robust - like Varnish - without any problems. See :doc:`How to use Varnish ` @@ -192,7 +196,7 @@ These four headers are used to help cache your responses via *two* different mod All of the HTTP headers you'll read about are *not* invented by Symfony! They're part of an HTTP specification that's used by sites all over the web. To dig deeper - into HTTP Caching, check out the documents `RFC 7234 - Caching`_ and + into HTTP Caching, check out the documents `RFC 7234 - Caching`_ and `RFC 7232 - Conditional Requests`_. As a web developer, you are strongly urged to read the specification. Its diff --git a/http_cache/cache_invalidation.rst b/http_cache/cache_invalidation.rst index a67adb470c4..435a1115148 100644 --- a/http_cache/cache_invalidation.rst +++ b/http_cache/cache_invalidation.rst @@ -47,17 +47,17 @@ the word "PURGE" is a convention, technically this can be any string) instead of ``GET`` and make the cache proxy detect this and remove the data from the cache instead of going to the application to get a response. -Here is how you can configure the Symfony reverse proxy to support the -``PURGE`` HTTP method:: +Here is how you can configure the Symfony reverse proxy (See :doc:`/http_cache`) +to support the ``PURGE`` HTTP method:: - // app/AppCache.php + // src/CacheKernel.php use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; // ... - class AppCache extends HttpCache + class CacheKernel extends HttpCache { protected function invalidate(Request $request, $catch = false) { diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 374edd23263..360fb7d5d07 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -173,17 +173,17 @@ named ``kernel.http_method_override``. .. caution:: - If you're using the :ref:`AppCache Reverse Proxy ` + If you're using the :ref:`HttpCache Reverse Proxy ` with this option, the kernel will ignore the ``_method`` parameter, which could lead to errors. To fix this, invoke the ``enableHttpMethodParameterOverride()`` method before creating the ``Request`` object:: - // web/app.php + // public/index.php // ... - $kernel = new AppCache($kernel); + $kernel = new CacheKernel($kernel); Request::enableHttpMethodParameterOverride(); // <-- add this line $request = Request::createFromGlobals(); From d0ede9911e75cc5a6e967cb202322a7c49cc5649 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 22 Nov 2017 19:28:27 +0100 Subject: [PATCH 0115/2437] Updated templating/* articles to Symfony 4 --- templating.rst | 30 +++---- templating/PHP.rst | 107 +++++++---------------- templating/debug.rst | 4 +- templating/embedding_controllers.rst | 6 +- templating/formats.rst | 4 +- templating/global_variables.rst | 22 ++--- templating/hinclude.rst | 12 +-- templating/namespaced_paths.rst | 54 ++++++------ templating/overriding.rst | 17 ++-- templating/render_without_controller.rst | 40 +++++---- templating/syntax.rst | 2 +- templating/twig_extension.rst | 18 ++-- 12 files changed, 133 insertions(+), 183 deletions(-) diff --git a/templating.rst b/templating.rst index 46753815714..00cd2c27602 100644 --- a/templating.rst +++ b/templating.rst @@ -575,7 +575,7 @@ configuration: /** * @Route("/", name="welcome") */ - public function indexAction() + public function index() { // ... } @@ -586,11 +586,11 @@ configuration: # config/routes.yaml welcome: path: / - defaults: { _controller: AppBundle:Welcome:index } + controller: App\Controller\WelcomeController::index .. code-block:: xml - + - AppBundle:Welcome:index + App\Controller\WelcomeController::index @@ -610,7 +610,7 @@ configuration: $collection = new RouteCollection(); $collection->add('welcome', new Route('/', array( - '_controller' => 'AppBundle:Welcome:index', + '_controller' => 'App\Controller\WelcomeController::index', ))); return $collection; @@ -644,7 +644,7 @@ route: /** * @Route("/article/{slug}", name="article_show") */ - public function showAction($slug) + public function show($slug) { // ... } @@ -654,8 +654,8 @@ route: # config/routes.yaml article_show: - path: /article/{slug} - defaults: { _controller: AppBundle:Article:show } + path: /article/{slug} + controller: App\Controller\ArticleController::show .. code-block:: xml @@ -667,7 +667,7 @@ route: http://symfony.com/schema/routing/routing-1.0.xsd"> - AppBundle:Article:show + App\Controller\ArticleController::show @@ -679,7 +679,7 @@ route: $collection = new RouteCollection(); $collection->add('article_show', new Route('/article/{slug}', array( - '_controller' => 'AppBundle:Article:show', + '_controller' => 'App\Controller\ArticleController::show', ))); return $collection; @@ -791,10 +791,10 @@ advantage of Symfony's template inheritance. .. tip:: This section will teach you the philosophy behind including stylesheet - and JavaScript assets in Symfony. Symfony is also compatible with another - library, called Assetic, which follows this philosophy but allows you to do - much more interesting things with those assets. For more information on - using Assetic see :doc:`/frontend/assetic/asset_management`. + and JavaScript assets in Symfony. If you are interested in compiling and + creating those assets, check out the :doc:`Webpack Encore documentation ` + a tool that seamlessly integrates Webpack and other modern JavaScript tools + into Symfony applications. Start by adding two blocks to your base template that will hold your assets: one called ``stylesheets`` inside the ``head`` tag and another called ``javascripts`` @@ -878,7 +878,7 @@ to add to the parent block's content (and not actually *replace* it), you should use the ``parent()`` Twig function to include everything from the ``stylesheets`` block of the base template. -You can also include assets located in your bundles' ``Resources/public`` folder. +You can also include assets located in your bundles' ``Resources/public/`` folder. You will need to run the ``php bin/console assets:install target [--symlink]`` command, which copies (or symlinks) files into the correct location. (target is by default the "web/" directory of your application). diff --git a/templating/PHP.rst b/templating/PHP.rst index b9449edd8b2..11a546132d3 100644 --- a/templating/PHP.rst +++ b/templating/PHP.rst @@ -24,7 +24,7 @@ your application configuration file: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... templating: @@ -32,7 +32,7 @@ your application configuration file: .. code-block:: xml - + loadFromExtension('framework', array( // ... 'templating' => array( @@ -67,28 +68,11 @@ below renders the ``index.html.php`` template:: // src/Controller/HelloController.php // ... - public function indexAction($name) + public function index($name) { - return $this->render( - 'AppBundle:Hello:index.html.php', - array('name' => $name) - ); - } - -You can also use the `@Template`_ shortcut to render the default -``AppBundle:Hello:index.html.php`` template:: - - // src/Controller/HelloController.php - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; - - // ... - - /** - * @Template(engine="php") - */ - public function indexAction($name) - { - return array('name' => $name); + return $this->render('hello/index.html.php', array( + 'name' => $name + )); } .. caution:: @@ -98,24 +82,24 @@ You can also use the `@Template`_ shortcut to render the default the ``@`` notation for Twig namespaces will no longer be supported for the ``render()`` method:: - public function indexAction() + public function index() { // ... // namespaced templates will no longer work in controllers - $this->render('@App/Default/index.html.twig'); + $this->render('@SomeNamespace/hello/index.html.twig'); // you must use the traditional template notation - $this->render('AppBundle:Default:index.html.twig'); + $this->render('hello/index.html.twig'); } .. code-block:: twig {# inside a Twig template, namespaced templates work as expected #} - {{ include('@App/Default/index.html.twig') }} + {{ include('@SomeNamespace/hello/index.html.twig') }} {# traditional template notation will also work #} - {{ include('AppBundle:Default:index.html.twig') }} + {{ include('hello/index.html.twig') }} .. index:: @@ -135,31 +119,24 @@ the ``extend()`` call: .. code-block:: html+php - extend('AppBundle::layout.html.php') ?> + extend('layout.html.php') ?> Hello ! -The ``AppBundle::layout.html.php`` notation sounds familiar, doesn't it? It -is the same notation used to reference a template. The ``::`` part simply -means that the controller element is empty, so the corresponding file is -directly stored under ``views/``. - Now, have a look at the ``layout.html.php`` file: .. code-block:: html+php - extend('::base.html.php') ?> + extend('base.html.php') ?>

    Hello Application

    output('_content') ?> -The layout is itself decorated by another one (``::base.html.php``). Symfony +The layout is itself decorated by another one (``base.html.php``). Symfony supports multiple decoration levels: a layout can itself be decorated by -another one. When the bundle part of the template name is empty, views are -looked for in the ``templates/`` directory. This directory stores -global views for your entire project: +another one: .. code-block:: html+php @@ -196,8 +173,8 @@ decorating the template. In the ``index.html.php`` template, define a .. code-block:: html+php - - extend('AppBundle::layout.html.php') ?> + + extend('layout.html.php') ?> set('title', 'Hello World Application') ?> @@ -238,17 +215,17 @@ Create a ``hello.html.php`` template: .. code-block:: html+php - + Hello ! And change the ``index.html.php`` template to include it: .. code-block:: html+php - - extend('AppBundle::layout.html.php') ?> + + extend('layout.html.php') ?> - render('AppBundle:Hello:hello.html.php', array('name' => $name)) ?> + render('hello/hello.html.php', array('name' => $name)) ?> The ``render()`` method evaluates and returns the content of another template (this is the exact same method as the one used in the controller). @@ -270,33 +247,15 @@ If you create a ``fancy`` action, and want to include it into the render( - new \Symfony\Component\HttpKernel\Controller\ControllerReference('AppBundle:Hello:fancy', array( - 'name' => $name, - 'color' => 'green', - )) + new \Symfony\Component\HttpKernel\Controller\ControllerReference( + 'App\Controller\HelloController::fancy', + array( + 'name' => $name, + 'color' => 'green', + ) + ) ) ?> -Here, the ``AppBundle:Hello:fancy`` string refers to the ``fancy`` action of the -``Hello`` controller:: - - // src/Controller/HelloController.php - - class HelloController extends Controller - { - public function fancyAction($name, $color) - { - // create some object, based on the $color variable - $object = ...; - - return $this->render('AppBundle:Hello:fancy.html.php', array( - 'name' => $name, - 'object' => $object - )); - } - - // ... - } - But where is the ``$view['actions']`` array element defined? Like ``$view['slots']``, it's called a template helper, and the next section tells you more about those. @@ -332,10 +291,10 @@ pattern: .. code-block:: yaml - # src/Resources/config/routing.yml - hello: # The route name - path: /hello/{name} - defaults: { _controller: AppBundle:Hello:index } + # config/routes.yaml + hello: + path: /hello/{name} + controller: App\Controller\HelloController::index Using Assets: Images, JavaScripts and Stylesheets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/templating/debug.rst b/templating/debug.rst index 691dd2f731b..2f22b107494 100644 --- a/templating/debug.rst +++ b/templating/debug.rst @@ -7,7 +7,7 @@ How to Dump Debug Information in Twig Templates =============================================== -When using PHP, you can use the +When using PHP templates, you can use the :ref:`dump() function from the VarDumper component ` if you need to quickly find the value of a variable passed. This is useful, for example, inside your controller:: @@ -19,7 +19,7 @@ for example, inside your controller:: class ArticleController extends Controller { - public function recentListAction() + public function recentList() { $articles = ...; dump($articles); diff --git a/templating/embedding_controllers.rst b/templating/embedding_controllers.rst index 8f8f8e11336..437ac6f080b 100644 --- a/templating/embedding_controllers.rst +++ b/templating/embedding_controllers.rst @@ -26,7 +26,7 @@ articles:: class ArticleController extends Controller { - public function recentArticlesAction($max = 3) + public function recentArticles($max = 3) { // make a database call or other logic // to get the "$max" most recent articles @@ -68,7 +68,7 @@ The ``recent_list`` template is perfectly straightforward: you'll learn how to do this correctly. To include the controller, you'll need to refer to it using the standard -string syntax for controllers (i.e. **controllerPath**::**action**): +string syntax for controllers (i.e. **controllerNamespace**::**action**): .. configuration-block:: @@ -98,4 +98,4 @@ string syntax for controllers (i.e. **controllerPath**::**action**): ) ?> -The result of an embedded controler can also be :doc:`cached ` +The result of an embedded controller can also be :doc:`cached ` diff --git a/templating/formats.rst b/templating/formats.rst index 7d1893b50f8..45f7274a7a5 100644 --- a/templating/formats.rst +++ b/templating/formats.rst @@ -30,7 +30,7 @@ pattern is to do the following:: /** * @Route("/{slug}") */ - public function showAction(Request $request, $slug) + public function show(Request $request, $slug) { // retrieve the article based on $slug $article = ...; @@ -53,7 +53,7 @@ special ``_format`` placeholder in your route definition:: /** * @Route("/{slug}.{_format}", defaults={"_format": "html"}) */ - public function showAction(Request $request, $slug) + public function show(Request $request, $slug) { // ... } diff --git a/templating/global_variables.rst b/templating/global_variables.rst index 332ddefaa0c..bfc2dcef08a 100644 --- a/templating/global_variables.rst +++ b/templating/global_variables.rst @@ -5,13 +5,13 @@ How to Inject Variables into all Templates (i.e. global Variables) ================================================================== Sometimes you want a variable to be accessible to all the templates you use. -This is possible inside your ``app/config/config.yml`` file: +This is possible inside your ``config/packages/twig.yaml`` file: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: # ... globals: @@ -19,7 +19,7 @@ This is possible inside your ``app/config/config.yml`` file: .. code-block:: xml - + loadFromExtension('twig', array( // ... 'globals' => array( @@ -61,7 +61,7 @@ system, which lets you isolate or reuse the value: .. code-block:: yaml - # app/config/parameters.yml + # config/services.yaml parameters: ga_tracking: UA-xxxxx-x @@ -69,14 +69,14 @@ system, which lets you isolate or reuse the value: .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: globals: ga_tracking: '%ga_tracking%' .. code-block:: xml - + loadFromExtension('twig', array( 'globals' => array( 'ga_tracking' => '%ga_tracking%', @@ -122,7 +122,7 @@ This should feel familiar, as it's the same syntax you use in service configurat .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: # ... globals: @@ -131,7 +131,7 @@ This should feel familiar, as it's the same syntax you use in service configurat .. code-block:: xml - + loadFromExtension('twig', array( // ... 'globals' => array( diff --git a/templating/hinclude.rst b/templating/hinclude.rst index c1fa4fa7a07..2768b15875b 100644 --- a/templating/hinclude.rst +++ b/templating/hinclude.rst @@ -44,14 +44,14 @@ tags: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... fragments: { path: /_fragment } .. code-block:: xml - + loadFromExtension('framework', array( // ... 'fragments' => array('path' => '/_fragment'), @@ -81,7 +81,7 @@ in your application configuration: .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: # ... templating: @@ -89,7 +89,7 @@ in your application configuration: .. code-block:: xml - + loadFromExtension('framework', array( // ... 'templating' => array( diff --git a/templating/namespaced_paths.rst b/templating/namespaced_paths.rst index 8c191ad4b2e..59e76e7477f 100644 --- a/templating/namespaced_paths.rst +++ b/templating/namespaced_paths.rst @@ -4,40 +4,35 @@ How to Use and Register Namespaced Twig Paths ============================================= -Usually, when you refer to a template, you'll use the Twig namespaced paths, which -are automatically registered for your bundles: +Usually, when you refer to a template, you'll use the relative path from the +main ``templates/`` dir at the root of the project: .. code-block:: twig - {% extends "@App/layout.html.twig" %} - {{ include('@App/Foo/bar.html.twig') }} + {# this template is located in templates/layout.html.twig #} + {% extends "layout.html.twig" %} -.. note:: + {# this template is located in templates/user/profile.html.twig #} + {{ include('user/profile.html.twig') }} - In the past, Symfony used a different syntax to refer to templates. This - format, which uses colons (``:``) to separate each template path section, is - less consistent and has worse performance than the Twig syntax. For reference - purposes, this is the equivalent notation of the previous example: - - .. code-block:: twig - - {# the following template syntax is no longer recommended #} - {% extends "AppBundle::layout.html.twig" %} - {{ include('AppBundle:Foo:bar.html.twig') }} +If the application defines lots of templates and stores them in deep nested +directories, you may consider using **Twig namespaces**, which create shortcuts +to template directories. Registering your own Namespaces ------------------------------- -You can also register your own custom namespaces. Suppose that you're using -some third-party library that includes Twig templates that live in -``vendor/acme/foo-bar/templates``. First, register a namespace for this -directory: +Suppose that you're using some third-party library that includes Twig templates +that live in ``vendor/acme/foo-bar/templates/``. This path is too long, so you +can define a ``foo_bar`` Twig namespace as a shortcut. + +First, register a namespace for this directory: .. configuration-block:: .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: # ... paths: @@ -45,7 +40,7 @@ directory: .. code-block:: xml - + loadFromExtension('twig', array( 'paths' => array( '%kernel.project_dir%/vendor/acme/foo-bar/templates' => 'foo_bar', ), )); -The registered namespace is called ``foo_bar``, which refers to the -``vendor/acme/foo-bar/templates`` directory. Assuming there's a file -called ``sidebar.twig`` in that directory, you can use it easily: +The registered namespace is called ``foo_bar``, but you must prefix the ``@`` +character when using it in templates (that's how Twig can differentiate +namespaces from regular paths). Assuming there's a file called ``sidebar.twig`` +in the ``vendor/acme/foo-bar/templates/`` directory, you can refer to it as: .. code-block:: twig @@ -78,7 +74,7 @@ called ``sidebar.twig`` in that directory, you can use it easily: Multiple Paths per Namespace ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can also assign several paths to the same template namespace. The order in +A single Twig namespace can be associated with multiple paths. The order in which paths are configured is very important, because Twig will always load the first template that exists, starting from the first configured path. This feature can be used as a fallback mechanism to load generic templates when the @@ -88,7 +84,7 @@ specific template doesn't exist. .. code-block:: yaml - # app/config/config.yml + # config/packages/twig.yaml twig: # ... paths: @@ -98,7 +94,7 @@ specific template doesn't exist. .. code-block:: xml - + loadFromExtension('twig', array( 'paths' => array( '%kernel.project_dir%/vendor/acme/themes/theme1' => 'theme', diff --git a/templating/overriding.rst b/templating/overriding.rst index 6b5f96c6efe..5247c155aa0 100644 --- a/templating/overriding.rst +++ b/templating/overriding.rst @@ -15,8 +15,8 @@ the template for a blog list page. Inside the bundle, the template you want to override lives at ``Resources/views/Blog/index.html.twig``. To override the bundle template, just copy the ``index.html.twig`` template -from the bundle to ``app/Resources/AcmeBlogBundle/views/Blog/index.html.twig`` -(the ``app/Resources/AcmeBlogBundle`` directory won't exist, so you'll need +from the bundle to ``templates/bundles/AcmeBlogBundle/Blog/index.html.twig`` +(the ``templates/bundles/AcmeBlogBundle/`` directory won't exist, so you'll need to create it). You're now free to customize the template. .. caution:: @@ -25,12 +25,7 @@ to create it). You're now free to customize the template. cache (``php bin/console cache:clear``), even if you are in debug mode. This logic also applies to *any* template that lives in a bundle: just follow the -convention: ``app/Resources/{BUNDLE_NAME}/views/{PATH/TO/TEMPLATE.html.twig}``. - -.. note:: - - You can also override templates from within a bundle by using bundle - inheritance. For more information, see :doc:`/bundles/inheritance`. +convention: ``templates/bundles/{BUNDLE_NAME}/{PATH/TO/TEMPLATE.html.twig}``. .. _templating-overriding-core-templates: @@ -40,10 +35,10 @@ convention: ``app/Resources/{BUNDLE_NAME}/views/{PATH/TO/TEMPLATE.html.twig}``. Overriding Core Templates ~~~~~~~~~~~~~~~~~~~~~~~~~ -Since the Symfony Framework itself is just a bundle, core templates can be +Since the Symfony framework itself uses lots of bundles, core templates can be overridden in the same way. For example, the core TwigBundle contains a number of different "exception" and "error" templates that can be overridden by -copying each from the ``Resources/views/Exception`` directory of the TwigBundle -to, you guessed it, the ``app/Resources/TwigBundle/views/Exception`` directory. +copying each from the ``Resources/views/Exception/`` directory of the TwigBundle +to, you guessed it, the ``templates/bundles/TwigBundle/Exception/`` directory. .. _`KnpBundles.com`: http://knpbundles.com diff --git a/templating/render_without_controller.rst b/templating/render_without_controller.rst index 831bf327423..00b1a006f59 100644 --- a/templating/render_without_controller.rst +++ b/templating/render_without_controller.rst @@ -7,7 +7,8 @@ How to Render a Template without a custom Controller Usually, when you need to create a page, you need to create a controller and render a template from within that controller. But if you're rendering a simple template that doesn't need any data passed into it, you can avoid -creating the controller entirely, by using the built-in ``FrameworkBundle:Template:template`` +creating the controller entirely, by using the built-in +``Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction`` controller. For example, suppose you want to render a ``static/privacy.html.twig`` @@ -18,40 +19,43 @@ can do this without creating a controller: .. code-block:: yaml + # config/routes.yaml acme_privacy: - path: /privacy + path: /privacy + controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction defaults: - _controller: FrameworkBundle:Template:template - template: static/privacy.html.twig + template: static/privacy.html.twig .. code-block:: xml + - FrameworkBundle:Template:template + Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction static/privacy.html.twig .. code-block:: php + // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('acme_privacy', new Route('/privacy', array( - '_controller' => 'FrameworkBundle:Template:template', + '_controller' => 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction', 'template' => 'static/privacy.html.twig', ))); return $collection; -The ``FrameworkBundle:Template:template`` controller will simply render whatever -template you've passed as the ``template`` default value. +The ``TemplateController`` will simply render whatever template you've passed as +the ``template`` default value. You can of course also use this trick when rendering embedded controllers from within a template. But since the purpose of rendering a controller from @@ -71,9 +75,6 @@ this is probably only useful if you'd like to cache this page partial (see use Symfony\Component\Routing\Generator\UrlGeneratorInterface; ?> - render( $view['router']->url('acme_privacy', array()) ) ?> @@ -91,23 +92,25 @@ other variables in your route, you can control exactly how your page is cached: .. code-block:: yaml + # config/routes.yaml acme_privacy: - path: /privacy + path: /privacy + controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction defaults: - _controller: FrameworkBundle:Template:template - template: 'static/privacy.html.twig' - maxAge: 86400 - sharedAge: 86400 + template: 'static/privacy.html.twig' + maxAge: 86400 + sharedAge: 86400 .. code-block:: xml + - FrameworkBundle:Template:template + Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction static/privacy.html.twig 86400 86400 @@ -116,12 +119,13 @@ other variables in your route, you can control exactly how your page is cached: .. code-block:: php + // config/routes.php use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('acme_privacy', new Route('/privacy', array( - '_controller' => 'FrameworkBundle:Template:template', + '_controller' => 'Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction', 'template' => 'static/privacy.html.twig', 'maxAge' => 86400, 'sharedAge' => 86400, diff --git a/templating/syntax.rst b/templating/syntax.rst index a2effc5a493..0dbf0f93038 100644 --- a/templating/syntax.rst +++ b/templating/syntax.rst @@ -16,4 +16,4 @@ console command: $ php bin/console lint:twig templates/article/recent_list.html.twig # or by directory: - $ php bin/console lint:twig app/Resources/views + $ php bin/console lint:twig templates/ diff --git a/templating/twig_extension.rst b/templating/twig_extension.rst index f57fd16cc63..014c2e0d1e9 100644 --- a/templating/twig_extension.rst +++ b/templating/twig_extension.rst @@ -21,17 +21,21 @@ money: {# pass in the 3 optional arguments #} {{ product.price|price(2, ',', '.') }} -Create a class that extends ``\Twig_Extension`` and fill in the logic:: +Create a class that extends the ``AbstractExtension`` class defined by Twig and +fill in the logic:: // src/Twig/AppExtension.php namespace App\Twig; - class AppExtension extends \Twig_Extension + use Twig\Extension\AbstractExtension; + use Twig\TwigFilter; + + class AppExtension extends AbstractExtension { public function getFilters() { return array( - new \Twig_SimpleFilter('price', array($this, 'priceFilter')), + new TwigFilter('price', array($this, 'priceFilter')), ); } @@ -44,14 +48,6 @@ Create a class that extends ``\Twig_Extension`` and fill in the logic:: } } -.. note:: - -   Prior to Twig 1.26, your extension had to define an additional ``getName()`` - method that returned a string with the extension's internal name (e.g. - ``app.my_extension``). When your extension needs to be compatible with Twig - versions before 1.26, include this method which is omitted in the example - above. - .. tip:: Along with custom filters, you can also add custom `functions`_ and register From 6259931025e7cc0d59ddb804a5c1eeb00d7c855e Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 22 Nov 2017 14:24:21 -0500 Subject: [PATCH 0116/2437] Finishing major overhaul of the main Doctrine chapter --- _build/redirection_map | 7 +- doctrine.rst | 825 +++++++++++++---------------- doctrine/console.rst | 43 -- doctrine/mapping_model_classes.rst | 149 ------ doctrine/repository.rst | 102 ---- 5 files changed, 361 insertions(+), 765 deletions(-) delete mode 100644 doctrine/console.rst delete mode 100644 doctrine/mapping_model_classes.rst delete mode 100644 doctrine/repository.rst diff --git a/_build/redirection_map b/_build/redirection_map index 89d6cfaa510..272c7dc6782 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -138,18 +138,21 @@ /cookbook/deployment/platformsh /deployment/platformsh /cookbook/deployment/tools /deployment/tools /cookbook/doctrine/common_extensions /doctrine/common_extensions -/cookbook/doctrine/console /doctrine/console +/cookbook/doctrine/console /doctrine /cookbook/doctrine/custom_dql_functions /doctrine/custom_dql_functions /cookbook/doctrine/dbal /doctrine/dbal /cookbook/doctrine/event_listeners_subscribers /doctrine/event_listeners_subscribers /cookbook/doctrine/index /doctrine -/cookbook/doctrine/mapping_model_classes /doctrine/mapping_model_classes +/cookbook/doctrine/mapping_model_classes /doctrine +/doctrine/mapping_model_classes /doctrine /cookbook/doctrine/mongodb_session_storage /doctrine/mongodb_session_storage /cookbook/doctrine/multiple_entity_managers /doctrine/multiple_entity_managers /cookbook/doctrine/pdo_session_storage /doctrine/pdo_session_storage /cookbook/doctrine/registration_form /doctrine/registration_form /cookbook/doctrine/resolve_target_entity /doctrine/resolve_target_entity /cookbook/doctrine/reverse_engineering /doctrine/reverse_engineering +/doctrine/repository /doctrine +/doctrine/console /doctrine /cookbook/email/cloud /email/cloud /cookbook/email/dev_environment /email/dev_environment /cookbook/email/email /email diff --git a/doctrine.rst b/doctrine.rst index 5b989103197..e318bfa899b 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -38,232 +38,104 @@ The database connection information is stored as an environment variable called # customize this line! DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" -----> HERE + # to use sqlite: + # DATABASE_URL="sqlite://%kernel.project_dir%/var/app.db" -Now that Doctrine can connect to your database, the following command -can automatically generate an empty ``test_project`` database for you: +Now that your connection parameters are setup, Doctrine can create the ``db_name`` +database for you: .. code-block:: terminal $ php bin/console doctrine:database:create -.. sidebar:: Setting up the Database to be UTF8 - - One mistake even seasoned developers make when starting a Symfony project - is forgetting to set up default charset and collation on their database, - ending up with latin type collations, which are default for most databases. - They might even remember to do it the very first time, but forget that - it's all gone after running a relatively common command during development: - - .. code-block:: terminal - - $ php bin/console doctrine:database:drop --force - $ php bin/console doctrine:database:create - - Setting UTF8 defaults for MySQL is as simple as adding a few lines to - your configuration file (typically ``my.cnf``): - - .. code-block:: ini - - [mysqld] - # Version 5.5.3 introduced "utf8mb4", which is recommended - collation-server = utf8mb4_unicode_ci # Replaces utf8_unicode_ci - character-set-server = utf8mb4 # Replaces utf8 - - You can also change the defaults for Doctrine so that the generated SQL - uses the correct character set. - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - doctrine: - dbal: - charset: utf8mb4 - default_table_options: - charset: utf8mb4 - collate: utf8mb4_unicode_ci - - .. code-block:: xml - - - - - - - - utf8mb4 - utf8mb4_unicode_ci - - - - - .. code-block:: php - - // app/config/config.php - $configuration->loadFromExtension('doctrine', array( - 'dbal' => array( - 'charset' => 'utf8mb4', - 'default_table_options' => array( - 'charset' => 'utf8mb4', - 'collate' => 'utf8mb4_unicode_ci', - ) - ), - )); - - We recommend against MySQL's ``utf8`` character set, since it does not - support 4-byte unicode characters, and strings containing them will be - truncated. This is fixed by the `newer utf8mb4 character set`_. -.. note:: +.. tip:: - If you want to use SQLite as your database, you need to set the path - where your database file should be stored: - - .. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - doctrine: - dbal: - driver: pdo_sqlite - path: '%kernel.project_dir%/app/sqlite.db' - charset: UTF8 - - .. code-block:: xml - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('doctrine', array( - 'dbal' => array( - 'driver' => 'pdo_sqlite', - 'path' => '%kernel.project_dir%/app/sqlite.db', - 'charset' => 'UTF-8', - ), - )); + There are many other Doctrine commands. To see a full list, run + ``php bin/console list doctrine``. Creating an Entity Class ------------------------ Suppose you're building an application where products need to be displayed. Without even thinking about Doctrine or databases, you already know that -you need a ``Product`` object to represent those products. Create this class -inside the ``Entity`` directory of your ``src``:: +you need a ``Product`` object to represent those products. Use the ``make:entity`` +command to create this class for you: - // src/Entity/Product.php - namespace App\Entity; +.. code-block:: terminal - class Product - { - private $name; - private $price; - private $description; - } + $ php bin/console make:entity Product -The class - often called an "entity", meaning *a basic class that holds data* - -is simple and helps fulfill the business requirement of needing products -in your application. This class can't be persisted to a database yet - it's -just a simple PHP class. +You now have a new ``src/Entity/Product.php`` file:: -.. tip:: + // src/Entity/Product.php + namespace App\Entity; - Once you learn the concepts behind Doctrine, you can have Doctrine create - simple entity classes for you. This will ask you interactive questions - to help you build any entity: + use Doctrine\ORM\Mapping as ORM; - .. code-block:: terminal + /** + * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") + * @ORM\Table() + */ + class Product + { + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + private $id; - $ php bin/console doctrine:generate:entity + // add your own fields + } -.. index:: - single: Doctrine; Adding mapping metadata +This class is called an "entity". And soon, you will be able to save and query Product +objects to a ``product`` table in your database. .. _doctrine-adding-mapping: -Add Mapping Information ------------------------ +Mapping More Fields / Columns +----------------------------- -Doctrine allows you to work with databases in a much more interesting way -than just fetching rows of scalar data into an array. Instead, Doctrine -allows you to fetch entire *objects* out of the database, and to persist -entire objects to the database. For Doctrine to be able to do this, you -must *map* your database tables to specific PHP classes, and the columns -on those tables must be mapped to specific properties on their corresponding -PHP classes. +Each property in the ``Product`` entity can be mapped to a column in the ``product`` +table. By adding some mapping configuration, Doctrine will be able to save a Product +object to the ``product`` table *and* query from the ``product`` table and turn +that data into ``Product`` objects: .. image:: /_images/doctrine/mapping_single_entity.png :align: center -You'll provide this mapping information in the form of "metadata", a collection -of rules that tells Doctrine exactly how the ``Product`` class and its -properties should be *mapped* to a specific database table. This metadata -can be specified in a number of different formats, including YAML, XML or -directly inside the ``Product`` class via DocBlock annotations: +Let's give the ``Product`` entity class three more properties and map them to columns +in the database. This is usually done with annotations: .. configuration-block:: .. code-block:: php-annotations // src/Entity/Product.php - namespace App\Entity; + // ... + // this use statement is needed for the annotations use Doctrine\ORM\Mapping as ORM; - /** - * @ORM\Entity - * @ORM\Table(name="product") - */ class Product { /** - * @ORM\Column(type="integer") * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") + * @ORM\GeneratedValue + * @ORM\Column(type="integer") */ private $id; /** - * @ORM\Column(type="string", length=100) + * @ORM\Column(type="string", length=100, nullable=false) */ private $name; /** - * @ORM\Column(type="decimal", scale=2) + * @ORM\Column(type="decimal", scale=2, nullable=false) */ private $price; - - /** - * @ORM\Column(type="text") - */ - private $description; } .. code-block:: yaml @@ -271,7 +143,6 @@ directly inside the ``Product`` class via DocBlock annotations: # src/Resources/config/doctrine/Product.orm.yml App\Entity\Product: type: entity - table: product id: id: type: integer @@ -280,11 +151,11 @@ directly inside the ``Product`` class via DocBlock annotations: name: type: string length: 100 + nullable: false price: type: decimal scale: 2 - description: - type: text + nullable: false .. code-block:: xml @@ -295,212 +166,234 @@ directly inside the ``Product`` class via DocBlock annotations: xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> - + - - - + + -.. note:: +Doctrine supports a wide variety of different field types, each with their own options. +To see a full list of types and options, see `Doctrine's Mapping Types documentation`_. - A bundle can accept only one metadata definition format. For example, it's - not possible to mix YAML metadata definitions with annotated PHP entity - class definitions. +.. caution:: -.. tip:: + Be careful not to use reserved SQL keywords as your table or column names + (e.g. ``GROUP`` or ``USER``). See Doctrine's `Reserved SQL keywords documentation`_ + for details on how to escape these. Or, configure the table name with + ``@ORM\Table(name="groups")`` or the column name with the ``name="group_name"`` + option. - The table name is optional and if omitted, will be determined automatically - based on the name of the entity class. +.. _doctrine-creating-the-database-tables-schema: -Doctrine allows you to choose from a wide variety of different field types, -each with their own options. For information on the available field types, -see the :ref:`doctrine-field-types` section. +Migrations: Creating the Database Tables/Schema +----------------------------------------------- -.. seealso:: +The ``Product`` class is fully-configured and ready to save to a ``product`` table. +Of course, your database doesn't actually have the ``product`` table yet. To add +the table, you can leverage the `DoctrineMigrationsBundle`_, which is already installed: - You can also check out Doctrine's `Basic Mapping Documentation`_ for - all details about mapping information. If you use annotations, you'll - need to prepend all annotations with ``ORM\`` (e.g. ``ORM\Column(...)``), - which is not shown in Doctrine's documentation. You'll also need to include - the ``use Doctrine\ORM\Mapping as ORM;`` statement, which *imports* the - ``ORM`` annotations prefix. +.. code-block:: terminal -.. caution:: + $ php bin/console doctrine:migrations:diff - Be careful if the names of your entity classes (or their properties) - are also reserved SQL keywords like ``GROUP`` or ``USER``. For example, - if your entity's class name is ``Group``, then, by default, the corresponding - table name would be ``group``. This will cause an SQL error in some database - engines. See Doctrine's `Reserved SQL keywords documentation`_ for details - on how to properly escape these names. Alternatively, if you're free - to choose your database schema, simply map to a different table name - or column name. See Doctrine's `Creating Classes for the Database`_ - and `Property Mapping`_ documentation. +If everything worked, you should see something like this: -.. note:: + Generated new migration class to + "/path/to/project/doctrine/src/Migrations/Version20171122151511.php" + from schema differences. - When using another library or program (e.g. Doxygen) that uses annotations, - you should place the ``@IgnoreAnnotation`` annotation on the class to - indicate which annotations Symfony should ignore. +If you open this file, it contains the SQL needed to update your database! To run +that SQL, execute your migrations: - For example, to prevent the ``@fn`` annotation from throwing an exception, - add the following:: +.. code-block:: terminal - /** - * @IgnoreAnnotation("fn") - */ - class Product + $ php bin/console doctrine:migrations:migrate + +This command executes all migration files that have not already been run against +your database. + +Migrations & Adding more Fields +------------------------------- + +But what if you need to add a new field property to ``Product``, like a ``description``? + +.. code-block:: diff + + // src/Entity/Product.php + // ... + + class Product + { // ... -.. tip:: + + /** + + * @ORM\Column(type="text") + + */ + + private $description; + } + +The new property is mapped, but it doesn't exist yet in the ``product`` table. No +problem! Just generate a new migration: + +.. code-block:: terminal + + $ php bin/console doctrine:migrations:diff + +This time, the SQL in the generated file will look like this: + +.. code-block:: sql - After creating your entities you should validate the mappings with the - following command: + ALTER TABLE product ADD description LONGTEXT NOT NULL - .. code-block:: terminal +The migration system is *smart*. It compares all of your entities with the current +state of the database and generates the SQL needed to synchronize them! Just like +before, execute your migrations: - $ php bin/console doctrine:schema:validate +.. code-block:: terminal + + $ php bin/console doctrine:migrations:migrate + +This will only execute the *one* new migration file, because DoctrineMigrationsBundle +knows that the first migration was already executed earlier. Behind the scenes, it +automatically manages a ``migration_versions`` table to track this. + +Each time you make a change to your schema, run these two commands to generate the +migration and then execute it. Be sure to commit the migration files and run execute +them when you deploy. .. _doctrine-generating-getters-and-setters: Generating Getters and Setters ------------------------------ -Even though Doctrine now knows how to persist a ``Product`` object to the -database, the class itself isn't really useful yet. Since ``Product`` is just -a regular PHP class with ``private`` properties, you need to create ``public`` -getter and setter methods (e.g. ``getName()``, ``setName($name)``) in order -to access its properties in the rest of your application's code. Add these -methods manually or with your own IDE. +Doctrine now knows how to persist a ``Product`` object to the database. But the class +itself isn't useful yet. All of the properties are ``private``, so there's no way +to set data on them! -.. _doctrine-creating-the-database-tables-schema: +For that reason, you should create public getters and setters for all the fields +you need to modify from outside of the class. If you use an IDE like PhpStorm, it +can generate these for you. In PhpStorm, put your cursor anywhere in the class, +then go to the Code -> Generate menu and select "Getters and Setters":: -Creating the Database Tables/Schema ------------------------------------ - -You now have a usable ``Product`` class with mapping information so that -Doctrine knows exactly how to persist it. Of course, you don't yet have the -corresponding ``product`` table in your database. Fortunately, Doctrine can -automatically create all the database tables needed for every known entity -in your application. To do this, run: + // src/Entity/Product + // ... -.. code-block:: terminal + class Product + { + // all of your properties - $ php bin/console doctrine:schema:update --force + public function getId() + { + return $this->id; + } -.. tip:: + public function getName() + { + return $this->name; + } - Actually, this command is incredibly powerful. It compares what - your database *should* look like (based on the mapping information of - your entities) with how it *actually* looks, and executes the SQL statements - needed to *update* the database schema to where it should be. In other - words, if you add a new property with mapping metadata to ``Product`` - and run this command, it will execute the "ALTER TABLE" statement needed - to add that new column to the existing ``product`` table. + public function setName($name) + { + $this->name = $name; + } - An even better way to take advantage of this functionality is via - `migrations`_, which allow you to generate these SQL statements and store - them in migration classes that can be run systematically on your production - server in order to update and track changes to your database schema safely - and reliably. + // ... getters & setters for price & description + } - Whether or not you take advantage of migrations, the ``doctrine:schema:update`` - command should only be used during development. It should not be used in - a production environment. +.. tip:: -Your database now has a fully-functional ``product`` table with columns that -match the metadata you've specified. + Typically you won't need a ``setId()`` method: Doctrine will set this for you + automatically. Persisting Objects to the Database ---------------------------------- -Now that you have mapped the ``Product`` entity to its corresponding ``product`` -table, you're ready to persist ``Product`` objects to the database. From inside -a controller, this is pretty easy. Add the following method to the -``DefaultController`` of the bundle:: +It's time to save a ``Product`` object to the database! Let's create a new controller +to experiment: + +.. code-block:: terminal + + $ php bin/console make:controller ProductController + +Inside the controller, you can create a new ``Product`` object, set data on it, +and save it! +.. code-block:: php - // src/Controller/DefaultController.php + // src/Controller/ProductController.php + + namespace App\Controller; // ... use App\Entity\Product; - use Symfony\Component\HttpFoundation\Response; - use Doctrine\ORM\EntityManagerInterface; - public function createAction() + class ProductController extends Controller { - // you can fetch the EntityManager via $this->getDoctrine() - // or you can add an argument to your action: createAction(EntityManagerInterface $em) - $em = $this->getDoctrine()->getManager(); + /** + * @Route("/product", name="product") + */ + public function index() + { + // you can fetch the EntityManager via $this->getDoctrine() + // or you can add an argument to your action: index(EntityManagerInterface $em) + $em = $this->getDoctrine()->getManager(); - $product = new Product(); - $product->setName('Keyboard'); - $product->setPrice(19.99); - $product->setDescription('Ergonomic and stylish!'); + $product = new Product(); + $product->setName('Keyboard'); + $product->setPrice(19.99); + $product->setDescription('Ergonomic and stylish!'); - // tells Doctrine you want to (eventually) save the Product (no queries yet) - $em->persist($product); + // tell Doctrine you want to (eventually) save the Product (no queries yet) + $em->persist($product); - // actually executes the queries (i.e. the INSERT query) - $em->flush(); + // actually executes the queries (i.e. the INSERT query) + $em->flush(); - return new Response('Saved new product with id '.$product->getId()); + return new Response('Saved new product with id '.$product->getId()); + } } - // if you have multiple entity managers, use the registry to fetch them - public function editAction() - { - $doctrine = $this->getDoctrine(); - $em = $doctrine->getManager(); - $em2 = $doctrine->getManager('other_connection'); - } +Try it out! -.. note:: + http://localhost:8000/product + +Congratulations! You just created your first row the ``product`` table. To prove it, +you can query the database directly: + +.. code-block:: terminal - If you're following along with this example, you'll need to create a - route that points to this action to see it work. + $ php bin/console doctrine:query:sql 'SELECT * FROM product' Take a look at the previous example in more detail: .. _doctrine-entity-manager: -* **line 12** The ``$this->getDoctrine()->getManager()`` method gets Doctrine's +* **line 17** The ``$this->getDoctrine()->getManager()`` method gets Doctrine's *entity manager* object, which is the most important object in Doctrine. It's responsible for saving objects to, and fetching objects from, the database. -* **lines 14-17** In this section, you instantiate and work with the ``$product`` +* **lines 19-22** In this section, you instantiate and work with the ``$product`` object like any other normal PHP object. -* **line 20** The ``persist($product)`` call tells Doctrine to "manage" the +* **line 25** The ``persist($product)`` call tells Doctrine to "manage" the ``$product`` object. This does **not** cause a query to be made to the database. -* **line 23** When the ``flush()`` method is called, Doctrine looks through +* **line 28** When the ``flush()`` method is called, Doctrine looks through all of the objects that it's managing to see if they need to be persisted to the database. In this example, the ``$product`` object's data doesn't exist in the database, so the entity manager executes an ``INSERT`` query, creating a new row in the ``product`` table. -.. note:: - - In fact, since Doctrine is aware of all your managed entities, when you call - the ``flush()`` method, it calculates an overall changeset and executes - the queries in the correct order. It utilizes cached prepared statement to - slightly improve the performance. For example, if you persist a total of 100 - ``Product`` objects and then subsequently call ``flush()``, Doctrine will - execute 100 ``INSERT`` queries using a single prepared statement object. - .. note:: If the ``flush()`` call fails, a ``Doctrine\ORM\ORMException`` exception is thrown. See `Transactions and Concurrency`_. -Whether creating or updating objects, the workflow is always the same. In -the next section, you'll see how Doctrine is smart enough to automatically -issue an ``UPDATE`` query if the entity already exists in the database. +Whether you're creating or updating objects, the workflow is always the same: Doctrine +is smart enough to know if it should INSERT of UPDATE your entity. .. tip:: @@ -511,89 +404,73 @@ issue an ``UPDATE`` query if the entity already exists in the database. Fetching Objects from the Database ---------------------------------- -Fetching an object back out of the database is even easier. For example, -suppose you've configured a route to display a specific ``Product`` based -on its ``id`` value:: +Fetching an object back out of the database is even easier. Suppose you want to +be able to go to ``/product/1`` to see your new product:: + + // src/Controller/ProductController.php + // ... - public function showAction($productId) + /** + * @Route("/product/{id}", name="product_show") + */ + public function showAction($id) { $product = $this->getDoctrine() ->getRepository(Product::class) - ->find($productId); + ->find($id); if (!$product) { throw $this->createNotFoundException( - 'No product found for id '.$productId + 'No product found for id '.$id ); } - // ... do something, like pass the $product object into a template + return new Response('Check out this great product: '.$product->getName()); + + // or render a template + // in the template, print things with {{ product.name }} + // $this->render('product/show.html.twig', ['product' => $product]); } -.. tip:: +Try it out! - You can achieve the equivalent of this without writing any code by using - the ``@ParamConverter`` shortcut. See the `FrameworkExtraBundle documentation`_ - for more details. + http://localhost:8000/product/1 When you query for a particular type of object, you always use what's known as its "repository". You can think of a repository as a PHP class whose only -job is to help you fetch entities of a certain class. You can access the -repository object for an entity class via:: - - $repository = $this->getDoctrine() - ->getRepository(Product::class); - -.. note:: - - You can also use ``App:Product`` syntax. This string is a shortcut you can use anywhere - in Doctrine instead of the full class name of the entity (i.e. ``App\Entity\Product``). - As long as your entity lives under the ``Entity`` namespace of your bundle, - this will work. +job is to help you fetch entities of a certain class. -Once you have a repository object, you can access all sorts of helpful methods:: +Once you have a repository object, you have many helper methods:: $repository = $this->getDoctrine()->getRepository(Product::class); - // query for a single product by its primary key (usually "id") - $product = $repository->find($productId); - - // dynamic method names to find a single product based on a column value - $product = $repository->findOneById($productId); - $product = $repository->findOneByName('Keyboard'); - - // dynamic method names to find a group of products based on a column value - $products = $repository->findByPrice(19.99); - - // find *all* products - $products = $repository->findAll(); - -.. note:: - - Of course, you can also issue complex queries, which you'll learn more - about in the :ref:`doctrine-queries` section. + // query for a single Product by its primary key (usually "id") + $product = $repository->find($id); -You can also take advantage of the useful ``findBy()`` and ``findOneBy()`` methods -to easily fetch objects based on multiple conditions:: + // query for a single Product by name + $product = $repository->findOneBy(['name' => 'Keyboard']); + // or find by name and price + $product = $repository->findOneBy([ + 'name' => 'Keyboard', + 'price' => 19.99, + ]); - $repository = $this->getDoctrine()->getRepository(Product::class); - - // query for a single product matching the given name and price - $product = $repository->findOneBy( - array('name' => 'Keyboard', 'price' => 19.99) - ); - - // query for multiple products matching the given name, ordered by price + // query for multiple Product objects matching the name, ordered by price $products = $repository->findBy( array('name' => 'Keyboard'), array('price' => 'ASC') ); + // find *all* Product objects + $products = $repository->findAll(); + +You can also add *custom* methods for more complex queries! More on that later in +the :ref:`doctrine-queries` section. + .. tip:: - When rendering a page requires to make some database calls, the web debug - toolbar at the bottom of the page displays the number of queries and the - time it took to execute them: + When rendering an HTML page, the web debug toolbar at the bottom of the page + will display the number of queries and the time it took to execute them: .. image:: /_images/doctrine/doctrine_web_debug_toolbar.png :align: center @@ -606,27 +483,28 @@ to easily fetch objects based on multiple conditions:: Updating an Object ------------------ -Once you've fetched an object from Doctrine, updating it is easy. Suppose -you have a route that maps a product id to an update action in a controller:: - - use App\Entity\Product; - // ... +Once you've fetched an object from Doctrine, updating it is easy:: - public function updateAction($productId) + /** + * @Route("/product/edit/{id}") + */ + public function updateAction($id) { $em = $this->getDoctrine()->getManager(); - $product = $em->getRepository(Product::class)->find($productId); + $product = $em->getRepository(Product::class)->find($id); if (!$product) { throw $this->createNotFoundException( - 'No product found for id '.$productId + 'No product found for id '.$id ); } $product->setName('New product name!'); $em->flush(); - return $this->redirectToRoute('homepage'); + return $this->redirectToRoute('product_show', [ + 'id' => $product->getId() + ]); } Updating an object involves just three steps: @@ -635,10 +513,8 @@ Updating an object involves just three steps: #. modifying the object; #. calling ``flush()`` on the entity manager. -Notice that calling ``$em->persist($product)`` isn't necessary. Recall that -this method simply tells Doctrine to manage or "watch" the ``$product`` object. -In this case, since you fetched the ``$product`` object from Doctrine, it's -already managed. +You *can* call ``$em->persist($product)``, but it isn't necessary: Doctrine is already +"watching" your object for changes. Deleting an Object ------------------ @@ -650,155 +526,164 @@ method of the entity manager:: $em->flush(); As you might expect, the ``remove()`` method notifies Doctrine that you'd -like to remove the given object from the database. The actual ``DELETE`` query, -however, isn't actually executed until the ``flush()`` method is called. +like to remove the given object from the database. The ``DELETE`` query isn't +actually executed until the ``flush()`` method is called. .. _doctrine-queries: -Querying for Objects --------------------- +Querying for Objects: The Repository +------------------------------------ You've already seen how the repository object allows you to run basic queries without any work:: + // from inside a controller $repository = $this->getDoctrine()->getRepository(Product::class); - $product = $repository->find($productId); - $product = $repository->findOneByName('Keyboard'); + $product = $repository->find($id); -Of course, Doctrine also allows you to write more complex queries using the -Doctrine Query Language (DQL). DQL is similar to SQL except that you should -imagine that you're querying for one or more objects of an entity class (e.g. ``Product``) -instead of querying for rows on a table (e.g. ``product``). +But what if you need a more complex query? When you generated your entity with +``make:entity``, the command *also* generated a ``ProductRepository`` class:: -When querying in Doctrine, you have two main options: writing pure DQL queries -or using Doctrine's Query Builder. + // src/Repository/ProductRepository.php + namespace App\Repository; -Querying for Objects with DQL -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + use App\Entity\Product; + use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; -Imagine that you want to query for products that cost more than ``19.99``, -ordered from least to most expensive. You can use DQL, Doctrine's native -SQL-like language, to construct a query for this scenario:: + class ProductRepository extends ServiceEntityRepository + { + } - $query = $em->createQuery( - 'SELECT p - FROM App:Product p - WHERE p.price > :price - ORDER BY p.price ASC' - )->setParameter('price', 19.99); +When you fetch your repository (i.e. ``->getRepository(Product::class)``, it is +*actually* an instance of *this* object! This is because of the ``repositoryClass`` +config that was generated at the top of your ``Product`` entity class. - $products = $query->getResult(); +Suppose you want to query for all Product objects greater than a certain price. Add +a new method for this to your repository:: -If you're comfortable with SQL, then DQL should feel very natural. The biggest -difference is that you need to think in terms of selecting PHP objects, -instead of rows in a database. For this reason, you select *from* the -``App:Product`` *entity* (an optional shortcut for the -``App\Entity\Product`` class) and then alias it as ``p``. + // src/Repository/ProductRepository.php -.. tip:: + // ... + class ProductRepository extends ServiceEntityRepository + { + /** + * @param $price + * @return Product[] + */ + public function findAllGreaterThanPrice($price): array + { + // automatically knows to selects Products + // the "p" is an alias you'll use in the rest of the query + $qb = $this->createQueryBuilder('p') + ->andWhere('p.price > :price') + ->setParameter('price', $price) + ->orderBy('p.price', 'ASC') + ->getQuery(); + + return $qb->execute(); + + // to get just one result: + // $product = $query->setMaxResults(1)->getOneOrNullResult(); + } + } - Take note of the ``setParameter()`` method. When working with Doctrine, - it's always a good idea to set any external values as "placeholders" - (``:price`` in the example above) as it prevents SQL injection attacks. +This uses Doctrine's `Query Builder`_: a very powerful and user-friendly way to +write custom queries. Now, you can call this method on the repository:: -The ``getResult()`` method returns an array of results. To get only one -result, you can use ``getOneOrNullResult()``:: + // from inside a controller + $minPrice = 10; - $product = $query->setMaxResults(1)->getOneOrNullResult(); + $products = $this->getDoctrine() + ->getRepository(Product::class) + ->findAllGreaterThanPrice($minPrice); -The DQL syntax is incredibly powerful, allowing you to easily join between -entities (the topic of :doc:`relations ` will be -covered later), group, etc. For more information, see the official -`Doctrine Query Language`_ documentation. + // ... -Querying for Objects Using Doctrine's Query Builder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If you're in a :ref:`services-constructor-injection`_, you can type-hint the +``ProductRepository`` class and inject it like normal. -Instead of writing a DQL string, you can use a helpful object called the -``QueryBuilder`` to build that string for you. This is useful when the actual query -depends on dynamic conditions, as your code soon becomes hard to read with -DQL as you start to concatenate strings:: +For more details, see the `Query Builder`_ Documentation from Doctrine. - $repository = $this->getDoctrine() - ->getRepository(Product::class); +Querying with DQL or SQL +------------------------ - // createQueryBuilder() automatically selects FROM App:Product - // and aliases it to "p" - $query = $repository->createQueryBuilder('p') - ->where('p.price > :price') - ->setParameter('price', '19.99') - ->orderBy('p.price', 'ASC') - ->getQuery(); +In addition to the query builder, you can also query with `Doctrine Query Language`_:: - $products = $query->getResult(); - // to get just one result: - // $product = $query->setMaxResults(1)->getOneOrNullResult(); + // src/Repository/ProductRepository.php + // ... -The ``QueryBuilder`` object contains every method necessary to build your -query. By calling the ``getQuery()`` method, the query builder returns a -normal ``Query`` object, which can be used to get the result of the query. + public function findAllGreaterThanPrice($price): array + { + $query = $em->createQuery( + 'SELECT p + FROM App\Entity\Product p + WHERE p.price > :price + ORDER BY p.price ASC' + )->setParameter('price', 10); + + // returns an array of Product objects + return $query->execute(); + } -For more information on Doctrine's Query Builder, consult Doctrine's -`Query Builder`_ documentation. +Or directly with SQL if you need to:: -Organizing Custom Queries into Repository Classes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // src/Repository/ProductRepository.php + // ... -All the queries in the previous sections were written directly in your controller. -But for organization, Doctrine provides special repository classes that allow you -to keep all your query logic in one, central place. + public function findAllGreaterThanPrice($price): array + { + $conn = $this->getEntityManager()->getConnection(); + + $sql = ' + SELECT * FROM product p + WHERE p.price > :price + ORDER BY p.price ASC + '; + $stmt = $conn->prepare($sql); + $stmt->execute(array('price' => 10)); + + // returns an array of arrays (i.e. a raw data set) + return $stmt->fetchAll(); + } -see :doc:`/doctrine/repository` for info. +With SQL, you will get back raw data, not objects (unless you use the `NativeQuery`_ +functionality). Configuration ------------- -Doctrine is highly configurable, though you probably won't ever need to worry -about most of its options. To find out more about configuring Doctrine, see -the Doctrine section of the :doc:`config reference `. - -.. _doctrine-field-types: - -Doctrine Field Types Reference ------------------------------- - -Doctrine comes with numerous field types available. Each of these -maps a PHP data type to a specific column type in whatever database you're -using. For each field type, the ``Column`` can be configured further, setting -the ``length``, ``nullable`` behavior, ``name`` and other options. To see a -list of all available types and more information, see Doctrine's -`Mapping Types documentation`_. +See the :doc:`Doctrine config reference `. Relationships and Associations ------------------------------ Doctrine provides all the functionality you need to manage database relationships -(also known as associations). For info, see :doc:`/doctrine/associations`. - -Final Thoughts --------------- - -With Doctrine, you can focus on your *objects* and how they're used in your -application and worry about database persistence second. This is because -Doctrine allows you to use any PHP object to hold your data and relies on -mapping metadata information to map an object's data to a particular database -table. +(also known as associations), including ManyToOne, OneToMany, OneToOne and ManyToMany +relationships. -Doctrine has a lot more complex features to learn, like relationships, complex queries, -and event listeners. +For info, see :doc:`/doctrine/associations`. Learn more ---------- .. toctree:: :maxdepth: 1 - :glob: - doctrine/* + doctrine/associations + doctrine/common_extensions + doctrine/lifecycle_callbacks + doctrine/event_listeners_subscribers + doctrine/registration_form + doctrine/custom_dql_functions + doctrine/dbal + doctrine/multiple_entity_managers + doctrine/pdo_session_storage + doctrine/mongodb_session_storage + doctrine/resolve_target_entity + doctrine/reverse_engineering * `DoctrineFixturesBundle`_ -* `DoctrineMongoDBBundle`_ .. _`Doctrine`: http://www.doctrine-project.org/ .. _`MongoDB`: https://www.mongodb.org/ @@ -815,3 +700,5 @@ Learn more .. _`FrameworkExtraBundle documentation`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html .. _`newer utf8mb4 character set`: https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html .. _`Transactions and Concurrency`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html +.. _`DoctrineMigrationsBundle`: https://github.com/doctrine/DoctrineMigrationsBundle +.. _`NativeQuery`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html diff --git a/doctrine/console.rst b/doctrine/console.rst deleted file mode 100644 index 5735e9ac09e..00000000000 --- a/doctrine/console.rst +++ /dev/null @@ -1,43 +0,0 @@ -.. index:: - single: Doctrine; ORM console commands - single: CLI; Doctrine ORM - -Console Commands ----------------- - -The Doctrine2 ORM integration offers several console commands under the -``doctrine`` namespace. To view the command list you can use the ``list`` -command: - -.. code-block:: terminal - - $ php bin/console list doctrine - -A list of available commands will print out. You can find out more information -about any of these commands (or any Symfony command) by running the ``help`` -command. For example, to get details about the ``doctrine:database:create`` -command, run: - -.. code-block:: terminal - - $ php bin/console help doctrine:database:create - -Some notable or interesting commands include: - -* ``doctrine:ensure-production-settings`` - checks to see if the current - environment is configured efficiently for production. This should always - be run in the ``prod`` environment: - - .. code-block:: terminal - - $ php bin/console doctrine:ensure-production-settings --env=prod - -* ``doctrine:mapping:import`` - allows Doctrine to introspect an existing - database and create mapping information. For more information, see - :doc:`/doctrine/reverse_engineering`. - -* ``doctrine:mapping:info`` - tells you all of the entities that Doctrine - is aware of and whether or not there are any basic errors with the mapping. - -* ``doctrine:query:dql`` and ``doctrine:query:sql`` - allow you to execute - DQL or SQL queries directly from the command line. diff --git a/doctrine/mapping_model_classes.rst b/doctrine/mapping_model_classes.rst deleted file mode 100644 index 134912d2dea..00000000000 --- a/doctrine/mapping_model_classes.rst +++ /dev/null @@ -1,149 +0,0 @@ -.. index:: - single: Doctrine; Mapping Model classes - -How to Provide Model Classes for several Doctrine Implementations -================================================================= - -When building a bundle that could be used not only with Doctrine ORM but -also the CouchDB ODM, MongoDB ODM or PHPCR ODM, you should still only -write one model class. The Doctrine bundles provide a compiler pass to -register the mappings for your model classes. - -.. note:: - - For non-reusable bundles, the easiest option is to put your model classes - in the default locations: ``Entity`` for the Doctrine ORM or ``Document`` - for one of the ODMs. For reusable bundles, rather than duplicate model classes - just to get the auto-mapping, use the compiler pass. - -In your bundle class, write the following code to register the compiler pass. -This one is written for the CmfRoutingBundle, so parts of it will need to -be adapted for your case:: - - use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass; - use Doctrine\Bundle\MongoDBBundle\DependencyInjection\Compiler\DoctrineMongoDBMappingsPass; - use Doctrine\Bundle\CouchDBBundle\DependencyInjection\Compiler\DoctrineCouchDBMappingsPass; - use Doctrine\Bundle\PHPCRBundle\DependencyInjection\Compiler\DoctrinePhpcrMappingsPass; - use Symfony\Cmf\RoutingBundle\Model; - - class CmfRoutingBundle extends Bundle - { - public function build(ContainerBuilder $container) - { - parent::build($container); - // ... - - $modelDir = realpath(__DIR__.'/Resources/config/doctrine/model'); - $mappings = array( - $modelDir => Model::class, - ); - - if (class_exists(DoctrineOrmMappingsPass::class)) { - $container->addCompilerPass( - DoctrineOrmMappingsPass::createXmlMappingDriver( - $mappings, - array('cmf_routing.model_manager_name'), - 'cmf_routing.backend_type_orm', - array('CmfRoutingBundle' => Model::class) - )); - } - - if (class_exists(DoctrineMongoDBMappingsPass::class)) { - $container->addCompilerPass( - DoctrineMongoDBMappingsPass::createXmlMappingDriver( - $mappings, - array('cmf_routing.model_manager_name'), - 'cmf_routing.backend_type_mongodb', - array('CmfRoutingBundle' => Model::class) - )); - } - - if (class_exists(DoctrineCouchDBMappingsPass::class)) { - $container->addCompilerPass( - DoctrineCouchDBMappingsPass::createXmlMappingDriver( - $mappings, - array('cmf_routing.model_manager_name'), - 'cmf_routing.backend_type_couchdb', - array('CmfRoutingBundle' => Model::class) - )); - } - - if (class_exists(DoctrinePhpcrMappingsPass::class)) { - $container->addCompilerPass( - DoctrinePhpcrMappingsPass::createXmlMappingDriver( - $mappings, - array('cmf_routing.model_manager_name'), - 'cmf_routing.backend_type_phpcr', - array('CmfRoutingBundle' => Model::class) - )); - } - } - } - -Note the :phpfunction:`class_exists()` check. This is crucial, as you do not want your -bundle to have a hard dependency on all Doctrine bundles but let the user -decide which to use. - -The compiler pass provides factory methods for all drivers provided by Doctrine: -Annotations, XML, Yaml, PHP and StaticPHP. The arguments are: - -* A map/hash of absolute directory path to namespace; -* An array of container parameters that your bundle uses to specify the name of - the Doctrine manager that it is using. In the example above, the CmfRoutingBundle - stores the manager name that's being used under the ``cmf_routing.model_manager_name`` - parameter. The compiler pass will append the parameter Doctrine is using - to specify the name of the default manager. The first parameter found is - used and the mappings are registered with that manager; -* An optional container parameter name that will be used by the compiler - pass to determine if this Doctrine type is used at all. This is relevant if - your user has more than one type of Doctrine bundle installed, but your - bundle is only used with one type of Doctrine; -* A map/hash of aliases to namespace. This should be the same convention used - by Doctrine auto-mapping. In the example above, this allows the user to call - ``$om->getRepository('CmfRoutingBundle:Route')``. - -.. note:: - - The factory method is using the ``SymfonyFileLocator`` of Doctrine, meaning - it will only see XML and YML mapping files if they do not contain the - full namespace as the filename. This is by design: the ``SymfonyFileLocator`` - simplifies things by assuming the files are just the "short" version - of the class as their filename (e.g. ``BlogPost.orm.xml``) - - If you also need to map a base class, you can register a compiler pass - with the ``DefaultFileLocator`` like this. This code is taken from the - ``DoctrineOrmMappingsPass`` and adapted to use the ``DefaultFileLocator`` - instead of the ``SymfonyFileLocator``:: - - use Doctrine\Common\Persistence\Mapping\Driver\DefaultFileLocator; - use Doctrine\ORM\Mapping\Driver\XmlDriver; - use App\Model; - - // ... - private function buildMappingCompilerPass() - { - $locator = new Definition(DefaultFileLocator::class, array( - array(realpath(__DIR__ . '/Resources/config/doctrine-base')), - '.orm.xml' - )); - $driver = new Definition(XmlDriver::class, array($locator)); - - return new DoctrineOrmMappingsPass( - $driver, - array(Model::class), - array('your_bundle.manager_name'), - 'your_bundle.orm_enabled' - ); - } - - Note that you do not need to provide a namespace alias unless your users are - expected to ask Doctrine for the base classes. - - Now place your mapping file into ``/Resources/config/doctrine-base`` with the - fully qualified class name, separated by ``.`` instead of ``\``, for example - ``Other.Namespace.Model.Name.orm.xml``. You may not mix the two as otherwise - the ``SymfonyFileLocator`` will get confused. - - Adjust accordingly for the other Doctrine implementations. - -.. _`CouchDB Mapping Compiler Pass pull request`: https://github.com/doctrine/DoctrineCouchDBBundle/pull/27 diff --git a/doctrine/repository.rst b/doctrine/repository.rst deleted file mode 100644 index 49acae61c96..00000000000 --- a/doctrine/repository.rst +++ /dev/null @@ -1,102 +0,0 @@ -.. index:: - single: Doctrine; Custom Repository Class - -How to Create custom Repository Classes -======================================= - -In the previous sections, you began constructing and using more complex queries -from inside a controller. In order to isolate, reuse and test these queries, -it's a good practice to create a custom repository class for your entity. -Methods containing your query logic can then be stored in this class. - -To do this, add the repository class name to your entity's mapping definition: - -.. configuration-block:: - - .. code-block:: php-annotations - - // src/Entity/Product.php - namespace App\Entity; - - use Doctrine\ORM\Mapping as ORM; - - /** - * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") - */ - class Product - { - //... - } - - .. code-block:: yaml - - # src/Resources/config/doctrine/Product.orm.yml - App\Entity\Product: - type: entity - repositoryClass: App\Repository\ProductRepository - # ... - - .. code-block:: xml - - - - - - - - - - - -Then, create an empty ``App\Repository\ProductRepository`` class extending -from ``Doctrine\ORM\EntityRepository``. - -Next, add a new method - ``findAllOrderedByName()`` - to the newly-generated -``ProductRepository`` class. This method will query for all the ``Product`` -entities, ordered alphabetically by name. - -.. code-block:: php - - // src/Repository/ProductRepository.php - namespace App\Repository; - - use Doctrine\ORM\EntityRepository; - - class ProductRepository extends EntityRepository - { - public function findAllOrderedByName() - { - return $this->getEntityManager() - ->createQuery( - 'SELECT p FROM App:Product p ORDER BY p.name ASC' - ) - ->getResult(); - } - } - -.. tip:: - - The entity manager can be accessed via ``$this->getEntityManager()`` - from inside the repository. - -You can use this new method just like the default finder methods of the repository:: - - use App\Entity\Product; - // ... - - public function listAction() - { - $products = $this->getDoctrine() - ->getRepository(Product::class) - ->findAllOrderedByName(); - } - -.. note:: - - When using a custom repository class, you still have access to the default - finder methods such as ``find()`` and ``findAll()``. From 7e77d9cd92e9fffe7bd0650c52eaa8426acf0193 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 22 Nov 2017 14:25:04 -0500 Subject: [PATCH 0117/2437] moving section down --- doctrine.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index e318bfa899b..1386f336a50 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -395,12 +395,6 @@ Take a look at the previous example in more detail: Whether you're creating or updating objects, the workflow is always the same: Doctrine is smart enough to know if it should INSERT of UPDATE your entity. -.. tip:: - - Doctrine provides a library that allows you to programmatically load testing - data into your project (i.e. "fixture data"). For information, see - the "`DoctrineFixturesBundle`_" documentation. - Fetching Objects from the Database ---------------------------------- @@ -664,6 +658,13 @@ relationships. For info, see :doc:`/doctrine/associations`. +Dummy Data Fixtures +------------------- + +Doctrine provides a library that allows you to programmatically load testing +data into your project (i.e. "fixture data"). For information, see +the "`DoctrineFixturesBundle`_" documentation. + Learn more ---------- From 68ac45468ac2cc8aab7cfa8e2a1ba8acf685fb4b Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 22 Nov 2017 15:17:00 -0500 Subject: [PATCH 0118/2437] WIP - updating associations article --- doctrine/associations.rst | 228 +++++++++++++++++++++----------------- 1 file changed, 128 insertions(+), 100 deletions(-) diff --git a/doctrine/associations.rst b/doctrine/associations.rst index 80f305fffff..b9a0fd45569 100644 --- a/doctrine/associations.rst +++ b/doctrine/associations.rst @@ -4,39 +4,76 @@ How to Work with Doctrine Associations / Relations ================================================== +There are **two** main relationship/association types: + +``ManyToOne`` / ``OneToMany`` + The most common relationship, mapped in the database with a simple foreign + key column (e.g. a ``category_id`` column on the ``product`` table). This is + actually just *one* association type, but seen from the two different *sides* + of the relation. + +``ManyToMany`` + Uses a join table and is needed when both sides of the relationship can have + many of the other side (e.g. "students" and "classes": each student is in many + classes, and each class has many students). + +First, you need to determine which relationship to use. If both sides of the relation +will contain many of the oter side (e.g. "students" and "classes"), you need a +``ManyToMany`` relation. Otherwise, you likely need a ``ManyToOne``. + +.. tip:: + + There is also a OneToOne relationship (e.g. one User has one Profile and vice + versa). In practice, using this is similar to ``ManyToOne``. + +The ManyToOne / OneToMany Association +------------------------------------- + Suppose that each product in your application belongs to exactly one category. In this case, you'll need a ``Category`` class, and a way to relate a ``Product`` object to a ``Category`` object. -Start by creating the ``Category`` entity. Since you know that you'll eventually -need to persist category objects through Doctrine, you can let Doctrine create -the class for you. +Start by creating a ``Category`` entity: .. code-block:: terminal - $ php bin/console doctrine:generate:entity --no-interaction \ - --entity="App:Category" \ - --fields="name:string(255)" + $ php bin/console make:entity Category + +Then, add a ``name`` field to that new ``Category`` class:: + + // src/Entity/Category + // ... -This command generates the ``Category`` entity for you, with an ``id`` field, -a ``name`` field and the associated getter and setter functions. + class Category + { + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + private $id; + + /** + * @ORM\Column(type="string") + */ + private $name; + + // ... getters and setters + } -Relationship Mapping Metadata ------------------------------ +Mapping the ManyToOne Relationship +---------------------------------- -In this example, each category can be associated with *many* products, while +In this example, each category can be associated with *many* products. But, each product can be associated with only *one* category. This relationship can be summarized as: *many* products to *one* category (or equivalently, *one* category to *many* products). From the perspective of the ``Product`` entity, this is a many-to-one relationship. From the perspective of the ``Category`` entity, this is a one-to-many relationship. -This is important, because the relative nature of the relationship determines -which mapping metadata to use. It also determines which class *must* hold -a reference to the other class. -To relate the ``Product`` and ``Category`` entities, simply create a ``category`` -property on the ``Product`` class, annotated as follows: +To map this, first create a ``category`` property on the ``Product`` class with +the ``ManyToOne`` annotation: .. configuration-block:: @@ -50,10 +87,20 @@ property on the ``Product`` class, annotated as follows: // ... /** - * @ORM\ManyToOne(targetEntity="Category", inversedBy="products") - * @ORM\JoinColumn(name="category_id", referencedColumnName="id") + * @ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="products") + * @ORM\JoinColumn(nullable=true) */ private $category; + + public function getCategory(): Category + { + return $this->category; + } + + public function setCategory(Category $category) + { + $this->category = $category; + } } .. code-block:: yaml @@ -64,11 +111,10 @@ property on the ``Product`` class, annotated as follows: # ... manyToOne: category: - targetEntity: Category + targetEntity: App\Entity\Category inversedBy: products joinColumn: - name: category_id - referencedColumnName: id + nullable: true .. code-block:: xml @@ -83,22 +129,19 @@ property on the ``Product`` class, annotated as follows: - - + target-entity="App\Entity\Category" + inversed-by="products"> + -This many-to-one mapping is critical. It tells Doctrine to use the ``category_id`` +This many-to-one mapping is required. It tells Doctrine to use the ``category_id`` column on the ``product`` table to relate each record in that table with a record in the ``category`` table. -Next, since a single ``Category`` object will relate to many ``Product`` -objects, a ``products`` property can be added to the ``Category`` class -to hold those associated objects. +Next, since a *one* ``Category`` object will relate to *many* ``Product`` +objects, add a ``products`` property to ``Category`` that will hold those objects: .. configuration-block:: @@ -108,13 +151,14 @@ to hold those associated objects. // ... use Doctrine\Common\Collections\ArrayCollection; + use Doctrine\Common\Collections\Collection; class Category { // ... /** - * @ORM\OneToMany(targetEntity="Product", mappedBy="category") + * @ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="category") */ private $products; @@ -122,6 +166,14 @@ to hold those associated objects. { $this->products = new ArrayCollection(); } + + /** + * @return Collection|Product[] + */ + public function getProducts() + { + return $this->products; + } } .. code-block:: yaml @@ -132,7 +184,7 @@ to hold those associated objects. # ... oneToMany: products: - targetEntity: Product + targetEntity: App\Entity\Product mappedBy: category # Don't forget to initialize the collection in # the __construct() method of the entity @@ -150,7 +202,7 @@ to hold those associated objects. + extend('layout.html.php') ?> Hello ! @@ -127,7 +128,7 @@ Now, have a look at the ``layout.html.php`` file: .. code-block:: html+php - + extend('base.html.php') ?>

    Hello Application

    @@ -140,7 +141,7 @@ another one: .. code-block:: html+php - + @@ -173,7 +174,7 @@ decorating the template. In the ``index.html.php`` template, define a .. code-block:: html+php - + extend('layout.html.php') ?> set('title', 'Hello World Application') ?> @@ -184,7 +185,7 @@ The base layout already has the code to output the title in the header: .. code-block:: html+php - + <?php $view['slots']->output('title', 'Hello Application') ?> @@ -215,14 +216,14 @@ Create a ``hello.html.php`` template: .. code-block:: html+php - + Hello ! And change the ``index.html.php`` template to include it: .. code-block:: html+php - + extend('layout.html.php') ?> render('hello/hello.html.php', array('name' => $name)) ?> @@ -245,7 +246,7 @@ If you create a ``fancy`` action, and want to include it into the .. code-block:: html+php - + render( new \Symfony\Component\HttpKernel\Controller\ControllerReference( 'App\Controller\HelloController::fancy', From 94fd2e920f6ac840279acd69ad98fe4c2f64bc09 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 23 Nov 2017 17:17:09 +0100 Subject: [PATCH 0121/2437] Add instructions to install dependencies before using them --- email.rst | 4 ++-- forms.rst | 10 ++++++++++ logging.rst | 16 +++++++++++++--- profiler.rst | 13 +++++++++++++ security.rst | 12 ++++++++++++ serializer.rst | 7 ++++--- validation.rst | 15 ++++++++++++--- workflow/usage.rst | 19 ++++++++++++++----- 8 files changed, 80 insertions(+), 16 deletions(-) diff --git a/email.rst b/email.rst index 29e91fa7dac..501173490ad 100644 --- a/email.rst +++ b/email.rst @@ -12,8 +12,8 @@ own mail servers as well as using popular email providers like `Mandrill`_, Installation ------------ -In applications using :doc:`Symfony Flex `, execute this command to -install and enable the mailer: +In applications using :doc:`Symfony Flex `, run this command to +install the Swift Mailer based mailer before using it: .. code-block:: terminal diff --git a/forms.rst b/forms.rst index 6390e53896e..7a7f55b475d 100644 --- a/forms.rst +++ b/forms.rst @@ -9,6 +9,16 @@ a web developer. Symfony integrates a Form component that makes dealing with forms easy. In this article, you'll build a complex form from the ground up, learning the most important features of the form library along the way. +Installation +------------ + +In applications using :doc:`Symfony Flex `, run this command to +install the form feature before using it: + +.. code-block:: terminal + + $ composer require form + .. note:: The Symfony Form component is a standalone library that can be used outside diff --git a/logging.rst b/logging.rst index 8b1e2b6b111..5d4f3bfd6c5 100644 --- a/logging.rst +++ b/logging.rst @@ -1,8 +1,18 @@ Logging with Monolog ==================== -Symfony comes with an outside library - called Monolog_ - that allows you to create -logs that can be stored in a variety of different places. +Symfony integrates seamlessly with `Monolog`_, the most popular PHP logging +library, to create and store log messages in a variety of different places. + +Installation +------------ + +In applications using :doc:`Symfony Flex `, run this command to +install the Monolog based logger before using it: + +.. code-block:: terminal + + $ composer require logger Logging a Message ----------------- @@ -19,7 +29,7 @@ your controller:: $logger->info('I just got the logger'); $logger->error('An error occurred'); - + $logger->critical('I left the oven on!', array( // include extra "context" info in your logs 'cause' => 'in_hurry', diff --git a/profiler.rst b/profiler.rst index 0f20ead43b8..ecfa48421ee 100644 --- a/profiler.rst +++ b/profiler.rst @@ -1,6 +1,19 @@ Profiler ======== +Symfony provides a powerful profiler to get detailed information about the +execution of any request. + +Installation +------------ + +In applications using :doc:`Symfony Flex `, run this command to +install the profiler before using it: + +.. code-block:: terminal + + $ composer require profiler + .. toctree:: :maxdepth: 1 diff --git a/security.rst b/security.rst index 9a2b607f63e..e3db5a33535 100644 --- a/security.rst +++ b/security.rst @@ -14,6 +14,8 @@ is both flexible and (hopefully) fun to work with. Since there's a lot to talk about, this article is organized into a few big sections: +#. Installing security support; + #. Initial ``security.yml`` setup (*authentication*); #. Denying access to your app (*authorization*); @@ -24,6 +26,16 @@ These are followed by a number of small (but still captivating) sections, like :ref:`logging out ` and :doc:`encoding user passwords `. +Installation +------------ + +In applications using :doc:`Symfony Flex `, run this command to +install the security feature before using it: + +.. code-block:: terminal + + $ composer require security + .. _security-firewalls: .. _firewalls-authentication: diff --git a/serializer.rst b/serializer.rst index 75b38c49d33..be5d6771600 100644 --- a/serializer.rst +++ b/serializer.rst @@ -11,10 +11,11 @@ its philosophy and the normalizers and encoders terminology. .. _activating_the_serializer: -Installing the Serializer -------------------------- +Installation +------------ -Before using the serializer, run this command to install it in your application: +In applications using :doc:`Symfony Flex `, run this command to +install the serializer before using it: .. code-block:: terminal diff --git a/validation.rst b/validation.rst index ebb13a90868..847a73ddc63 100644 --- a/validation.rst +++ b/validation.rst @@ -8,9 +8,18 @@ Validation is a very common task in web applications. Data entered in forms needs to be validated. Data also needs to be validated before it is written into a database or passed to a web service. -Symfony ships with a `Validator`_ component that makes this task easy and -transparent. This component is based on the -`JSR303 Bean Validation specification`_. +Symfony provides a `Validator`_ component that makes this task easy and +transparent. This component is based on the `JSR303 Bean Validation specification`_. + +Installation +------------ + +In applications using :doc:`Symfony Flex `, run this command to +install the validator before using it: + +.. code-block:: terminal + + $ composer require validator .. index:: single: Validation; The basics diff --git a/workflow/usage.rst b/workflow/usage.rst index 283b13df434..88a33c0632c 100644 --- a/workflow/usage.rst +++ b/workflow/usage.rst @@ -4,13 +4,19 @@ How to Create and Use Workflows =============================== -Before creating your first workflow, execute this command to install the -:doc:`Workflow component ` in your application: +Installation +------------ + +In applications using :doc:`Symfony Flex `, run this command to +install the workflow feature before using it: .. code-block:: terminal $ composer require workflow +Creating a Workflow +------------------- + A workflow is a process or a lifecycle that your objects go through. Each step or stage in the process is called a *place*. You do also define *transitions* to that describes the action to get from one place to another. @@ -163,9 +169,12 @@ like this: value ``marking``) attributes of the ``marking_store`` option are optional. If omitted, their default values will be used. -With this workflow named ``blog_publishing``, you can now decide what actions -are allowed on a blog post. For example, inside a controller of an application -using the :ref:`default services.yaml configuration `, +Using a Workflow +---------------- + +Once the ``blog_publishing`` workflow has been created, you can now use it to +decide what actions are allowed on a blog post. For example, inside a controller +of an application using the :ref:`default services.yaml configuration `, you can get the workflow by injecting the Workflow registry service:: // ... From e84c0e02273300140b4795b5084b7acb59b9e2cc Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 21 Nov 2017 09:48:12 -0500 Subject: [PATCH 0122/2437] Remove svn & changelog articles --- _build/redirection_map | 3 +- changelog.rst | 2731 ------------------------------------- index.rst | 5 - setup/new_project_svn.rst | 138 -- 4 files changed, 2 insertions(+), 2875 deletions(-) delete mode 100644 changelog.rst delete mode 100644 setup/new_project_svn.rst diff --git a/_build/redirection_map b/_build/redirection_map index 89d6cfaa510..146e731e460 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -283,7 +283,8 @@ /cookbook/workflow/homestead /setup/homestead /cookbook/workflow/index /setup /cookbook/workflow/new_project_git /setup/new_project_git -/cookbook/workflow/new_project_svn /setup/new_project_svn +/cookbook/workflow/new_project_svn /setup/new_project_git +/setup/new_project_svn /setup/new_project_git /components/asset/index /components/asset /components/asset/introduction /components/asset /components/browser_kit/index /components/browser_kit diff --git a/changelog.rst b/changelog.rst deleted file mode 100644 index f91895f535c..00000000000 --- a/changelog.rst +++ /dev/null @@ -1,2731 +0,0 @@ -.. index:: - single: CHANGELOG - -.. !! CAUTION !! - This file is automatically generated. Do not add new changelog - items when preparing a pull request. - -The Documentation Changelog -=========================== - -This documentation is always changing: All new features need new documentation -and bugs/typos get fixed. This article holds all important changes of the -documentation. - -.. tip:: - - Do you also want to participate in the Symfony Documentation? Take a look - at the ":doc:`/contributing/documentation/overview`" article. - -October, 2016 -------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6958 `_ [FrameworkBundle] add support for prioritizing form type extension tags (dmaicher) -* `#7074 `_ [PhpUnitBridge] Doc for @expectedDeprecation & new configuration env vars (nicolas-grekas) -* `#6947 `_ [Cache] Add chapter about invalidation, tags, etc. (nicolas-grekas) -* `#7021 `_ [ServiceContainer] Remove implementation details of private services (lemoinem) -* `#7023 `_ Added useful debug commands in the debug documentation (hiddewie) -* `#6946 `_ [VarDumper] Adding semantics with metadata (nicolas-grekas) -* `#6949 `_ Update ProgressBar docs with regress information (jameshalsall) -* `#7019 `_ [Framework] Update link-to-source mapping definition (nicolas-grekas) -* `#6938 `_ Document new utf8 option of Routing component (mickaelandrieu) -* `#6932 `_ Explain the limitations of the custom messages in UniqueEntity (javiereguiluz) -* `#6876 `_ Updated single command How to (mickaelandrieu) -* `#6870 `_ [Debug] Added configuration reference for new debug options (lyrixx) -* `#6783 `_ Routing: add explanation for the "_fragment" parameter (alexislefebvre) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#7049 `_ Fix the platform.sh builds (wouterj) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#7090 `_ Remove suggestion to change the `.class` parameters (mpdude) -* `#7095 `_ Also mention "hasXXX" methods as validation targets (mpdude) -* `#7091 `_ A bracket was missed (hpatoio) -* `#7097 `_ link to specific HTTP Cache RFC (snoek09) -* `#7098 `_ Improved Redirecting paragraph of Testing page (ShinDarth) -* `#7100 `_ Update birthday.rst (angyvolin) -* `#7020 `_ Added jQuery symfony-collection plugin to Form collection docs (hiddewie) -* `#7086 `_ Update bug documentation input console /console/input.rst (Quiss) -* `#7085 `_ Update custom_authentication_provider.rst (BatsaxIV) -* `#7083 `_ update github example (hootlex) -* `#7082 `_ Update metadata.rst (fberthereau) -* `#7078 `_ Simple typo fix (Renrhaf) -* `#7077 `_ remove caution message (snoek09) -* `#7073 `_ Accept only array in TagAwareAdapter::invalidateTags() (Koc) -* `#7048 `_ [#6938] tweak the wording a bit (xabbuh) -* `#7061 `_ Change link to docs instead repo (mik-laj) -* `#7066 `_ Remove erroneous placeholder text (regularjack) -* `#7068 `_ Remove double spaces in some YAML configuration (michaelperrin) -* `#7069 `_ use FCQN to reference the form type in add() (xabbuh) -* `#6785 `_ Twig reference: Add links from routing functions to special routing parameters (alexislefebvre) -* `#7043 `_ [Serializer] Move the see also block in the Learn More section (dunglas) -* `#7035 `_ Redirect /form to /forms for consistency (wouterj) -* `#7054 `_ Fix IS_AUTHENTICATED_FULLY annotation (mschobner) -* `#7044 `_ Add Nginx configuration to environment variables (peterkokot) -* `#6928 `_ Update the Apache Router article to deprecate it entirely (javiereguiluz) -* `#7053 `_ Minor improvements for the contribution guide (javiereguiluz) -* `#7050 `_ use single quotes for YAML strings (snoek09) -* `#7047 `_ Fix typo in doctrine.rst (to manage) (lacyrhoades) -* `#7046 `_ Fix incorrect callback validation example (mvar) -* `#7034 `_ Changed RFC links from drafts to proposed standarts (a-ast) -* `#7038 `_ Remove a dead link to the old PR header (dunglas) -* `#7037 `_ Fix a typo in the serializer doc (dunglas) -* `#7036 `_ Fix 404 error link for American English Oxford Dictionary (peterkokot) -* `#6980 `_ Use strict comparison (greg0ire) -* `#7025 `_ Update buisness-logic (zairigimad) -* `#7027 `_ Remove dash prefix from route name (bocharsky-bw) -* `#7028 `_ A few minor tweaks (bocharsky-bw) -* `#7029 `_ refer to Symfony instead of Symfony2 (snoek09) -* `#7031 `_ Capitalize the time designator (simoheinonen) -* `#7018 `_ Reorder arguments: $request as the first argument (bocharsky-bw) -* `#7014 `_ Add a note about Filesystem:mkdir behavior (mickaelandrieu) -* `#6886 `_ Update controllers.rst (asandjivy) - - -September, 2016 ---------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6989 `_ Added paths options in Framework::translator configuration (mickaelandrieu) -* `#6926 `_ [Serializer] Add information about name converter parameter (michaelperrin) -* `#6891 `_ [VarDumper] Doc for the Data::seek() method (nicolas-grekas) -* `#6890 `_ [Routing] Add doc about unicode requirements (nicolas-grekas) -* `#6944 `_ Update doc about IDE file link format (nicolas-grekas) -* `#6968 `_ [Console] Add multiple options for the output example (SpacePossum) -* `#6956 `_ [Filesystem] Add documentation for the readlink method (tgalopin) -* `#6973 `_ Callback doesn't have to be static (patrick-mcdougle) -* `#6976 `_ [Finishing][Serializer] Document the encoders (Ener-Getick, weaverryan) -* `#6622 `_ Documentation for YAML flags added in 3.1 (dantleech) -* `#6962 `_ [Bridge/PhpUnit] doc bin/simple-phpunit (nicolas-grekas, weaverryan) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#7016 `_ Add empty parentheses to method names (bocharsky-bw) -* `#7015 `_ Replace title placeholder name with slug (bocharsky-bw) -* `#7009 `_ Update form_dependencies.rst: fix DI (ReDnAxE) -* `#7010 `_ Update service_decoration.rst (lamari) -* `#7008 `_ Missing semicolon (Saphyel) -* `#6979 `_ Add specific tip about the http-kernel component (greg0ire) -* `#6686 `_ Update installation.rst (mgkimsal) -* `#7007 `_ normalize versionadded wording (xabbuh) -* `#6990 `_ replace dirname() call with .. (xabbuh) -* `#6992 `_ [Serializer] versionadded directive for name_converter option (xabbuh) -* `#7005 `_ Use new array syntax and make a few minor tweaks (bocharsky-bw) -* `#7005 `_ Use new array syntax and make a few minor tweaks (bocharsky-bw) -* `#7004 `_ Tweak URL - CMF project moved to the other repo (bocharsky-bw) -* `#7001 `_ Several typo fixes (emirb) -* `#7000 `_ Several typo fixes (emirb) -* `#6999 `_ Several typo fixes (emirb) -* `#6997 `_ Update console.rst (adyassine) -* `#6917 `_ [Finder] document array use for locations (mickaelandrieu) -* `#6993 `_ Update create_custom_field_type.rst (yceruto) -* `#6993 `_ Update create_custom_field_type.rst (yceruto) -* `#6994 `_ [Reference] remove 2.8 versionadded directive (xabbuh) -* `#6984 `_ Update deployment.rst (adyassine) -* `#6995 `_ the least -> least (konrados) -* `#6996 `_ fix reference syntax (xabbuh) -* `#6991 `_ Update heroku.rst (adyassine) -* `#6934 `_ Update events.rst (asandjivy) -* `#6897 `_ Update voters.rst (asandjivy) -* `#6920 `_ [Config] Note about bundle priority for PrependExtensionInterface (wodor) -* `#6905 `_ Change example of ignoring dependencies for yaml (Integrity-178B) -* `#6885 `_ [FormComponent]Fix wrong mention in side note (rendler-denis) -* `#6911 `_ Article about logout. (BorodinDemid) -* `#6923 `_ Clarify by_reference use (jxmallett) -* `#6942 `_ Updated the "Build a Login Form" article (javiereguiluz) -* `#6931 `_ [Guard] Improve clarity using the configured provider (chalasr) -* `#6933 `_ Misplaced paragraph about placeholders in routing.rst (antoin-m) -* `#6930 `_ Use Terminal lexer for console examples (wouterj) -* `#6893 `_ Update entity_provider.rst (asandjivy) -* `#6895 `_ fixing $formatLevelMap array values (zrashwani) -* `#6935 `_ Use the standard cache and logs dir for the micro kernel example (javiereguiluz) -* `#6970 `_ Fix subject/verb agreement (micheal) -* `#6971 `_ Update composer.rst (TravisCarden) -* `#6983 `_ Update voters.rst (seferov) -* `#6986 `_ Fixed directory name typo (JoeThielen) -* `#6988 `_ fix link role syntax (xabbuh) -* `#6960 `_ [Reference] add back the option's description (xabbuh) -* `#6987 `_ Update input.rst (adyassine) -* `#6974 `_ Fix minor typo in security chapter How to Build a Traditional Login Form (peterkokot) -* `#6941 `_ Mentioned the "Symfony Upgrade Fixer" in the upgrade article (javiereguiluz) -* `#6936 `_ Improved the title of Validation Groups article to make it easier to find (javiereguiluz) -* `#6925 `_ Method "$this->getMock()" is deprecated (JohnnyEvo) -* `#6922 `_ [Config] Add ExprBuilder::ifEmpty() (ogizanagi) -* `#6964 `_ Fix typo in validator example (svenluijten) -* `#6945 `_ Fixed indentation issues in alias_private article (javiereguiluz) -* `#6954 `_ Typo fix in tags.rst (NoScopie) -* `#6955 `_ Typo in the class name. (pythagor) - - -August, 2016 ------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6903 `_ Remove reference to profiler lifetime property that was removed in 3.x (jameshalsall) -* `#6908 `_ Add deprecation warnings to relevant profiler options (jameshalsall) -* `#5974 `_ [PropertyInfo] Add Component Documentation (zanderbaldwin) -* `#6765 `_ [Contributing] [Standards] Do not use spaces inside/around offset accessors (phansys) -* `#6746 `_ Removing the alias stuff - not required after symfony/symfony#17074 (weaverryan) -* `#6798 `_ Finishing Validator Docs (wouterj, mickaelandrieu, javiereguiluz, weaverryan) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6915 `_ Fix the error in code example (kruglikov) -* `#6907 `_ fix wrong variable name in OptionsResolver example (dincho) -* `#6904 `_ Update create_custom_field_type.rst (tuanalumi) -* `#6892 `_ Update custom_provider.rst (asandjivy) -* `#6884 `_ service_container : fix php Definition instance (ReDnAxE) -* `#6883 `_ [Routing] Fix a route path in a routing example (thomasbisignani) -* `#6869 `_ Update templating.rst (asandjivy) -* `#6822 `_ Adjust Application use statement (kvdnberg) -* `#6881 `_ Error in CSRF example code snippet (makoru-hikage) -* `#6863 `_ Update argument_value_resolver.rst (asandjivy) -* `#6852 `_ Fix Cache Pools: SQLite3Cache constructor argument (wimme002) -* `#6848 `_ Fix Varnish 4 code example (Dreimus) -* `#6845 `_ Fixed the extension of a logging article (javiereguiluz) -* `#6790 `_ Simplex\Framework contructor - remove extra parameter (alchimik) -* `#6793 `_ Simplex\Framework - add argumentResolver property (alchimik) -* `#6800 `_ Fix missing function name (JosefVitu) -* `#6843 `_ fix index directive syntax (xabbuh) -* `#6784 `_ Fix CS for form templates locations (javiereguiluz) -* `#6797 `_ fix FlattenException namespace (alchimik) -* `#6787 `_ Fix reference to output object (micheal) -* `#6761 `_ fixed missing level in namespace (themasch) -* `#6757 `_ Fix typo in external_parameters.rst (gmorel) -* `#6754 `_ Add missing use statements to data collector example (richardmiller) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6921 `_ Fix var_dumper advanced usage link (ogizanagi) -* `#6913 `_ [Controller Description] Fix typos and class link (rendler-denis) -* `#6909 `_ DumpFile() third argument is deprecated and doesn't exists anymore (mickaelandrieu) -* `#6901 `_ [EventDispatcher] paragraph duplicated (ReDnAxE) -* `#6899 `_ Update access_control.rst (asandjivy) -* `#6898 `_ Fixes after tonight's merge round (wouterj) -* `#6896 `_ Tweaks to property info component (weaverryan) -* `#6888 `_ Update http_kernel_controller_resolver.rst (audiua) -* `#6887 `_ [FormComponent] Fix typos (rendler-denis) -* `#6849 `_ Link to inversedBy/mappedBy documentation (soulchainer, wouterj) -* `#6846 `_ Adds bin folder creation instruction (joelrfcosta) -* `#6835 `_ Updated the instructions to build docs locally (javiereguiluz) -* 5a5720fe minor #6834 Refactored how to get the container in a test (javiereguiluz) -* `#6814 `_ Created the main article about "deployment" (javiereguiluz) -* `#6882 `_ Update serializer.rst (seferov) -* `#6880 `_ Remove extra quotes from ExprBuilder::thenInvalid() usage (chalasr) -* `#6878 `_ missing "`" (jevgenijusr) -* `#6877 `_ added lyrixx to the core team (fabpot) -* `#6867 `_ Add a class specificity for SplFileInfo text (rendler-denis) -* `#6872 `_ Remove redundant verb (julienfalque) -* `#6866 `_ Deprecated message with "true" parameter (wazz42) -* `#6862 `_ Remove unused JsonResponse dependency in example (Farskies) -* `#6855 `_ [Form] Use composer require instead of modifying composer.json (wouterj) -* `#6853 `_ Logrotate moved to GitHub (wouterj) -* `#6851 `_ Update lazy_services.rst (takeit) -* `#6794 `_ Added a new section to the page templating/global_vars using a EVListener (piet, Piet Bijl) -* `#6850 `_ Remove outdated reference (hvt) -* `#6824 `_ Service naming convension (orions) -* `#6825 `_ update `cache` and `logs` folder locations (georgiana-gligor) -* `#6829 `_ Fix a typo in an HTTP Cache code example (aybbou) -* `#6833 `_ Fixed a syntax issue in custom_constraint article (javiereguiluz) -* `#6842 `_ Fixed service name (jeremyFreeAgent) -* `#6803 `_ Remove complex speech pattern (micheal) -* `#6805 `_ Remove colloquialism "hold on" (micheal) -* `#6796 `_ Remove AcmeDemoBundle references (michaelcullum) -* `#6786 `_ Subject-verb agreement (micheal) -* `#6759 `_ Fix tense and sentence length (aalaap) -* `#6748 `_ Fix web/front.php (ranqiangjun) -* `#6820 `_ Fixed the main index page redirections (javiereguiluz) -* `#6819 `_ Fixed the redirection for "upgrade" articles (javiereguiluz) -* `#6812 `_ Fixed a Console article redirection (javiereguiluz) -* `#6807 `_ Fixed the redirection of the cookbook/psr7 article (javiereguiluz) -* `#6806 `_ Fixed the redirection of some cache articles (javiereguiluz) -* `#6808 `_ Fixed a DI redirection (javiereguiluz) -* `#6810 `_ Fixed the redirection of the previous "performance" book chapter (javiereguiluz) -* `#6816 `_ Added all the missing "index pages" redirections (javiereguiluz) - - -July, 2016 ----------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6744 `_ [Form] Ambiguous block prefixes render incorrectly (foaly-nr1) -* `#6611 `_ Discourage the use of controllers as services (javiereguiluz) -* `#5672 `_ Add constants to BC promise (WouterJ) -* `#6737 `_ Document the file() controller helper (javiereguiluz) -* `#6707 `_ Describe serialization config location in cookbook (jcrombez, WouterJ) -* `#6726 `_ Use getParameter method in controllers (peterkokot) -* `#6727 `_ Updated the condition to display console name (mickaelandrieu) -* `#6701 `_ [CS] Avoid using useless expressions (phansys) -* `#6422 `_ Documented the ArgumentResolver along the ControllerResolver (iltar) -* `#6705 `_ [Process] Introduce InputStream and iterator for output (nicolas-grekas) -* `#6673 `_ Caution about impersonation not compatible with pre authenticated (pasdeloup) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6634 `_ Update custom_constraint.rst (axelvnk) -* `#6719 `_ [Components][Browser-Kit]Fix typo with CookieJar (Denis-Florin Rendler) -* `#6717 `_ Cache Component: Fix SQLite3Cache instanciation (ReDnAxE) -* `#6687 `_ Namespace fix (JhonnyL) -* `#6714 `_ UppercaseRot13Transformer wrong class name used (jevgenijusr) -* `#6704 `_ Encountered an error when following the steps for contribution (chancegarcia) -* `#6708 `_ Routes should be just imported, not mounted (OndraM) -* `#6708 `_ Routes should be just imported, not mounted (OndraM) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6778 `_ fix syntax errors (xabbuh) -* `#6777 `_ fix code block indentation (xabbuh) -* `#109 `_ after merge fixes (xabbuh) -* `#107 `_ fix bugs due to choosing the wrong base branch (xabbuh) -* `#108 `_ fix another bug due to choosing the wrong branch (xabbuh) -* `#105 `_ fix bugs due to choosing the wrong base branch (xabbuh) -* `#102 `_ Updated the Global Composer Installation article (javiereguiluz) -* `#101 `_ Update some screenshots to wrap them with a browser window (javiereguiluz) -* `#104 `_ complete component cross references (xabbuh) -* `#106 `_ some minor tweaks (xabbuh) -* `#98 `_ Remove mentions of cookbook/book (WouterJ) -* `#97 `_ Rewrote the Console articles (WouterJ, javiereguiluz) -* `#99 `_ Rename cache/ to http_cache/ (WouterJ) -* `#100 `_ Add file extension to SOAP article (WouterJ) -* `#92 `_ Make usage of "The" in the edition list consistent (WouterJ) -* `#91 `_ Create a section for "Getting Started" so we can generate a book (javiereguiluz) -* `#86 `_ bootstrapping Workflow component docs (weaverryan) -* `#77 `_ Proofing the controller chapter (weaverryan) -* `#90 `_ Fixed doc build issues (javiereguiluz) -* `#82 `_ Bootstrapping property info doc (weaverryan) -* `#79 `_ Shortening the setup section (weaverryan) -* `#81 `_ Merging setup and install directories (weaverryan) -* `#84 `_ Bootstrapping the validator components (weaverryan) -* `#87 `_ Moving the email guide to the top level (weaverryan) -* `#88 `_ Moving event_dispatcher/event_listener.rst -> event_dispatcher.rst (weaverryan) -* `#78 `_ Move redirection_map from root (WouterJ) -* `#54 `_ split the Security chapter (xabbuh) -* `#53 `_ split the Validation chapter (xabbuh) -* `#63 `_ Readded removed versionadded directives (WouterJ) -* `#55 `_ Created the "Set Up" topic (WouterJ) -* `#62 `_ Rename includes directory to _includes (WouterJ) -* `#61 `_ Fix install/upgrade references (WouterJ) -* `#58 `_ The no-brainer topic merges/removal (WouterJ) -* `#56 `_ Fix build errors (WouterJ) -* `#39 `_ Deleting index files - using globbing (weaverryan, WouterJ) -* `#47 `_ Move nested service container articles to sub-topic root (WouterJ) -* `#50 `_ Move images to _images and group by topic (WouterJ) -* `#32 `_ Move all cookbook contents (javiereguiluz) -* `#28 `_ split the routing chapter (xabbuh) -* `#30 `_ Moved the rest of the book chapters (javiereguiluz) -* `#24 `_ Moved book chapters out of the book (javiereguiluz) -* `#20 `_ Creating the Controller topic (xabbuh) -* `#6747 `_ Correcting reference to ``isSuccessful()`` method for Process (aedmonds) -* `#6600 `_ Removing some extra details from #6444 (weaverryan) -* `#6715 `_ [Book] Remove DI extension info and link the cookbook article instead (WouterJ) -* `#6745 `_ Branch fix (Talita Kocjan Zager, weaverryan) -* `#6743 `_ Finishing #6252 (Talita Kocjan Zager, weaverryan) -* `#6656 `_ Clarify usage of handler channel configuration (shkkmo) -* `#6664 `_ replace occurrences of `_ Add little comment indicating meaning of $firewall variable (ruslan-fidesio, WouterJ) -* `#6734 `_ Add little caution to add service id for @Route annotation (DHager, WouterJ) -* `#6735 `_ Change _method parameter versionadded note (sfdumi, WouterJ) -* `#6736 `_ Use message argument for PHPunit assert() functions (SimonHeimberg, WouterJ) -* `#6739 `_ fix list item termination character (xabbuh) -* `#6218 `_ path() explanation inside templating + Minor formatting changes (sfdumi) -* `#6559 `_ Update lazy_services.rst (hboomsma) -* `#6733 `_ [DX] Form Types location contradicts Best Practices (pbowyer) -* `#6264 `_ Update email.rst (mikaelz) -* `#6633 `_ Added escaping tip (xDaizu) -* `#5464 `_ Removed the glossary (WouterJ) -* `#6665 `_ use PDO prepared statement - avoid straw man (dr-matt-smith) -* `#6700 `_ Update monolog.rst (zhil) -* `#6720 `_ [Component][ClassLoader]Remove invalid note (rendler-denis) -* `#6613 `_ Clarify documentation on serving files (raphaelm) -* `#6723 `_ Require latest Symfony version (yhoiseth) -* `#6721 `_ [Finder] Fixed typo in RealPath method on SplFileInfo class (acrobat) -* `#6716 `_ Typo fix "they the name" => "that the name" (jevgenijusr) -* `#6702 `_ Removed empty ``Notes on previous versions`` (mickaelandrieu) -* `#6709 `_ Fix URL in http basic screenshot (WouterJ) -* `#6706 `_ Update "How to Authenticate Users with API Keys" (gondo, WouterJ) -* `#5892 `_ Updated the session proxy article (javiereguiluz) -* `#6699 `_ [Cache] add versionadded directive (xabbuh) -* `#6697 `_ [Asset] add versionadded directive (xabbuh) -* `#6698 `_ [Ldap] add versionadded directive (xabbuh) - - -June, 2016 ----------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6515 `_ Added the documentation for the Cache component (javiereguiluz) -* `#6623 `_ [Console] Adapt doc for easier testing of commands needing user inputs (chalasr) -* `#6690 `_ Added an example for a different method of verbosity level usage. (smatyas) -* `#6648 `_ Process: callbacks now allowed when output disabled (avindra) -* `#6587 `_ Updating recommended email settings for monolog (jorgelbg) -* `#6617 `_ [WSSE] - Using a PSR6 cache instead of file cache (Nyholm) -* `#6438 `_ Added docs about ArgumentValueResolvers (iltar) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6679 `_ Invalid PHP return statement (JohnnyEvo) -* `#6675 `_ Update broken links to default VCL files (sgrodzicki) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6597 `_ [Validator] Add shorter examples using the default option (alexmart) -* `#6696 `_ Typo fix (jevgenijusr) -* `#6693 `_ Add missing parameter (rodnaph) -* `#6614 `_ Updated the CS rule about return null; and return; (javiereguiluz) -* `#6680 `_ Fix ldap security examples (jvasseur) -* `#6692 `_ Update date.rst - Fixes typo (fdarre) -* `#6689 `_ Hard values for the driver option (iltar) -* `#6685 `_ NullOutput should be passed to $command->run() (Ma27) -* `#6676 `_ Removed 'html' from the component description (naroga) -* `#6674 `_ CheckStyle in Voters cookbook (JakeFr) -* `#6672 `_ [Book][Testing] remove Symfony core testing note (xabbuh) -* `#6670 `_ Fix typo 'even' >> 'event' in event_listener.rst (kuusas) -* `#6667 `_ [Contributing][Code] fix list item terminators (xabbuh) -* `#6616 `_ Better explain the mandatory/convention location of some elements (rcousens, javiereguiluz) -* `#6628 `_ Fix for #6625 (kix) -* `#6668 `_ [Contributing][Code] remove PHPUnit requirement (xabbuh) -* `#6654 `_ Update upload_file.rst (liubinas) -* `#6650 `_ fix dumper default representation (Jamal Youssefi) -* `#6652 `_ ``Finder::path()`` method matching directories and files (soyuka) -* `#6662 `_ preg_match throw an warning (nicolae-stelian) -* `#6651 `_ [#6438] some tweaks to the argument value resolver (xabbuh) -* `#6658 `_ [Process] tweak a sentence (xabbuh) -* `#6599 `_ Fixed null description of query_builder option (HeahDude) -* `#6638 `_ swap terminate and exception event descriptions (xabbuh) -* `#6615 `_ Minor grammar fix (aalaap) -* `#6637 `_ Update security.rst (norbert-n) -* `#6644 `_ [Console] Fix wrong quotes in QuestionHelper::setInputStream() (chalasr) -* `#6645 `_ Fix bootstrap class name help-block (foaly-nr1) -* `#6642 `_ do not reference unused interface (xabbuh) -* `#6641 `_ [Book][Form] fix reference to renamed document (xabbuh) -* `#6579 `_ Added callable validation_groups example (gnat42) -* `#6626 `_ reflect the EOM of Symfony 2.3 (xabbuh) -* `#6631 `_ Fix console.exception and console.terminate order (Julien Falque) -* `#6629 `_ Update options_resolver.rst (atailouloute) -* `#6627 `_ Fixed a typo in cookbook/security/entity_provider (michaeldegroot) -* `#6618 `_ Added a note about coding standards and method arguments (javiereguiluz) - - -May, 2016 ---------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6402 `_ [RFR] Documentation for the Ldap component (csarrazi) -* `#6040 `_ Remove old File Upload article + improve the new one (WouterJ) -* `#6412 `_ added a maintenance document (fabpot) -* `#6554 `_ Adding information about using the date type as usable date picker field (weaverryan) -* `#6590 `_ Added note on YAML mappings as objects (dantleech) -* `#6378 `_ refs #5898 Fix updates of testing.rst for 3.0 (guilliamxavier) -* `#6583 `_ Adding a description for the use_microseconds parameter introduced in MonologBundle v2.11 (jorgelbg) -* `#6582 `_ Advanced YAML component usage (dantleech) -* `#6594 `_ Allowed to return null for query_builder (JonEastman) -* `#6502 `_ Added the json() shortcut to the controller chapter (dfridrich, javiereguiluz) -* `#6593 `_ Adding the payload parameter to the callback examples (jorgelbg) -* `#6405 `_ Added the explanation about addClassesToCompile() method (javiereguiluz) -* `#6539 `_ Documented the "autoescape" TwigBundle config option (javiereguiluz) -* `#5574 `_ [2.7] Update Twig docs for asset features (javiereguiluz, WouterJ) -* `#6433 `_ Documented the detectCorrupted and corruptedMessage options (javiereguiluz) -* `#6406 `_ Added a note about the new "disabled" option for PHPUnitBridge (javiereguiluz) -* `#6302 `_ [Form] add ``choice_translation_domain`` option to date types (HeahDude) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6619 `_ Fix wrong variable name in comment (zanardigit) -* `#6608 `_ deprecated 'datettime' Form Type (dsmink) -* `#6606 `_ fix #6602 (yamiko-ninja) -* `#6578 `_ [Cookbook][Profiler] Fix arguments for Profiler::find() (hason) -* `#6546 `_ Make ClockMock Tests\\ namespace matching less specific (teohhanhui) -* `#6564 `_ [PhpUnitBridge] Remove section about clock mocking (z38) -* `#6552 `_ Typo fix in the Serializer deserialization example for existing object (fre5h) -* `#6545 `_ Replace property_accessor by property_access (jbenoit2011) -* `#6561 `_ About Templating Naming Pattern (raulconti) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6601 `_ Deprecated usage of AsseticBundle removed from bundles.rst (Vehsamrak) -* `#6624 `_ remove versionadded directive for 2.x features (xabbuh) -* `#6620 `_ Move PSR to correct place on index page (WouterJ) -* `#6609 `_ Use a better escaping mechanism for data-prototype attr (javiereguiluz) -* `#6380 `_ [book] [validation] Constraints can be applied to an entire class too (sustmi) -* `#6459 `_ Remove choices as values in 3.0 (weaverryan) -* `#6444 `_ [Form] fixed EntityType choice options (HeahDude) -* `#6367 `_ Simplified the contribution article for Symfony Docs (javiereguiluz) -* `#6419 `_ Update routing.rst (tamtamchik) -* `#6598 `_ [Yaml] use static Yaml API (xabbuh) -* `#6589 `_ Clarify signed requests in the ESI renderer (WouterJ) -* `#6596 `_ Fixed query_builder option (HeahDude) -* `#6595 `_ Added a note about "encoding vs. hashing" passwords (javiereguiluz) -* `#6581 `_ [#6431] changing "Simple Example" to use implode/explode (mccullagh) -* `#6585 `_ 6555 link to Download instructions page & Windows executable (snoek09) -* `#6588 `_ Update configuration.rst (superhaggis) -* `#6591 `_ 5953 use kernel events constants (snoek09) -* `#6592 `_ [Form] Making the name property private to be more realistic (weaverryan) -* `#6541 `_ Trusted proxies were removed when URL signing took over (rawkode) -* `#6586 `_ 6338 use csrfManager instead of csrfProvider (snoek09) -* `#6401 `_ Added Link to Cmder (c33s) -* `#6391 `_ Fix mem leak in example doctrine testing (nicolas-grekas) -* `#6087 `_ Add a note about needing to install proxy-manager (mcfedr) -* `#6569 `_ [Reference] change namespace to point to new class (xabbuh) -* `#6553 `_ EntityType: query_builder link to usage (weaverryan) -* `#6572 `_ Edited BowerPHP tip (SecondeJK) -* `#6575 `_ Rename command logging services (sroze) -* `#6577 `_ [Cookbook][Profiler] Remove mention of import/export (hason) -* `#6571 `_ [Cookbook][Console] Minor: Fix typo (andreia) -* `#6570 `_ Fix typo (jdreesen) -* `#6568 `_ fix RequestDataCollector class namespace (xabbuh) -* `#6566 `_ Update options_resolver.rst (snake77se) -* `#6548 `_ merge choice_translation_domain files (xabbuh) -* `#6547 `_ remove 2.x versionadded directives (xabbuh) -* `#6563 `_ [PhpUnitBridge] Add versionadded directive to clock mocking section (z38) -* `#6549 `_ drop AppBundle examples in components section (xabbuh) -* `#6562 `_ Remove extra spaces in Nginx template (bocharsky-bw) -* `#6557 `_ [ClassLoader] Add missed link to the external PSR-4 specification (nicolas-grekas, fre5h) -* `#6511 `_ [DependencyInjection] Improved "optional argument" documentation (dantleech) -* `#6455 `_ Editing the Doctrine section to improve accuracy and readability (natechicago) -* `#6526 `_ Documented how to configure Symfony correctly with regards to the Forwarded header (magnusnordlander) -* `#6535 `_ Improved the description of the Twig global variables (javiereguiluz) -* `#6536 `_ [DomCrawler] Removed references to CssSelector (aerialls) -* `#6529 `_ [DependencyInjection] Unquote services FQCN in autowiring examples (chalasr) -* `#6530 `_ [DependencyInjection] Unquote services FQCN in parent-services examples (chalasr) -* `#6517 `_ Add a warning about using same user for cli and web server (pasdeloup) -* `#6504 `_ Improved the docs for the DependencyInjection component (javiereguiluz) -* `#6506 `_ Added a tip about routes and container parameters (javiereguiluz) -* `#6518 `_ Add details about chmod +a vs setfacl (pasdeloup) -* `#6525 `_ [Contributing] use more precise version checker URL (xabbuh) -* `#6528 `_ Fixed a minor indentation issue (javiereguiluz) - - -April, 2016 ------------ - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6470 `_ Documented the config options of TwigBundle (javiereguiluz) -* `#6427 `_ [Testing] Explain how to add or remove data in a collection of forms (alexislefebvre) -* `#6465 `_ Added ldap to the list of user providers (AAstakhov) -* `#6437 `_ Improved the documentation about the explicit column widths (javiereguiluz) -* `#6450 `_ [Form] added prototype_data option in CollectionType (kgilden, HeahDude) -* `#6394 `_ Updated Heroku instructions (magnusnordlander) -* `#6388 `_ Added the docs for the @dns-sensitive mocks (javiereguiluz) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6503 `_ Fix typo in from flat PHP to Symfony (gregfriedrice, WouterJ) -* `#6483 `_ Fix typo: signifcantly => significantly (ifdattic) -* `#6482 `_ fixed wrong secret string in array examples (OskarStark) -* `#6460 `_ Update authorization.rst (mantulo) -* `#6451 `_ fix status code in snippet (Barno) -* `#6448 `_ [Form] fixed CollectionType needless option (HeahDude) -* `#6439 `_ Fix form/validation directory path (nemo-) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6522 `_ On line 360 the ``404 Not Found`` header not working (mbrig-co) -* `#6521 `_ The ``$link`` argument must be passed as a reference (mbrig-co) -* `#6523 `_ Fix snippet (ismailbaskin) -* `#6472 `_ Avoid confusion (gerryvdm) -* `#6300 `_ Document constraint validator alias optional (Triiistan) -* `#6513 `_ remove documentation of not supported "verbose" option value (TobiasXy) -* `#6507 `_ fix typo (tyx) -* `#6509 `_ Update http_kernel_httpkernel_class.rst (AchillesKal) -* `#6510 `_ use port 587 in Amazon SES example (snoek09) -* `#6464 `_ Added possible values for access_decision_manager.strategy (AAstakhov) -* `#6469 `_ Tweaks for the DNS-sensitive tests doc (javiereguiluz) -* `#6478 `_ Replace reference to the request service (gerryvdm) -* `#6479 `_ Update php.rst (carlos-granados) -* `#6481 `_ Remove reference to Symfony2 in request-flow.png (Daniel Cotton) -* `#6471 `_ fix broken merge (xabbuh) -* `#6449 `_ [Form] fixed ChoiceType example in CollectionType (HeahDude) -* `#6445 `_ updated the core team (fabpot) -* `#6423 `_ Added a caution note about REMOTE_USER and user impersonation (javiereguiluz) -* `#6452 `_ Use different placeholders in mailer config (sblaut) -* `#6457 `_ Fixed an array notation in comment (serializer.rst) (iltar) -* `#6456 `_ Fixed array [] notation and trailing spaces (iltar) -* `#6420 `_ Added tip for optional second parameter for form submissions. (Michael Phillips) -* `#6418 `_ fix spelling of the flashBag() method (xabbuh) -* `#6432 `_ fixed yaml config error (RickieL) - - -March, 2016 ------------ - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6274 `_ Update Doctrine UTF8 docs (mcfedr) -* `#6314 `_ New normalizers (mcfedr) -* `#4971 `_ [DomCrawler] Document images crawler (valeriangalliat) -* `#6296 `_ [Console] Add columns width setter documentation (akeeman) -* `#6282 `_ [Form] fix ``choice_label`` values (HeahDude) -* `#5894 `_ [WIP] Added an article to explain how to upgrade third-party bundles to Symfony 3 (javiereguiluz) -* `#6273 `_ [PHPUnit bridge] Add documentation for the component (theofidry) -* `#6316 `_ [Validator] Added docs about the format option (dosten) -* `#6291 `_ fortrabbit deployment guide + index listing (ostark) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6377 `_ Update "bootstrap.php.cache" to "autoload.php" (guilliamxavier) -* `#6368 `_ [cookbook] Made list of form types more consistent (AAstakhov) -* `#6366 `_ Removed server:stop code block for 2.3 (theyoux) -* `#6347 `_ Add a note about enabling DebugBundle to use VarDumper inside Symfony (martijn80, javiereguiluz) -* `#6320 `_ Fixed typo in path (timhovius) -* `#6334 `_ Fixed yaml configuration of app.exception_controller (AAstakhov) -* `#6322 `_ [DependencyInjection] fix autowiring docs (eXtreme) -* `#6315 `_ Remove third parameter from createFormBuilder call (Hocdoc) -* `#6324 `_ Fixed UserCheckerInterface importing (VIs-a-vis) -* `#6326 `_ Missing svn:ignore (f-plante) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6404 `_ fixed a typo (RickieL) -* `#6409 `_ Update 'date' to DateType::class in form.rst (iltar) -* `#6411 `_ Fixed a typo in configuration-block (VarunAgw) -* `#6414 `_ stick to Sphinx 1.3.x for the moment (xabbuh) -* `#6399 `_ Fixed wrong code examples for Isbn constraint (AAstakhov) -* `#6397 `_ Fix typo in SwitchUserListener file name (luxifer) -* `#6390 `_ Reworded the example about $deep param (Oliboy50, javiereguiluz) -* `#6381 `_ [Form] [Cookbook] Correctly setup unit tests with dependencies (corphi) -* `#6382 `_ unused use instructions (bshevchenko) -* `#6365 `_ Removed the PR table example (this is now included by GitHub template) (javiereguiluz) -* `#6363 `_ Removed info about reducing visibility for private (AAstakhov) -* `#6362 `_ [book] Updated link to Translatable Extension (AAstakhov) -* `#6336 `_ Added minor clarification (ThomasLandauer) -* `#6303 `_ Tweaked the Symfony Releases page (javiereguiluz) -* `#6360 `_ Editing the Doctrine section to improve accuracy and readability (natechicago) -* `#6352 `_ [book] controller ch review, part 3 (Talita Kocjan Zager) -* `#6351 `_ [book] controller ch review, part 2 (Talita Kocjan Zager) -* `#6349 `_ [book] controller ch review, part 1 (Talita Kocjan Zager) -* `#6369 `_ Minor corrections (sfdumi) -* `#6370 `_ Fixed typo (tabbi89) -* `#6371 `_ Fix escaping of backtick inside double back-quotes (guilliamxavier) -* `#6364 `_ [reference] [constraints] added missing colon character for Image constraint documentation in YAML format. (hhamon) -* `#6345 `_ Remove link-local IPv6 address (snoek09) -* `#6219 `_ Point that route parameters are also Request attributes (sfdumi) -* `#6348 `_ [best practices] mostly typos (Talita Kocjan Zager) -* `#6350 `_ Fix reference to app folder (kainjow) -* `#6275 `_ [quick tour] mostly typos (Talita Kocjan Zager) -* `#6305 `_ Mention IvoryCKEditorBundle in the Symfony Forms doc (javiereguiluz) -* `#6331 `_ Rename DunglasApiBundle to ApiPlatform (sroze) -* `#6328 `_ Update extension.rst - added caution box for people trying to remove the default file with services definitions (Pavel Jurecka) -* `#6343 `_ Replace XLIFF number ids by strings (Triiistan) -* `#6344 `_ Altered single / multiple inheritance sentence (outspaced) -* `#6330 `_ [Form] reorder EntityType options (HeahDude) -* `#6337 `_ Fix configuration.rst typo (gong023) -* `#6295 `_ Update tools.rst (andrewtch) -* `#6323 `_ [DependencyInjection] Add Autowiring keyword (theofidry) -* `#6325 `_ Minor error (ThomasLandauer) -* `#6311 `_ Improved TwigExtension to show default values and optional arguments (javiereguiluz) -* `#6286 `_ [HttpFoundation] Fix typo for ParameterBag getters - 3.0 (rendler-denis) -* `#6267 `_ [Form] fix 'data_class' option in EntityType (HeahDude) -* `#6281 `_ Change isValid to isSubmitted. (mustafaaloko) - - -February, 2016 --------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6172 `_ move assets options from templating to assets section and add base_path documentation (snoek09) -* `#6021 `_ mention routing from the database (dbu) -* `#6032 `_ [DependencyInjection] Autowiring doc (dunglas) -* `#6233 `_ Document translation_domain for choice fields (merorafael, WouterJ) -* `#5655 `_ Added doc about Homestead's Symfony integration (WouterJ) -* `#5886 `_ [2.8] Add "How to Use Multiple Guard Authenticators" cookbook documentation (mheki) -* `#6072 `_ Add browserkit component documentation (yamiko, yamiko-ninja, robert Parker, javiereguiluz) -* `#6243 `_ Add missing getBoolean() method (bocharsky-bw) -* `#6076 `_ added a sentence about the HttpException::setHeaders method (smatyas) -* `#6231 `_ Use hash_equals instead of StringUtils::equals (WouterJ) -* `#6186 `_ [Console] Add FormatterHelper::truncate docs (mheki) -* `#5530 `_ [Cookbook, Security] Added user_checkers.rst (iltar) -* `#5920 `_ Document automatic registration of extension compiler passes (WouterJ) -* `#5724 `_ Describe configuration behaviour with multiple mailers (xelan) -* `#6077 `_ fixes #5971 (vincentaubert) -* `#5483 `_ [FrameworkBundle] Name converter of Serializer (dunglas) -* `#6156 `_ [reference] [form] [options] fix #6153 (HeahDude) -* `#6104 `_ Fix #6103 (zsturgess) -* `#6058 `_ Update Testing Form Types article for 2.8 refactorings (WouterJ) -* `#5856 `_ Reworded the "How to use Gmail" cookbook article (javiereguiluz) -* `#6230 `_ Add annotation to glossary (rebased) (DerStoffel) -* `#5642 `_ Documented label_format option (WouterJ) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6292 `_ Fix setting permission for var subdirectories (voda) -* `#5995 `_ Update dev_environment.rst (gonzalovilaseca) -* `#6240 `_ [#6224] some tweaks (xabbuh) -* `#5513 `_ [load_balancer_reverse_proxy ] Always use 127.0.0.1 as a trusted proxy (ruudk) -* `#6081 `_ [cookbook New project] Fix symfony version and initial add (bigs21) -* `#6124 `_ [cookbook] Add annotations block and fix regex (peterkokot) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6308 `_ fix literal syntax (xabbuh) -* `#6299 `_ Removed True and False constraints from reference (edefimov) -* `#6298 `_ Update dependency_injection.rst because it has an error. (joserprieto) -* `#6263 `_ [Cookbook][Debugging] reflect behavior changes in cache generation (xabbuh) -* `#6251 `_ To use annotations, files must be removed (pbowyer) -* `#6288 `_ Update factories.rst (velikanov) -* `#6278 `_ [HttpFoundation] Fix typo for ParameterBag getters (rendler-denis) -* `#6280 `_ Fix syntax of Company class example (cakper) -* `#6284 `_ [Book] [Routing] Fix third param true to UrlGeneratorInterface::ABSOLUTE_URI (eriwin) -* `#6269 `_ [Cookbook][Bundles]fix yaml syntax (mhor) -* `#6277 `_ remove dot in front of colon (xabbuh) -* `#6255 `_ [Cookbook][Doctrine] some tweaks to the Doctrine registration article (xabbuh) -* `#6229 `_ Rewrite EventDispatcher introduction (WouterJ) -* `#6260 `_ add missing options `choice_value`, `choice_name` and `choice_attr` to `EntityType` (HeahDude) -* `#6262 `_ [Form] reorder options in choice types references (HeahDude) -* `#6256 `_ Fixed code example (twifty) -* `#6257 `_ [Components][Form] remove outdated caution (xabbuh) -* `#6253 `_ [Security] Include guard firewall configuration sample. (calinpristavu) -* `#6250 `_ [Cookbook][Console] remove note about memory spool handling on CLI (xabbuh) -* `#6249 `_ [Cookbook][Serializer] fix wording (xabbuh) -* `#6242 `_ Removed all 2.x versionadded directives (WouterJ) -* `#6246 `_ removed duplicate lines (seferov) -* `#6222 `_ Updated "Learn more from the Cookbook" section (sfdumi) -* `#6245 `_ [Cookbook][Console] change API doc class name (xabbuh) -* `#6223 `_ Improveme the apache/mod_php configuration example (gnat42) -* `#6234 `_ File System Security Issue in Custom Auth Article (finished) (mattjanssen, WouterJ) -* `#4773 `_ [Cookbook] Make registration_form follow best practices (xelaris) -* `#6090 `_ Reworded the article about profiler storage (xavierleune, javiereguiluz) -* `#5630 `_ Add a caution about logout when using http-basic authenticated firewall (rmed19) -* `#6215 `_ Added a caution about failing cache warmers (javiereguiluz) -* `#6239 `_ Remove app_dev as build-in server is used (rmed19, WouterJ) -* `#6241 `_ [ExpressionLanguage] Add caution about backslash handling (zerustech, WouterJ) -* `#6235 `_ #6232 update forms as services section (backbone87) -* `#6236 `_ fix some minor typos (xabbuh) -* `#6237 `_ use literals for external class names (xabbuh) -* `#6206 `_ add separate placeholder examples for birthday, datetime and time type (snoek09) -* `#6238 `_ fix directive name (xabbuh) -* `#6224 `_ Note to create a service if you extend ExceptionController (pamuche) -* `#5958 `_ Update security.rst (mpaquet) -* `#6092 `_ Updated information about testing code coverage. (roga) -* `#6051 `_ Mention HautelookAliceBundle in best practices (theofidry, WouterJ) -* `#6044 `_ Added note about the hash_equals polyfill (WouterJ) -* `#6213 `_ Update form_collections.rst (insekticid) -* `#6220 `_ [book] fixes typo about redirect status codes in the controller chapter. (hhamon) -* `#6227 `_ Update testing.rst (dvapelnik) -* `#6228 `_ removed unnecessary exception from repository (gondo) -* `#6212 `_ Typo in default session save_path (DerekRoth) -* `#6208 `_ Replace references of PSR-0 with PSR-4 (opdavies) -* `#6170 `_ change translation getMessages() to getCatalogue() (snoek09) -* `#6211 `_ Remove 2.3.\* from composer snippets in the form component doc (Nicofuma) -* `#6225 `_ [Reference][Forms] add versionadded directive for range type (xabbuh) -* `#6190 `_ Fix redundant command line sample (sylozof) - - -January, 2016 -------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#6174 `_ Missing reference docs for kernel.finish_request event (acrobat) -* `#6184 `_ added Javier as a merger for the WebProfiler bundle (fabpot) -* `#6136 `_ Update directory permissions to make var/ writable (andrerom) -* `#5600 `_ [DependencyInjection] Documented the ability of define the service decoration priority (dosten) -* `#5303 `_ [WIP] 4373 - document security events (kevintweber) -* `#6023 `_ clarify the routing component documentation a bit (dbu) -* `#6091 `_ Added an example for info() method (javiereguiluz) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6193 `_ Added the missing namespace in example of a subscriber class (raulconti) -* `#6152 `_ csrf_token_generator and csrf_token_id documentation (Raistlfiren, Aaron Valandra, xabbuh) -* `#6115 `_ [Form] Fix syntax error in code snippet (valisj) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6199 `_ fix types (garak) -* `#6207 `_ revert form login CSRF changes on wrong branch (xabbuh) -* `#6191 `_ Document the invalidate_session option (javiereguiluz) -* `#6204 `_ Expected: semicolon (cn007b) -* `#6141 `_ Docs do not match functionality (Loupax) -* `#6192 `_ fix MongoDB shell syntax highlighting (xabbuh) -* `#6147 `_ Update templating.rst - Asset absolute url fix (gbalcewicz) -* `#6187 `_ Typofix for "Defining and Processing Configuration Values" (kix) -* `#6182 `_ Latest demo has no bin folder (Jace25) -* `#6183 `_ use valid XML in code block (xabbuh) -* `#6180 `_ use single quotes for YAML strings (snoek09) -* `#6070 `_ Typo in When Things Get More Advanced (BallisticPain) -* `#6119 `_ Remove phrase "in order" (micheal) -* `#6160 `_ remove versionadded for unmaintained versions (xabbuh) -* `#6161 `_ [Contributing][Documentation] replace EOL with EOM (xabbuh) -* `#6166 `_ Fix by_reference deprecated FormType::class (nemo-) -* `#6162 `_ [Reference] add missing version number (xabbuh) -* `#6163 `_ Remove excessive pluses (aivus) -* `#6082 `_ change app/check.php for 3.0 (nanocom) -* `#6149 `_ Reference to session + Corrected sample code char (sfdumi) -* `#6130 `_ [Security][Guard] Completed start method signature (jeremyFreeAgent) -* `#6080 `_ Removed doc about getting original parameter value from ParameterBag (edefimov) -* `#6158 `_ Update override_dir_structure.rst (denniskoenigComparon) -* `#6122 `_ Added missing mandatory parameter (yceruto) -* `#6108 `_ [Form] remove the getName() function as it is deprecated (aybbou) -* `#6100 `_ [Cookbook][Security] add back updateUserSecurityIdentity() hint (xabbuh) -* `#6129 `_ Added new links to the Symfony screencast series at KnpU (javiereguiluz) -* `#6138 `_ Correction needed (pfleu) -* `#6139 `_ Update the doc to change a deprecated use case (ChristopheBoucaut) -* `#6133 `_ fixed the component name (fabpot) -* `#6127 `_ escape namespace backslashes in class role (xabbuh) -* `#5818 `_ document old way of checking validity of CSRF token (snoek09) -* `#6062 `_ Update HTTP method requirement example (WouterJ) -* `#6120 `_ fix README requirements link (garak) -* `#6109 `_ add link to Monolog configuration (snoek09) -* `#6121 `_ [MicroKernel] Fixed the display of a code block (jeremyFreeAgent) -* `#6096 `_ [Contributing] update year in license (xabbuh) -* `#6114 `_ make method protected (OskarStark) -* `#6111 `_ Fixed a typo in the choice_label code example (ferdynator) -* `#6110 `_ [Security][Guard] Fixed a typo (jeremyFreeAgent) -* `#6105 `_ Removed deprecated methods from VoterInterface (edefimov) -* `#6106 `_ Remove repetition in text (dominikhajduk) -* `#6102 `_ promoted xabbuh as merger on the Yaml component (fabpot) -* `#6014 `_ [2.8][Form] entry_type option: replace "in favor" misuses (ogizanagi) -* `#6013 `_ [2.7][Form] placeholder option: replace "in favor" misuses (ogizanagi) - - -December, 2015 --------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#5906 `_ Added documentation for choice_translation_domain option (peterrehm) -* `#6017 `_ Documented the Symfony Console Styles (javiereguiluz) -* `#5811 `_ Conversion from mysql to PDO (iqbalmalik89) -* `#5966 `_ Remove deprecated StringUtils from WSSE custom auth provider (pimpreneil) -* `#5962 `_ Simplify code example in "Adding custom extensions" section (snoek09) -* `#5977 `_ RequestStack parameter is required since 3.0 (leunggamciu) -* `#6022 `_ clarify custom route loader documentation (dbu) -* `#5994 `_ Updated the release process for Symfony 3.x and future releases (javiereguiluz) -* `#5954 `_ Fix #5236 [2.8][Translation] specify additional translation loading paths (Pierre Maraitre, Balamung) -* `#5948 `_ Update 3.0 docs accordingly to min PHP version requirement (ogizanagi) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#6086 `_ Update form_customization.rst (vudaltsov) -* `#6063 `_ minor #5829 Fix broken composer command (JHGitty) -* `#5904 `_ Update php_soap_extension.rst (xDaizu) -* `#5819 `_ Remove AppBundle (roukmoute) -* `#6001 `_ Fix class name (BlueM) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#6043 `_ Mention commiting only bower.json (krike, WouterJ) -* `#5848 `_ Added hints to spool config section (martinczerwi) -* `#5586 `_ [2.8] Remove 2.6 versionaddeds as version reached eom (WouterJ) -* `#6042 `_ some tweaks to unit testing form types (xabbuh) -* `#6059 `_ Add best practice about the Form type namespace (WouterJ) -* `#6068 `_ Remove references to API tagging (dunglas) -* `#6088 `_ Update validation.rst (syedi) -* `#6085 `_ Update validation.rst (syedi) -* `#6094 `_ [Form] Added a missing php opening tag (dev-symfony-void) -* `#5840 `_ [Contributing] [Standards] Add note about ``trigger_error()`` and deprecation messages (phansys) -* `#6050 `_ Lots of minor fixes & applying best practices to form cookbook doc (ThomasLandauer, WouterJ) -* `#5993 `_ [Cookbook] [Security] Use UserLoaderInterface instead of UserProviderInterface (ogizanagi) -* `#6071 `_ Fix syntax (WouterJ) -* `#5570 `_ Quick review of 'create framework' tutorial (WouterJ) -* `#5445 `_ Reworded the explanation about the kernel.event_listener tag (javiereguiluz) -* `#6054 `_ Remove 2.8 branch from patch documentation (Triiistan) -* `#6057 `_ Fix PHP code for registering service (WouterJ) -* `#6066 `_ Update location of ``app/check.php`` to ``bin/symfony_requirements`` (Kevinrob) -* `#6067 `_ improve phrasing (greg0ire) -* `#6063 `_ minor #5829 Fix broken composer command (JHGitty) -* `#6041 `_ Fixed misspelling of human in glossary.rst YAML (Wasserschlange) -* `#6049 `_ Finish #5798 Add ``app_`` prefix to form type names (OskarStark, WouterJ) -* `#5829 `_ use composer command instead of editing json file (OskarStark) -* `#6046 `_ Update framework.rst (typo in sesssion) (patrick-mota) -* `#5662 `_ Fixed wrong version of symfony with composer install (Nek-) -* `#5890 `_ Updated article for modern Symfony practices and the use of bcrypt (javiereguiluz) -* `#6015 `_ [Assetic] complete XML configuration examples (xabbuh) -* `#5963 `_ Add note about 'phar extension' dependency (snoek09) -* `#6006 `_ [Book] use AppBundle examples and follow best practices (xabbuh) -* `#6016 `_ Corrected the line references for the basic controller example (theTeddyBear) -* `#5446 `_ [Contributing] [Standards] Added note about phpdoc_separation (phansys) -* `#6027 `_ Update guard-authentication.rst (rvanginneken) -* `#6025 `_ Update guard-authentication.rst (rvanginneken) -* `#6038 `_ Fix #6037 (zsturgess) -* `#5820 `_ Fixed an issue with command option shortcuts (javiereguiluz) -* `#6033 `_ Fix Typo (Shine-neko) -* `#6011 `_ Fixed formatting issues (javiereguiluz) -* `#6012 `_ Use HTTPS for downloading the Symfony Installer (javiereguiluz) -* `#6009 `_ Fix missing constant usage for generating urls (Tobion) -* `#5965 `_ Removing php opening tags (Deamon) -* `#6003 `_ #5999 fix files names (vincentaubert) -* `#6004 `_ Fix for small typo (djoos) -* `#5996 `_ Clarify example for SUBMIT form event (bkosborne) -* `#6000 `_ Update registration_form.rst (afurculita) -* `#5989 `_ Fix words according context (richardpq) -* `#5992 `_ More use single quotes for YAML strings (snoek09) -* `#5957 `_ mark deep option as deprecated (snoek09) -* `#5940 `_ [Cookbook][ServiceContainer] move filename comment to the top of the code block (xabbuh) -* `#5943 `_ Add tip for when returning ``null`` from ``createToken()`` (jeroenseegers) -* `#5956 `_ Update security.rst (mpaquet) -* `#5959 `_ Fix #5912 Ambiguity on Access Decision Manager's Strategy (Pierre Maraitre) -* `#5955 `_ use single quotes for YAML strings (snoek09) -* `#5979 `_ [Book] Do not extend the base controller before introducing it (ogizanagi) -* `#5970 `_ Remove isSubmitted call (DanielSiepmann) -* `#5972 `_ Add isSubmitted call (DanielSiepmann) -* `#5964 `_ Missing n in Column (joshuataylor) -* `#5961 `_ update from_flat_php_to_symfony2.rst (thao-witkam) -* `#5924 `_ Removed note about removed content (WouterJ) -* `#5938 `_ Add proper use of the password type (themccallister) - - -November, 2015 --------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#5917 `_ [3.0][Cookbook] Use the 3.0 directory structure (WouterJ) -* `#5916 `_ [3.0][Best Practices][Quick Tour] Use the 3.0 directory structure (WouterJ) -* `#5913 `_ [3.0][Book] Use the 3.0 directory structure (WouterJ) -* `#5907 `_ Updating some places to use the new CustomUserMessageAuthenticationException (weaverryan) -* `#5922 `_ Added minimal cookbook article about the shared flag (WouterJ) -* `#5908 `_ Voter update (weaverryan) -* `#5909 `_ More 2.8 form updates (weaverryan) -* `#5927 `_ Use path() and url() PHP templating helpers (WouterJ) -* `#5926 `_ Update voter section of best practices (WouterJ) -* `#5921 `_ [2.8] Document some Security changes (WouterJ) -* `#5834 `_ Updated form aliases to FQCNs for forms in book and component (hiddewie) -* `#5265 `_ Documentation for the new Guard authentication style (weaverryan) -* `#5899 `_ Adding the MicroKernel article (weaverryan) -* `#5893 `_ Added a note about the use of _format query parameter (javiereguiluz) -* `#5891 `_ Removed the comments about the is_granted() issues in non-secure pages (javiereguiluz) -* `#5876 `_ Symfony 2.7 Form choice option update (aivus, althaus, weaverryan) -* `#5861 `_ Updated Table Console helper for spanning cols and rows (hiddewie) -* `#5835 `_ Updated CssSelector code example to use the new Converter (hiddewie) -* `#5816 `_ Merge branches (nicolas-grekas, snoek09, WouterJ, xabbuh) -* `#5804 `_ Added documentation for dnsMessage option (BenjaminPaap) -* `#5774 `_ Show a more real example in data collectors doc (WouterJ) -* `#5735 `_ [Contributing][Code] do not distinguish regular classes and API classes (xabbuh) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#5903 `_ Update front controller (nurolopher) -* `#5768 `_ Removed "http_basic" config from the login form cookbook (javiereguiluz) -* `#5863 `_ Correct useAttributeAsKey usage (danrot) -* `#5833 `_ Fixed whitelist delivery of swiftmailer (hiddewie) -* `#5815 `_ fix constraint names (xabbuh) -* `#5793 `_ Callback Validation Constraint: Remove reference to deprecated option (ceithir) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#5931 `_ [#5875] Fixed link description, list of common media types (Douglas Naphas) -* `#5923 `_ Remove information about request service deps of core services (WouterJ) -* `#5911 `_ Wrap all strings containing @ in quotes in Yaml (WouterJ) -* `#5889 `_ Always use "main" as the default firewall name (to match Symfony Standard Edition) (javiereguiluz) -* `#5888 `_ Removed the use of ContainerAware class (javiereguiluz) -* `#5625 `_ Tell about SYMFONY__TEMPLATING__HELPER__CODE__FILE_LINK_FORMAT (nicolas-grekas) -* `#5896 `_ [Book][Templating] Update absolute URL asset to match 2.7 (lemoinem) -* `#5828 `_ move the getEntityManager, only get it if needed (OskarStark) -* `#5900 `_ Added new security advisories to the docs (fabpot) -* `#5897 `_ Fixed some wrong line number references in doctrine.rst (DigNative) -* `#5895 `_ Update debug_formatter.rst (strannik-06) -* `#5883 `_ Book: Update Service Container Documentation (zanderbaldwin) -* `#5868 `_ [2.8] Make screenshots with the new profiler/web dev toolbar design (WouterJ) -* `#5862 `_ Fixes done automatically by the docbot (WouterJ) -* `#5851 `_ updated sentence (OskarStark) -* `#5870 `_ Update securing_services.rst (aruku) -* `#5859 `_ Use Twig highlighter instead of Jinja (WouterJ) -* `#5866 `_ Fixed little typo with a twig example (artf) -* `#5849 `_ Clarified ambiguous wording (ThomasLandauer) -* `#5826 `_ "setup" is a noun or adjective, "set up" is the verb (carlos-granados) -* `#5816 `_ Merge branches (nicolas-grekas, snoek09, WouterJ, xabbuh) -* `#5813 `_ use constants to choose generated URL type (xabbuh) -* `#5808 `_ Reworded the explanation about flash messages (javiereguiluz) -* `#5809 `_ Minor fix (javiereguiluz) -* `#5807 `_ Minor rewordings for the "deprecated" service option (javiereguiluz) -* `#5805 `_ Mentioned the BETA and RC support for the Symfony Installer (javiereguiluz) -* `#5781 `_ Added annotations example to Linking to Pages examples (carlos-granados) -* `#5780 `_ Clarify when we are talking about PHP and Twig (carlos-granados) -* `#5767 `_ [Cookbook][Security] clarify description of the getPosition() method (xabbuh) -* `#5731 `_ [Cookbook][Security] update versionadded directive to match the content (xabbuh) -* `#5681 `_ Update storage.rst (jls2933) -* `#5363 `_ Added description on how to enable the security:check command through… (bizmate) -* `#5841 `_ [Cookbook][Psr7] fix zend-diactoros Packagist link (xabbuh) -* `#5850 `_ Fixed typo (tobiassjosten) -* `#5852 `_ Fix doc for 2.6+, `server:start` replace `...:run` (Kevinrob) -* `#5837 `_ Corrected link to ConEmu (dritter) - - -October, 2015 -------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#5345 `_ Adding information about empty files sent using BinaryFileResponse. (kherge) -* `#5214 `_ [WIP] Reworking most of the registration form: (weaverryan) -* `#5051 `_ Rename CollectionType entry options (WouterJ) -* `#5677 `_ replacing deprecated usage of True, False, Null validators in docs (Tim Stamp) -* `#5314 `_ Documented the useAttributeAsKey() method (javiereguiluz) -* `#5377 `_ Added a cookbook section about event subscribers (beni0888, javiereguiluz) -* `#5623 `_ [Validator] added BIC validator (mvhirsch) -* `#5689 `_ [DI] Add some documentation for the deprecation feature (Taluu) -* `#5592 `_ Updated the article about data collectors (javiereguiluz) -* `#5745 `_ [Translation] Ability to format a message catalogue without actually writing it. (aitboudad) -* `#5702 `_ Added a reference to the Foundation form theme (totophe) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#5795 `_ Fix typo in UserType class (Dorozhko-Anton) -* `#5758 `_ symlink issues with php-fpm (kendrick-k) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#5843 `_ Fixed the YAML syntax for service references (javiereguiluz) -* `#5797 `_ [Process] use ProcessFailedException instead of RuntimeException. (aitboudad) -* `#5812 `_ Remove duplicate and confusing info about testing error pages (carlos-granados) -* `#5821 `_ Minor fixes in the HttpFoundation introduction article (javiereguiluz) -* `#5822 `_ Fixed a syntax issue (javiereguiluz) -* `#5817 `_ fix version for `entry_options` and `entry_type` (craue) -* `#5796 `_ Fix for #5783 (BenjaminPaap) -* `#5810 `_ Fixed a typo (javiereguiluz) -* `#5784 `_ Add fe80::1 (j-d) -* `#5799 `_ make file path consitent with other articles (OskarStark) -* `#5794 `_ Minor tweaks for the registration form article (javiereguiluz) -* `#5801 `_ namespace fix (OskarStark) -* `#5792 `_ [Cookbook][EventDispatcher] fix build (xabbuh) -* `#5787 `_ Definition Tweaks - see #5314 (weaverryan) -* `#5777 `_ Update links (thewilkybarkid) -* `#5775 `_ Misspelling (carlos-granados) -* `#5664 `_ Info about implicit session start (ThomasLandauer) -* `#5744 `_ translations have been removed from symfony.com (xabbuh) -* `#5771 `_ Remove not existing response constant (amansilla) -* `#5761 `_ [DX] [Security] Renamed key to secret (SongoQ) -* `#5766 `_ Fixed two typos (ThomasLandauer) -* `#5733 `_ [Components][OptionsResolver] adding type hint to normalizer callback (xabbuh) -* `#5561 `_ Change default value of cookie_httponly (jderusse) -* `#5678 `_ Update HttpFoundation note after recent changes in routing component (senkal) -* `#5643 `_ Document how to customize the prototype (daFish, WouterJ) -* `#5584 `_ Add DebugBundle config reference (WouterJ) -* `#5753 `_ configureOptions(...) : protected => public (lucascherifi) -* `#5750 `_ fix YAML syntax highlighting (xabbuh) -* `#5749 `_ complete Swiftmailer XML examples (xabbuh) -* `#5730 `_ Remove documentation of deprecated console shell (Tobion) -* `#5726 `_ Document the support of Mintty for colors (stof) -* `#5708 `_ Added caution to call createView after handleRequest (WouterJ) -* `#5640 `_ Update controller.rst clarifying automatic deletion for flash messages (miguelvilata) -* `#5578 `_ Add supported branches in platform.sh section (WouterJ) -* `#5468 `_ [Cookbook][Templating] Add note about cache warming namespaced twig templates (kbond) -* `#5684 `_ Fix delivery_whitelist regex (gonzalovilaseca) -* `#5742 `_ incorrect: severity is an array key here and not a constant (lbayerl) - - -September, 2015 ---------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#5555 `_ added result yaml and xml from example code (OskarStark) -* `#5631 `_ Updated the Quick Tour to the latest changes introduced by Symfony (javiereguiluz) -* `#5497 `_ Simplified the Quick tour explanation about Symfony Installation (DQNEO) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#5629 `_ Fixing web user permission (BenoitLeveque) -* `#5673 `_ Update http_cache.rst (szyszka90) -* `#5666 `_ Fix EntityManager namespace (JhonnyL) -* `#5656 `_ Fix monolog line formatter in logging cookbook example. (vmarquez) -* `#5507 `_ Path fixed (carlosreig) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#5740 `_ Fix typo in PdoSessionHandler Documentation (tobemedia) -* `#5719 `_ changed repo names to the new ones (fabpot) -* `#5227 `_ [Cookbook] Fix doc on Generic Form Type Extensions (lemoinem) -* `#5703 `_ comment old logic (OskarStark) -* `#5683 `_ Improve the demo-warning. (GuGuss) -* `#5690 `_ Updated the release process image (javiereguiluz) -* `#5188 `_ Updated Cookies & Caching section (lukey78) -* `#5710 `_ Fix grammar mistake in security.rst (zatikbalazs) -* `#5706 `_ Update assetic.rst (Acinonux) -* `#5705 `_ Update assetic.rst (Acinonux) -* `#5685 `_ Fix indentation in some annotations (iamdto) -* `#5704 `_ Fix typo in translation.rst (zatikbalazs) -* `#5701 `_ Update testing.rst (hansallis) -* `#5711 `_ removed service call from controller (sloba88) -* `#5692 `_ Made a sentence slightly more english (GTheron) -* `#5715 `_ Add missing code tag (zatikbalazs) -* `#5720 `_ adding closing tag (InfoTracer) -* `#5714 `_ Remove unnecessary word from http_cache.rst (zatikbalazs) -* `#5680 `_ fix grammar mistake (greg0ire) -* `#5682 `_ Fix grammar and CS (iamdto) -* `#5652 `_ Do not use dynamic REQUEST_URI from $_SERVER as base url (senkal) -* `#5654 `_ Doc about new way of running tests (nicolas-grekas) -* `#5598 `_ [Cookbook][Security] proofread comments in voter article (xabbuh) -* `#5560 `_ [2.3] [Contributing] [CS] Added missing docblocks in code snippet (phansys) -* `#5674 `_ Update cookbook entries with best practices (JhonnyL) -* `#5675 `_ [Contributing] add a link to the testing section (xabbuh) -* `#5669 `_ Better explanation of implicit exception response status code (hvt) -* `#5651 `_ [Reference][Constraints] follow best practices in the constraints reference (xabbuh) -* `#5648 `_ Minor fixes for the QuestionHelper documentation (javiereguiluz) -* `#5641 `_ Move important information out of versionadded (WouterJ) -* `#5619 `_ Remove a caution note about StringUtils::equals() which is no longer true (javiereguiluz) -* `#5571 `_ Some small fixes for upload files article (WouterJ) -* `#5660 `_ Improved "Community Reviews" page (webmozart) - - -August, 2015 ------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#5480 `_ Added page "Community Reviews" (webmozart) -* `#5595 `_ Improve humanize filter documentation (bocharsky-bw) -* `#5319 `_ [Console] Command Lifecycle explications (94noni) -* `#5394 `_ Fix Major upgrade article for 2.7.1 changes (WouterJ) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#5589 `_ [Cookbook][Session] fix default expiry field name (xabbuh) -* `#5607 `_ Fix (sebastianbergmann) -* `#5608 `_ updated validation.rst (issei-m) -* `#5449 `_ Ensure that the entity is updated. (yceruto) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#5553 `_ Fix all broken links/permanent redirects/removed anchors (WouterJ) -* `#5650 `_ [RFR] fixing typo and removing duplicated lines in Config component doc (salahm) -* `#5635 `_ Fix minor problems in book/page_creation.rst (fabschurt) -* `#5579 `_ [3.0] Remove mentions of Symfony1 (WouterJ) -* `#5647 `_ don't ignore the _exts directory anymore (xabbuh) -* `#5587 `_ [2.6] Don't use deprecated features (WouterJ) -* `#5637 `_ Add QueryBuilder vs DQL section (bocharsky-bw) -* `#5645 `_ Updated Constraint reference with best practices (WouterJ) -* `#5646 `_ Moved comment to the right place (mickaelandrieu) -* `#5649 `_ [RFR] Fixing typo in Symfony version for ButtonType (salahm) -* `#5606 `_ Use symfony.com theme on Platform.sh builds (WouterJ) -* `#5644 `_ Update page_creation.rst (jeromenadaud) -* `#5593 `_ Updated the profiler matchers article (javiereguiluz) -* `#5522 `_ [create_framework] Add missing extract() 2nd arg (kenjis) -* `#5597 `_ [CreateFramework] don't override existing variables (xabbuh) -* `#5628 `_ Updated the installation chapter (javiereguiluz) -* `#5638 `_ Update page_creation.rst (jeromenadaud) -* `#5636 `_ Fixed typo in web-assets.rst (nielsvermaut) -* `#5633 `_ Upgrade Platform.sh configuration snippet. (GuGuss) -* `#5620 `_ Changed the recommendation about the LICENSE file for third-party bundles (javiereguiluz) -* `#5617 `_ Add Body tag to see the web debug toolbar (rmed19) -* `#5594 `_ Missing --no-interaction flag? (alexwybraniec) -* `#5613 `_ Remove unneeded backtick (fabschurt) -* `#5622 `_ typo fix in pre authenticated (Maxime Douailin) -* `#5624 `_ the_architecture: Fix syntax error (kainjow) -* `#5609 `_ Add a missing backtick (fabschurt) -* `#5312 `_ Some fixes for bundle best practices (WouterJ) -* `#5601 `_ Update lazy_services.rst (baziak3) -* `#5591 `_ Update templating.rst: lint:twig instead of twig:lint in 2.7 (alexwybraniec) - - -July, 2015 ----------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#5374 `_ Remove deprecated parameters (norkunas) -* `#5533 `_ Replace Capifony with Capistrano/symfony (mojzis) -* `#5543 `_ Add deprecation notice to "choice_list" option of ChoiceType (XitasoChris) -* `#5521 `_ [Cookbook][WebServer] #5504 add a tip for the --force option (vincentaubert) -* `#5516 `_ Added a note about session data size in PdoSessionHandler (javiereguiluz) -* `#5499 `_ The "property" option of DoctrineType was deprecated. (XWB) -* `#5491 `_ added composer info (OskarStark) -* `#5478 `_ Add cookbook article for using MongoDB to store session data (stevenmusumeche) -* `#5472 `_ Added a tip about hashing the result of nextBytes() (javiereguiluz) -* `#5458 `_ HTML5 range documentation (harikt) -* `#5453 `_ Cleanup security voters cookbook recipes (WouterJ) -* `#5444 `_ Documented the "auto_alias" feature (javiereguiluz) -* `#5201 `_ [Book][Routing] Add example about how to match multiple methods (xelaris) -* `#5430 `_ Pr/5085 (sjagr, javiereguiluz) -* `#5456 `_ Completely re-reading the data transformers chapter (weaverryan) -* `#5426 `_ Documented the checkDNS option of the Url validator (saro0h, javiereguiluz) -* `#5333 `_ [FrameworkBundle] Update serializer configuration reference (dunglas) -* `#5424 `_ Integrate the "Create your own framework" tutorial (fabpot, lyrixx, jdreesen, catchamonkey, gnugat, andreia, Arnaud Kleinpeter, willdurand, amitayh, nanocom, hrbonz, Pedro Gimenez, ubick, dirkaholic, bamarni, revollat, javiereguiluz) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#5567 `_ Change Sql Field name because it's reserved (rmed19) -* `#5528 `_ [reate_framework] Fix mock $matcher (kenjis) -* `#5501 `_ Fix typo in url for PHPUnit test coverage report (TrueGit) -* `#5501 `_ Fix typo in url for PHPUnit test coverage report (TrueGit) -* `#5461 `_ Rework quick tour big picture (smatejic, DQNEO, xabbuh) -* `#5488 `_ fix #5487 (emillosanti) -* `#5496 `_ Security voters fixes (german.bortoli) -* `#5424 `_ Integrate the "Create your own framework" tutorial (fabpot, lyrixx, jdreesen, catchamonkey, gnugat, andreia, Arnaud Kleinpeter, willdurand, amitayh, nanocom, hrbonz, Pedro Gimenez, ubick, dirkaholic, bamarni, revollat, javiereguiluz) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#5575 `_ Move some articles from wrong sections (sylvaincombes, WouterJ) -* `#5580 `_ Additional User check in voter class (weaverryan) -* `#5573 `_ fix YAML syntax highlighting (xabbuh) -* `#5564 `_ Improve and simplify the contributing instructions about tests (javiereguiluz) -* `#5498 `_ [WIP] Added caution notes about the deprecation of container scopes (javiereguiluz) -* `#5550 `_ [docbot] Reviewed some component chapters (WouterJ) -* `#5556 `_ Fix typo Esi in part create framework (nicolasdewez) -* `#5568 `_ [Create Framework] Fix extract calls (replaces #5522) (kenjis) -* `#5548 `_ use the include() Twig function instead of the tag (xabbuh) -* `#5542 `_ [Cookbook][Email] add missing versionadded directive (xabbuh) -* `#5476 `_ [Cookbook][Security] some additional tweaks for the voter cookbook (xabbuh) -* `#5413 `_ Fix doc about deprecations policy (nicolas-grekas) -* `#5557 `_ [2.3] [Contributing] Added note about empty returns (phansys) -* `#5492 `_ updated tree for front controller (OskarStark) -* `#5536 `_ Removed reference to remove HTTPS off from nginx configuration (wjzijderveld) -* `#5545 `_ Misc. improvements in the Console component introduction (javiereguiluz) -* `#5512 `_ [Cookbook] Backport PSR-7 bridge docs to 2.3 (dunglas, weaverryan) -* `#5494 `_ updated tree (OskarStark) -* `#5490 `_ changed headline (OskarStark) -* `#5479 `_ Update http-foundation.rst (jezemery) -* `#5552 `_ rename $input to $greetInput (Xosofox) -* `#5544 `_ [components][expression_language] Fix the wrong constructor for SerializedParsedExpression (zerustech) -* `#5537 `_ Update design patter of Event Dispatcher (almacbe) -* `#5546 `_ A bunch of doc fixes again (WouterJ) -* `#5486 `_ review all Security code blocks (xabbuh) -* `#5538 `_ Update email.rst (TisLars) -* `#5529 `_ [Cookbook][upload_file] Fix :methods: to remove doubled braces (bicpi) -* `#5455 `_ Improve travis build speed (WouterJ) -* `#5442 `_ Improved the explanation about the verbosity levels of the console (javiereguiluz) -* `#5523 `_ Custom voter example, fix missing curly brace (snroki) -* `#5524 `_ TYPO: missing closing parantheses of the array (listerical85) -* `#5519 `_ Prepare Platform.sh configuration files. (GuGuss) -* `#5443 `_ Added a note about the implementation of the verbosity semantic methods (javiereguiluz) -* `#5518 `_ Minor grammar fix. (maxolasersquad) -* `#5520 `_ Fix RST (kenjis) -* `#5429 `_ Promote Symfony's builtin serializer instead of JMS (javiereguiluz) -* `#5427 `_ Cookbook grammar and style fixes (frne, javiereguiluz) -* `#5505 `_ [Cookbook][Form] some tweaks to the data transformers chapter (xabbuh) -* `#5352 `_ Update http_fundamentals.rst (wouthoekstra) -* `#5471 `_ Updated the Symfony Versions Roadmap image (javiereguiluz) -* `#5511 `_ [HttpKernel] Fix use statement (dunglas) -* `#5510 `_ [PSR-7] Fix Diactoros link (dunglas) -* `#5506 `_ Fixes small typo in data transformers cookbook (catchamonkey) -* `#5425 `_ Added a caution note about invoking other commands (kix, javiereguiluz) -* `#5367 `_ Split Security into Authentication & Authorization (iltar) -* `#5485 `_ Fix invalid phpunit URLs (norkunas) -* `#5473 `_ --dev is default and causes a warning (DQNEO) -* `#5474 `_ typo in components/translation/instruction.rst (beesofts) - - -June, 2015 ----------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#5423 `_ [Security] add & update doc entries on AbstractVoter implementation (Inoryy, javiereguiluz) -* `#5409 `_ [Reference] document new Doctrine APC cache service (xabbuh) -* `#5401 `_ Added some more docs about the remember me feature (WouterJ) -* `#5384 `_ Added information about the new date handling in the comparison constraints and Range (webmozart, javiereguiluz) -* `#5382 `_ Added support for standard Forwarded header (tony-co, javiereguiluz) -* `#5361 `_ Document security.switch_user event (Rvanlaak) -* `#5332 `_ [Serializer] ObjectNormalizer, object_to_populate doc. Minor enhancements. (dunglas) -* `#5335 `_ [Serializer] Updated the cookbook. (dunglas) -* `#5313 `_ Documented the overridden form options (javiereguiluz) -* `#5360 `_ [Serializer] Array Denormalization (derrabus) -* `#5307 `_ Update data_transformers.rst (zebba) -* `#5186 `_ Added a new article about using/installing unstable Symfony versions (javiereguiluz) -* `#5166 `_ Proposed a new article about using pure PHP libraries with Assetic (javiereguiluz) -* `#5416 `_ fix for Symfony 2.7 (DQNEO) -* `#5014 `_ Updated the best practices article for reusable bundles (javiereguiluz) -* `#5435 `_ Added information about the four sub-components of Security component (javiereguiluz) -* `#5368 `_ added examples for squashing (OskarStark) -* `#5428 `_ Improved description of choice_list option (adamziel, javiereguiluz) -* `#5336 `_ Adding a paragraph about updating multiple packages during an update (weaverryan) -* `#5375 `_ Added a new cookbook about file uploading (javiereguiluz) -* `#5385 `_ Added a note about the need to require Composer's autoload file (javiereguiluz) -* `#5386 `_ Re-write of Page Creation (weaverryan) -* `#5355 `_ Added a mention to the Symfony Demo application (javiereguiluz) -* `#5331 `_ [PSR-7] Bridge documentation (dunglas) -* `#5373 `_ Added mentions to some popular (and useful) Symfony bundles (javiereguiluz) -* `#4354 `_ [WCM] Added depreciation note for the cascade_validation constraint (peterrehm) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#5415 `_ Updating for AppBundle and purposefully \*not\* doing work on configure (weaverryan) -* `#5407 `_ Change PhpStormOpener to PhpStormProtocol (King2500) -* `#5450 `_ Fixing "Undefined method" error in code example (nebkam) -* `#5454 `_ Changed dump() to var_dump() (WouterJ) -* `#5417 `_ Add use statement for InputDefinition (harikt) -* `#5420 `_ Fix invalid method name (bocharsky-bw) -* `#5431 `_ Updated the code to display flash messages (aykin, javiereguiluz) -* `#5418 `_ Import Psr LogLevel (harikt) -* `#5438 `_ Fixed 404 at Configuring Sessions and Save Handlers (2.3 branch) (suzuki) -* `#5412 `_ Update serializer.rst (mantulo) -* `#5397 `_ Escape backslash in error message (WouterJ) -* `#5379 `_ [Cookbook][Console] don't use BufferedOutput on Symfony 2.3 (xabbuh) -* `#5400 `_ Fix after install URL and new photo since AcmeDemoBundle is not part … (smatejic) -* `#5350 `_ [Form][2.3] fix `validation_groups` typos (craue) -* `#5358 `_ Fix typo in description (martyshka) -* `#5356 `_ [Form] Fixed typo about _token field name for CSRF protection (JMLamodiere) -* `#5362 `_ Fix invalid endtag (norkunas) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#5467 `_ use HTTPS for links to symfony.com (xabbuh) -* `#5466 `_ data transformers cookbook service definition typo (intrepion) -* `#5414 `_ Rewrite sentence about fingers crossed handler action level (snoek09) -* `#5402 `_ [Contributing] [Standards] Added entry for Yoda conditions (phansys) -* `#5369 `_ Remove the Propel book chapter and explain why we do that (javiereguiluz) -* `#5460 `_ Finish #5291: Bootstrap form theme and checkboxes (anacicconi, WouterJ) -* `#5457 `_ [Cookbook][Assetic] complete a sentence (xabbuh) -* `#5398 `_ Quick review of the remember me article (WouterJ) -* `#5399 `_ Quick review of Form login chapter (WouterJ) -* `#5403 `_ [Contributing] [Standards] Added entry for identical comparison (phansys) -* `#5392 `_ Wrap the table creation inside the class extending Command, so users … (harikt) -* `#5378 `_ [Cookbook][Controller] use the jinja lexer to render Twig code (xabbuh) -* `#5421 `_ Update the name of the branch for new BC features (Restless-ET) -* `#5441 `_ [Contributing] remove mailing list and forum references (xabbuh) -* `#5433 `_ Warn users of older PHP versions Crawler might not decode HTML entities properly (jakzal, javiereguiluz) -* `#5293 `_ [Translation] Add note about how to override translation in chi… (zebba) -* `#5290 `_ Overriding 3rd party bundles (anacicconi) -* `#5242 `_ Update load_balancer_reverse_proxy.rst (urg) -* `#5381 `_ remove Yoda condition (greg0ire) -* `#5452 `_ [#5388] change echo and print in examples (snoek09) -* `#5451 `_ [#5388] change echo and print in examples (snoek09) -* `#3782 `_ [Form] Deprecate read_only option (snoob) -* `#5432 `_ removed squashing stuff. fixes #5368 (OskarStark) -* `#5383 `_ Reword a paragraph about service configurations (richardudovich) -* `#5389 `_ Updates to security.rst (HexTitan) -* `#5408 `_ typo (larsborn) -* `#5406 `_ Update yaml_format.rst (marcel-burkhard) -* `#5396 `_ [Cookbook][Bundles] fix a typo (xabbuh) -* `#5288 `_ Constraints - empty strings and null values (anacicconi) -* `#5284 `_ Split advanced container configuration article (WouterJ) -* `#5342 `_ [Cookbook][Bundles] clarify bundle installation instructions (xabbuh) -* `#5321 `_ Use the reserved domains example.com and example.org (javiereguiluz) -* `#5095 `_ Reviewed the Bundles cookbook articles (javiereguiluz) -* `#4947 `_ [Components][ClassLoader] remove DebugClassLoader (xabbuh) -* `#5365 `_ Finish #4967: Code style standardization on form type options (mimol91) -* `#5034 `_ Update the_big_picture.rst (oldskool) -* `#5351 `_ [Finder] minor CS fix (dunglas) -* `#5344 `_ [Book] Finish #4776 and #4782 (ifdattic) -* `#5348 `_ Fix list format (bicpi) -* `#5357 `_ [Form] Replace deprecated form_enctype by form_start (JMLamodiere) -* `#5359 `_ Bumped version of proxy manager to stable release (peterrehm) - - -May, 2015 ---------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -* `#5329 `_ Adding a new entry about deprecation warnings (weaverryan) -* `#4604 `_ Making the channel handler more useful by showing it on the prod environment (weaverryan) -* `#5155 `_ Documented upgrading path for a major version (WouterJ) -* `#5127 `_ [VarDumper] Add doc for assertDump\* assertions (nicolas-grekas) -* `#5137 `_ Added a note about the rotating_file monolog handler (javiereguiluz) -* `#5283 `_ [BestPractices] restructured text format for the installation instructions template (xabbuh) -* `#5298 `_ Completed framework config (WouterJ) -* `#5255 `_ [Cookbook] Use configured user provider instead of injection (mvar) -* `#5216 `_ [Cookbook] [Deployment] Added note about Nginx (phansys) -* `#5169 `_ Removed synchronized services from Symfony 2.7 docs (javiereguiluz) -* `#5117 `_ Complete review of the "Customize Error Pages" cookbook article (javiereguiluz) -* `#5115 `_ Flesh out twig-template for custom data-collector (Darien Hager) -* `#5106 `_ [VarDumper] upgrade doc to 2.7 wither interface (nicolas-grekas) -* `#4728 `_ Add Session Cache Limiting section for NativeSessionStorage (mrclay) -* `#4084 `_ [Book][Forms] describe the allow_extra_fields form option (xabbuh) -* `#5294 `_ Tweaks to bower entry - specifically committing deps (weaverryan) -* `#5062 `_ Cookbook about Command in Application with AnsiToHtml (Rvanlaak) -* `#4901 `_ Removed the Internals chapter from the Symfony book (javiereguiluz) -* `#4807 `_ [2.7] bumped min PHP version to 5.3.9 (xelaris) -* `#4790 `_ [Cookbook][Routing] Update custom_route_loader.rst (xelaris) -* `#5159 `_ Added an article explaining how to use Bower in Symfony (WouterJ) -* `#4700 `_ add informations how to create a custom doctrine mapping (timglabisch) -* `#4675 `_ [Serializer] Doc for groups support (dunglas) -* `#5164 `_ Added information about the Symfony Demo application (javiereguiluz) -* `#5100 `_ Change MySQL UTF-8 examples to use utf8mb4 (DHager, Darien Hager) -* `#5088 `_ [Cookbook] Custom compile steps on Heroku (bicpi) -* `#5005 `_ Renamed precision option to scale (WouterJ) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -* `#5324 `_ 5259 improve 'Testing Documentation' in contributing guide (snoek09) -* `#5328 `_ Update create_form_type_extension.rst (jackdelin) -* `#5305 `_ [BestPractices][Security] revert #5271 on the 2.6 branch (xabbuh) -* `#5251 `_ [Cookbook][Controller] replace docs for removed `forward()` method (xabbuh) -* `#5237 `_ Update authentication.rst (taavit) -* `#5299 `_ Command controller tweaks to #5062 (weaverryan) -* `#5297 `_ Kernel Events Proofreading after #4901 (weaverryan) -* `#5296 `_ Fix link to Zend Soap (peterkokot) -* `#5266 `_ Update heroku.rst (nickbyfleet) -* `#5270 `_ Use OptionsResolver (tacman) -* `#5271 `_ Fix nonexistent controller method (amansilla) -* `#4615 `_ Update NotBlank to reflect the actual validation (DRvanR) -* `#5249 `_ [security][form login] fix translations for the security messages. (aitboudad) -* `#5247 `_ [2.7] [Serializer] fixes the order of the Serializer constructor arguments. (hhamon) -* `#5220 `_ Fix example namespace (lepiaf) -* `#5203 `_ Order has one param without spaces (carlosbuenosvinos) -* `#4273 `_ - fix doctrine version in How to Provide Model Classes for several Doctrine Implementations cookbook - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* `#5343 `_ [Reference][Forms] reorder index to match the description order (xabbuh) -* `#5309 `_ [Cookbook][Controller] few tweaks to the error pages article (xabbuh) -* `#5311 `_ Moved sections to be equal to index list (WouterJ) -* `#5326 `_ Fixed code intentation (lyrixx) -* `#5327 `_ [Platform] Made things more obvious and copy/paste friendly (lyrixx) -* `#5338 `_ Text in index.html.twig for The Big Picture wrong (BT643) -* `#5341 `_ fixed typo and added additional hit for NullOutput() (kuldipem) -* `#5302 `_ Place DQL in front of QueryBuilder (alfonsomga) -* `#5276 `_ Better illustrate what the "user mistake" is. (diamondsea) -* `#5304 `_ Proofreading Javier's excellent updates - in some places, shortening some things (weaverryan) -* `#5263 `_ Let docbot review the form docs (WouterJ) -* `#5280 `_ Rebase #4633 (seangallavan) -* `#5241 `_ [Components][Form] apply some fixes to the Form events chapter (xabbuh) -* `#5233 `_ Improve Choice Validation Constraint Example (huebs) -* `#5228 `_ Clarify `query_builder` closure return type (kix) -* `#5165 `_ Minor changes to match the Symfony Demo reference application (javiereguiluz) -* `#5281 `_ store templates under app/Resources/views (xabbuh) -* `#5267 `_ fix infinity upper bound (xabbuh) -* `#5277 `_ always refer to getcomposer.org through HTTPS (xabbuh) -* `#4671 `_ consistent spelling (xabbuh) -* `#4255 `_ Updated autoload standard to PSR-4. (phansys) -* `#5278 `_ remove unnecessary code (karion) -* `#5262 `_ Update Routes in the Getting Started documentation (BT643) -* `#5178 `_ Usage of denyAccessUnlessGranted in the controller (94noni) -* `#5229 `_ Remove mention of \*.class parameters from conventions (jvasseur) -* `#5250 `_ [Cookbook][Logging] use straightforward instead of straigt forward (xabbuh) -* `#5257 `_ Let docbot review the constraint docs (WouterJ) -* `#5222 `_ Update service_container.rst (assoum891) -* `#5221 `_ Update Uglifyjs.rst (assoum891) -* `#5219 `_ Fix contradicting merging policy rules (lscholten) -* `#5217 `_ Update _payload-option.rst.inc (bvleur) -* `#5226 `_ Update http_cache.rst (assoum891) -* `#5238 `_ Fixed typo and removed outdated imports (nomack84) -* `#5240 `_ [Cookbook][Email] revert #4808 (xabbuh) - - -April, 2015 ------------ - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `387ebc0 `_ #5109 Improved the explanation about the "secret" configuration parameter (javiereguiluz) -- `cac0a9c `_ #5207 Updated the cookbook about Composer installation (javiereguiluz) -- `b5dd5a1 `_ #5206 [Cookbook][Security] Replace deprecated csrf_provider service (xelaris) -- `99e2034 `_ #5195 Add missing caching drivers (mhor) -- `b90c7cb `_ #5078 [Cookbook] Add warning about Composer dev deps on Heroku (bicpi) -- `55730c4 `_ #5021 Explained the "Remember Me" firewall options (javiereguiluz) -- `45ba71b `_ #4811 Simplified some Symfony installation instructions (javiereguiluz) -- `c4a5661 `_ #5060 Adds note on new validation files scanned in 2.7 (GromNaN) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `6641b4b `_ #5202 added missing tab (martinbertinat) -- `49f6b2a `_ #5211 Rebase #5182 (Balamung) -- `318bb8a `_ #5187 Fixing a bad bcrypt string using http://www.bcrypt-generator.com/ (weaverryan) -- `6fb2eea `_ #5162 Fix misplelled XliffFileLoader class in the Using Domains (Nicola Pietroluongo) -- `402b586 `_ #5162 Fix misplelled XliffFileLoader class in the Using Message Domains (Nicola Pietroluongo) -- `8fc3d6c `_ #5149 Fixed loadUserByUsername method coding errors (Linas Merkevicius) -- `2a1d2bb `_ #5153 [Book] app_dev with php built-in web server (manelselles) -- `c6e6d28 `_ #5061 Trim default is false in password field (raziel057) -- `5880f38 `_ #5126 Fix a typo in ProgressBar usage example (kamazee) -- `65c1669 `_ #5124 #3412 correct overridden option name of timezone (alexandr-kalenyuk) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `0b7f89b `_ #4868 Remove horizontal scrollbar (ifdattic) -- `c166fdf `_ #5212 Fixed typo. (pcky) -- `134268e `_ #5209 [Reference] Fix order of config blocks (xelaris) -- `c6dc4ea `_ #5200 Added missing link in "Sections" (sfdumi) -- `8b25e6e `_ #5198 Link twig constant function (davidfuhr) -- `2d6d78c `_ #5194 Fix priority range values for event listeners. (chtipepere) -- `914345a `_ #5191 Fixed inconsistency (jperovic) -- `c2d1f3d `_ #5190 Change '.xliff' extensions to '.xlf' (xelaris) -- `32b874a `_ #5189 [Quick Tour] Fixed things found by the docbot (WouterJ) -- `20ac2a6 `_ #5174 [CookBook] [configuration_organization] Use $this->getRootDir() instead of __DIR__ (manelselles) -- `eacb71b `_ #5173 Use $this->getRootDir() instead of __DIR__ (manelselles) -- `16e0849 `_ #5184 Removing a section about Roles that I think has no real use-case (weaverryan) -- `2948d6e `_ #5185 Fix broken link in security chapter (iboved) -- `a4f290e `_ #5172 [Contributing][Code] add missing security advisories (xabbuh) -- `2b7ddcd `_ #5167 Add version 2.8 to the release roadmap (Maks3w) -- `404d0b3 `_ #5161 Use correct Session namespace (JhonnyL) -- `c778178 `_ #5098 Reviewed Configuration cookbook articles (javiereguiluz) -- `d9e1690 `_ #5096 Reviewed Cache cookbook articles (javiereguiluz) -- `c40b618 `_ #5065 [Reference] fix code block order (xabbuh) -- `73ccc8b `_ #5160 Update process.rst (sfdumi) -- `ab01d08 `_ #5141 Removed remaining setDefaultOptions usage (WouterJ) -- `0dc6204 `_ #5143 Rebased #4747 (ifdattic) -- `b467e23 `_ #5147 Add missing word in bundles best practice description (jbafford) -- `bf1e44b `_ #5150 [Cookbook] Update serializer.rst (xelaris) -- `bec695a `_ #5144 [Cookbook][Deployment] fix references to Platform.sh documentation (xabbuh) -- `b73346a `_ #5145 Update introduction.rst (cafferata) -- `7f39e87 `_ #5073 [Cookbook] Add note about possible 404 error on Heroku (bicpi) -- `fbdc177 `_ #5057 Add a link to Multiple User Providers (thePanz) -- `526c880 `_ #5132 [Components][DependencyInjection] fix wrong disable of factories (sstok) -- `b19ded6 `_ #5130 [Cookbook][Security] Fiyed typo in entity_provider.rst (althaus) -- `87c39b7 `_ #5129 Fix to Twig asset function packageName argument (ockcyp) -- `1d443c0 `_ #5128 [VarDumper] little optim (lyrixx) - -March, 2015 ------------ - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `25d2f54 `_ #4958 Add Twitter Bootstrap form theme example (bocharsky-bw) -- `8ac6fed `_ #5093 Added a new best practices for custom form field types (javiereguiluz) -- `50cd620 `_ #4892 Add possible values for widget_type (XitasoChris) -- `ade7ba4 `_ #4842 Add meaning of yellow icon for number of queries (XitasoChris) -- `fa10f1c `_ #5083 Proofreading and updating entity_provider for readability (weaverryan) -- `e36faec `_ #5099 Rebase of #4989 (solazs, weaverryan) -- `65dd03b `_ #5056 [Reference] Add missing option delivery_whitelist (TerjeBr) -- `c2f21e6 `_ #5050 [OptionsResolver] Fixed deprecated functionality usage (WouterJ) -- `3405c42 `_ #5046 Rebased "add shortcut methods" (Cydonia7, WouterJ) -- `b138a50 `_ #5032 Minor improvement for symfony-installer with LTS (94noni) -- `5261e79 `_ #5033 adding table for controller as a service (dbu) -- `d6c0cb7 `_ #5028 Finish #4308: Documentation for the new PropertyNormalizer (mnapoli, WouterJ) -- `ccabc95 `_ #5023 Added a note about data transformers not being applied with inherit_data option set (javiereguiluz) -- `65a33c0 `_ #5020 Added a commented config useful when you use symlinks (javiereguiluz) -- `1dbed80 `_ #5017 Added a note about the server_version DBAL option (javiereguiluz) -- `86abdde `_ #5015 Added an example about how to get the impersonating user object (javiereguiluz) -- `c6db525 `_ #5010 Added a note about the Symfony versions affected by ICU problems (javiereguiluz) -- `3c76623 `_ #5008 Added a note about how to enable http_method_override for caching kernels (javiereguiluz) -- `22eee86 `_ #4987 Added the documentation for the new Asset component (javiereguiluz) -- `3fb19ce `_ #4959 Add excluded_ajax_paths new parameter in v2.6 (bocharsky-bw) -- `78733c3 `_ #4941 Adding a section to emailing showing off absolute_url (weaverryan) -- `325354e `_ #4903 Reworded the explanation about when a lock is released (javiereguiluz) -- `d76f046 `_ #4875 Added chapter about the locale based on the user entity (peterrehm) -- `0d1e97e `_ #4834 [translator] use the new fallbacks option. (aitboudad) -- `9846d97 `_ #5001 Best practices template names (WouterJ) -- `8e93786 `_ #4779 Update book to comply with best practices, round 3 (WouterJ) -- `dbdb408 `_ #4724 [Reference][Constraints] document the validation payload option (xabbuh) -- `f8e2e19 `_ #4692 [Serializer] Name Converter (dunglas) -- `24c4f42 `_ #4732 [Reference] add missing reference options and descriptions (xabbuh) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `6ba6ffd `_ #5058 Fix: assets_version instead of asset_version (sebastianblum) -- `edf9b78 `_ #5118 Update logger.rst (jdecoster) -- `adf5b90 `_ #5110 [Serializer] Fix class name (iamluc) -- `d65880f `_ #5092 Fixed a minor error introduced by the new redirectToRoute() method (javiereguiluz) -- `206e613 `_ #4304 [DX] Suggest a hint to any auth-check (larsborn) -- `df9c3f4 `_ #5053 Correct RegisterListenersPass namespace (hacfi) -- `893ffad `_ #5041 Fixed variable name in : Reference -> validation constraints -> count -> PHP (aminemat) -- `42ba278 `_ #5037 Finish 4644: Update the_controller.rst (teggen, WouterJ) -- `e9b9376 `_ #5009 Reworded the explanation about optional command options (javiereguiluz) -- `f9901d5 `_ #5000 Fixed case where service definition is actually an alias (Xavier Coureau) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `e7cdb2b `_ #5121 As per twigphp/Twig#472, automatic escaping is not yet available (Ocramius) -- `bce3f04 `_ #5114 [Cookbook][Templating] Use best practice to put templates in app/ dir (WouterJ) -- `d43b845 `_ #5116 Fixes for 2.3 branch (ifdattic) -- `eef413b `_ #5090 Quick review of the Security book chapter (WouterJ) -- `b07c0f4 `_ #5102 Removed duplicate "long"s in length constraint (ByStones) -- `c19598a `_ #5101 [Cookbook][Deployment] some tweaks to #4601 (xabbuh) -- `7e669c1 `_ #5105 added Jakub as a merger for the DomCrawler component (fabpot) -- `2c3513e `_ #5097 added xabbuh to the list of the Symfony core team member (fabpot) -- `6b96470 `_ #5076 Better explain that form types should be unique in the application (javiereguiluz) -- `cdb9350 `_ #5086 Use AppBundle instead of AcmeDemoBundle for consistency (snamor) -- `6719802 `_ #5108 [Components][HttpKernel] fix typo in event flow diagrams (xabbuh) -- `d6a838a `_ #5082 Proofreading tweaks to asset component (weaverryan) -- `17a6863 `_ #5094 Reviewed the Assetic cookbook articles (javiereguiluz) -- `ac9ba97 `_ #4909 Remove horizontal scrollbar and other fixes (ifdattic) -- `51af15d `_ #5087 added Abdellatif as a core team member (fabpot) -- `a801d57 `_ #4601 [Heroku] A few more tweaks to outline the steps (weaverryan) -- `b76ffad `_ #4464 [BestPractices Removing micro-optimization note about @Template (weaverryan) -- `b3e204c `_ #5079 [Contributing][Code] link to deciders' GitHub profiles (xabbuh) -- `33232a8 `_ #5075 Removed an admonition that is no longer true for Symfony 2.6+ (javiereguiluz) -- `4307190 `_ #5072 Add missing use statement in Building Login Form doc (ockcyp) -- `9468b9a `_ #5071 Fixed incorrect plural form (Katharina Störmer) -- `63f1ca3 `_ #5066 [Reference] enclose data type with double backticks (xabbuh) -- `dc01076 `_ #5064 Updated documentation standards (code examples and English use) (javiereguiluz) -- `0d0c795 `_ #5047 Fix service id (JhonnyL) -- `2fe8f76 `_ #5044 Minor improvement in the node types explanation (javiereguiluz) -- `9b1f5f1 `_ #5043 Switched the first example to a static constructor method (kix) -- `ce19196 `_ #5042 added some more components for Tobion as a merger (fabpot) -- `b8a11e1 `_ #5036 A very quick reread of the Form Login article (WouterJ) -- `e94ec09 `_ #5035 reword to serves (cordoval) -- `5eb52e3 `_ #5031 Reworded the note about Windows console and output coloring (javiereguiluz) -- `df72862 `_ #5030 Finish #4586: Update routing.rst (guangle) -- `93387bf `_ #5029 Finish #4370: add a note about apc for php recent versions (ip512, WouterJ) -- `66cf990 `_ #5018 Added a note about the class option of the services defined via factories (javiereguiluz) -- `a89448d `_ #5012 #4032 improved comments about em option (raulfraile) -- `1c50386 `_ #5011 tip for mapping definition (SrgSteak) -- `ce8744d `_ #5081 [Cookbook][Session] some language tweaks (xabbuh) -- `1ee04ba `_ #5006 Added a note about log file sizes and the use of logrotate (javiereguiluz) -- `3be0081 `_ #4976 Improved sentence (edsonmedina) -- `a444220 `_ #4885 Fix typos (ifdattic) -- `482502d `_ #4793 [Contributing] Several tweaks (xelaris) -- `a2395ef `_ #5054 [Changelog] fix changelog syntax (xabbuh) -- `6b66f03 `_ #5003 Updated the generic Deployment article (javiereguiluz) -- `39a1487 `_ #4999 Fixed semantic error (beni0888) - -February, 2015 --------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `16dcf53 `_ #4980 [#4974] Added Twig loader priority Documentation (wizhippo) -- `a25da10 `_ #4966 [#4231] Clarify that only the main command triggers events (riperez) -- `c6bea37 `_ #4957 Added a mention to the @Security annotation (javiereguiluz) -- `9cce63c `_ #4924 [swiftmailer] Document whitelist option to email redirect (TerjeBr) -- `14a080f `_ #4907 Adjustments to PDO Session storage page (kbond) -- `f5ff45e `_ #4712 Provide full test example (ifdattic) -- `5e83045 `_ #4657 Update assetic watch command (xtreamwayz) -- `d447b12 `_ #4556 Updated twig reference with optimizations and paths (jzawadzki) -- `ed80100 `_ minor #4977 Unnecessary comma (edsonmedina) -- `018cf3f `_ #4661 Added a short cookbook about avoiding the automatic start of the sessions (javiereguiluz) -- `2305066 `_ #4902 Removed the Stable API chapter from the Symfony book (javiereguiluz) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `215cacf `_ #4423 Fix description of ConfirmationQuestion (cxj) -- `ed80100 `_ minor #4977 Unnecessary comma (edsonmedina) -- `583ec92 `_ #4984 Fix the example using SerializedParsedExpression (stof) -- `b0d9c5c `_ #4978 fix wrong header-line syntax (sstok) -- `6d65564 `_ #4954 Fixed some syntax issues in Twig Reference (javiereguiluz) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `2a29225 `_ #4985 Fixed a typo (javiereguiluz) -- `f75bc2b `_ #4972 Fix typos (ifdattic) -- `89e626f `_ #4952 symfony 2.7 requires at least php 5.3.9 (scaytrase) -- `9fab10b `_ #4854 Removed no longer needed information about PHP 5.3 (WouterJ) -- `1726054 `_ #4500 Link to standard edition (harikt) -- `91ff6f8 `_ #4329 ensure consistency with the note (greg0ire) -- `f4ab4b6 `_ #5002 Revert very bad merge (WouterJ) -- `e5dbd49 `_ #4977 Unnecessary comma (edsonmedina) -- `ed80100 `_ #4977 Unnecessary comma (edsonmedina) -- `5d44987 `_ #4991 Fixed typo and tweaked syntax. (cdvrooman) -- `b1aadbf `_ #4993 Bumped symfony version number to 2.6 in flat php composer.json example (TSchuermans) -- `3845c9c `_ #4979 require_once path fixed (mvanmeerbeck) -- `96770aa `_ #4969 Add typehint (piotrantosik) -- `f97d01f `_ #4995 [#4965] file extension fix (hansstevens) -- `c5647dd `_ #4968 Fix typo (ifdattic) -- `c3218fc `_ #4962 cookbok/security/acl.rst (DaliusK) -- `72489a4 `_ #4963 Normalize excluded_404s in monolog cookbook (jbafford) -- `0adb6f6 `_ #4964 link to the cookbook article on avoiding to start a session (dbu) -- `5d8456f `_ #4955 Fixed wrong API link (dosten) -- `0a85053 `_ #4950 Fixes for 2.3 branch (ifdattic) -- `d3d96e1 `_ #4951 fix characters in backported patch (xabbuh) -- `208904a `_ #4949 Fixes for 2.3 branch (ifdattic) -- `6be214c `_ #4948 Fixes for 2.6 branch (ifdattic) -- `42b44c4 `_ #4929 Remove block which doesn't make sense after best practices (ifdattic) -- `008c4de `_ #4928 Change installation method order (ifdattic) -- `6f8b145 `_ #4904 Added a reference about including JS and CSS files in PHP templates (javiereguiluz) - -January, 2015 -------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `b32accb `_ minor #4935 Fix typos (ifdattic) -- `ad74169 `_ #4628 Varnish cookbook session cookie handling (dbu) -- `50c5a9e `_ #4895 Added configuration of the user provider (peterrehm) -- `4226fc2 `_ #4883 Global dump (nicolas-grekas) -- `a57db5b `_ #4879 Documented true regex (WouterJ) -- `3bb7b61 `_ #4645 Remove note that's no longer the case (thewilkybarkid) -- `3293286 `_ #4801 [Cookbook][cache][varnish] be more precise about version differences (dbu) -- `572bf3b `_ #4800 [Cookbook][Security] Hint about createToken can return null (xelaris) -- `74d2e30 `_ #4786 Replaced setDefaultOptions by the new configureOptions method (peterrehm) -- `528e8e1 `_ #4740 Use AppBundle whenever it's possible (javiereguiluz) -- `08e5ac9 `_ #4658 Debug formatter tweaks (weaverryan) -- `cfad26c `_ #4605 Adding a link to log things in the prod environment (weaverryan) -- `3643ec2 `_ #4723 [Cookbook][Security] document the new AuthenticationUtils (xabbuh) -- `9742b92 `_ #4761 [Cookbook][Security] don't output message from AuthenticationException (xabbuh) -- `a23e7d2 `_ #4643 How to override vendor directory location (gajdaw) -- `99aca45 `_ #4749 [2.3][Book][Security] Add isPasswordValid doc as in 2.6 (xelaris) -- `d9935a3 `_ #4141 Notes about caching pages with a CSRF Form (ricardclau) -- `207f2f0 `_ #4711 [Reference] Add default_locale config description (xelaris) -- `1b0fe77 `_ #4708 Change Apache php-fpm proxy configuration (TeLiXj) -- `7be0dc6 `_ #4681 adding note to assetic cache busting (weaverryan) -- `127ebc1 `_ #4650 Documented the characters that provoke a YAML escaping string (javiereguiluz) -- `0c0b708 `_ #4454 More concrete explanation of validation groups (peterrehm) -- `4fe4f65 `_ #4682 [Reference] document the `````2.5````` validation options (xabbuh) -- `144e5af `_ #4611 Adding a guide about upgrading (weaverryan) -- `01df3e7 `_ #4626 clean up cache invalidation information on the cache chapter (dbu) -- `5f7ef85 `_ #4651 Documented the security:check command (javiereguiluz) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `ea51aeb `_ #4926 Finish #4505: Fixed composer create-project command (windows) (Epskampie) -- `b32accb `_ minor #4935 Fix typos (ifdattic) -- `7e84533 `_ #4886 [Best Pracitices] restore example in the "Service: No Class Parameter" section (u-voelkel) -- `a6b7d72 `_ #4861 Ifdattic's fixes (ifdattic) -- `8ef3477 `_ #4856 [Components][Debug] fix DebugClassLoader namespace (xabbuh) -- `b9359a2 `_ #4905 Update routing.rst (IlhamiD) -- `9fee9ee `_ #4746 Revert #4651 for 2.3 branch (xelaris) -- `5940d52 `_ #4735 [BestPractices] remove @Security annotation for Symfony 2.3 (xabbuh) -- `ce37b96 `_ #4771 [QuickTour] use the debug:router command name (xabbuh) -- `ffe3425 `_ #4765 [Book][Forms] avoid the request service where possible (xabbuh) -- `36f2e1f `_ #4757 [Components][ClassLoader] don't show deprecated usage of ``Yaml::parse()`` (xabbuh) -- `d8e8d75 `_ #4756 [Components][Config] don't show deprecated usage of ``Yaml::parse()`` (xabbuh) -- `b143754 `_ #4744 [Book][Security] Update code example to fit description (xelaris) -- `310f4ae `_ #4639 Update by_reference.rst.inc (docteurklein) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `2cff942 `_ #4878 [Book][Security] Remove out-dated anchor (xelaris) -- `a97646f `_ #4882 Remove horizontal scrollbar (ifdattic) -- `c24c787 `_ #4931 Remove horizontal scrollbar (ifdattic) -- `83696b8 `_ #4934 Fixes for 2.3 branch (ifdattic) -- `99d225b `_ #4943 Fixes for 2.3 branch (ifdattic) -- `3907af6 `_ #4944 Fix formatting (ifdattic) -- `137ba72 `_ #4945 Fixes for 2.3 branch (ifdattic) -- `5a53e87 `_ #4946 Remove horizontal scrollbar (ifdattic) -- `b32accb `_ #4935 Fix typos (ifdattic) -- `04090c0 `_ #4936 fixed typo (issei-m) -- `0fa9cbd `_ #4937 Keeping documentation consistent (thecatontheflat) -- `3921d70 `_ #4918 Quick proofread of the email cookbook (weaverryan) -- `768650e `_ #4932 Add missing comma in array (ifdattic) -- `418a73b `_ #4922 Fix typo: missing space (ifdattic) -- `30ecdde `_ #4921 Fixes for 2.5 branch (ifdattic) -- `d1103a8 `_ #4919 Fix code examples (ifdattic) -- `20d80c3 `_ #4916 Fixes for 2.3 branch (ifdattic) -- `d7acccf `_ #4914 Fix typo, remove horizontal scrollbar (ifdattic) -- `fc776ab `_ #4894 Align methods in YAML example (ifdattic) -- `bd279f6 `_ #4908 Set twig service as private (ifdattic) -- `37fd035 `_ #4899 Fix typo: looks => look (ifdattic) -- `fbaeecd `_ #4898 added Kévin Dunglas as a merger for the Serializer component (fabpot) -- `7c66a8b `_ #4893 Move annotations example to front (ifdattic) -- `2b7e5ee `_ #4891 fixed typo (acme -> app) (adiebler) -- `00981de `_ #4890 Fixed typo (beni0888) -- `dc87147 `_ #4876 Remove horizontal scrollbar (ifdattic) -- `f5f3c1b `_ #4865 Removed literals for bundle names (WouterJ) -- `33914c9 `_ #4859 [Components][EventDispatcher] don't explain deprecated `````getName()````` method (xabbuh) -- `9a6d7b9 `_ #4831 Update override.rst (ifdattic) -- `f9c2d69 `_ #4803 [Book][Translation] Added tip for routing params (xelaris) -- `2f41c9e `_ #4887 Typo (XitasoChris) -- `3774a37 `_ #4881 Remove 'acme' (ifdattic) -- `d85fa76 `_ #4880 Remove duplicate link, introduction.rst (Quberik) -- `6a15077 `_ #4874 Remove trailing whitespace (WouterJ) -- `80bef5a `_ #4873 [BestPractices] fix typo (xabbuh) -- `6cffa4e `_ #4866 Remove horizontal scrollbar (ifdattic) -- `65b0822 `_ #4798 Add version added note for the debug:event-dispatcher command (adamelso) -- `bcf1508 `_ #4785 [Book][Security] add back old anchors (xabbuh) -- `4143076 `_ #4872 [BestPractices] fix merge after removing @Security in 2.3 (xabbuh) -- `dc25c65 `_ #4769 [2.7] Removed 2.5 versionadded as its deprecated (WouterJ) -- `48835de `_ #4767 [2.6] Removed 2.4 versionadded as version is deprecated (WouterJ) -- `240a981 `_ #4764 [Reference][Forms] move cautions to make them visible (xabbuh) -- `cf3d38a `_ #4731 [Book][Testing] bump required PHPUnit version (xabbuh) -- `4f47dec `_ #4837 Monolog Cookbook Typo Fix: "allows to" should be "allows you to" (mattjanssen) -- `c454fd2 `_ #4857 Add custom link labels where Cookbook articles titles looked wrong (javiereguiluz) -- `17989fd `_ #4860 [Components][HttpKernel] replace API link for SwiftmailerBundle (xabbuh) -- `84839ba `_ #4829 Fix code example (ifdattic) -- `e347ec8 `_ #4819 Removed a leftover comma in security config sample (javiereguiluz) -- `11b9d23 `_ #4772 Tweaks to the new form csrf caching entry (weaverryan) -- `c04ed79 `_ #4848 Fix typo: BLOG => BLOB (ifdattic) -- `f9c1389 `_ #4845 Update security.rst (meelijane) -- `9680ec0 `_ #4844 Update routing.rst (bglamer) -- `c243d00 `_ #4843 Fixed typo (beni0888) -- `5b91653 `_ #4843 Fixed typo (beni0888) -- `13ffb83 `_ #4835 Fixed broken link (SofHad) -- `d2a67ac `_ #4826 Fixed 404 page (SofHad) -- `f34fc2d `_ #4825 Fixed the 404 not found error (SofHad) -- `467c538 `_ #4824 fix SQL: table names (e-moe) -- `91a89b7 `_ #4821 Fixed typo (SofHad) -- `f7179df `_ #4818 [Routing] Removed deprecated usage (WouterJ) -- `82bce29 `_ #4815 Update translation.rst (ifdattic) -- `892586b `_ #4808 Email message instantiation changed to a more 'symfonysh' way. (alebo) -- `e913808 `_ #4802 [Cookbook][Routing] Fixed typo (xelaris) -- `6522145 `_ #4799 Fix markup (WouterJ) -- `a42e5b6 `_ #4778 Update templating.rst (ifdattic) -- `bd7d246 `_ #4752 [Book][Validation] clarify group validation (xabbuh) -- `236c26f `_ #4796 Update service_container.rst (ifdattic) -- `f85c44c `_ #4795 Remove horizontal scrollbar (ifdattic) -- `45189bb `_ #4792 [BestPractices] add filename to codeblock (xelaris) -- `fccea1d `_ #4791 Fix heading level in form_login_setup.rst (xelaris) -- `74c3a35 `_ #4788 Controller is a callable (timglabisch) -- `eb56376 `_ #4781 [Serializer] Bad variable name in example (arno14) -- `28571fc `_ #4780 Add missing semicolon (NightFox7) -- `32bd0b1 `_ #4777 Update templating.rst (ifdattic) -- `dc5d8f8 `_ #4760 Update routing.rst (ifdattic) -- `4e880c1 `_ #4755 fix typo (xabbuh) -- `463c30b `_ #4751 [BestPractices] fix alignment of YAML values (xelaris) -- `1972757 `_ #4775 Corrected validation information on inheritance (peterrehm) -- `f4f8621 `_ #4762 [Cookbook][Configuration] update text to use SetHandler (not ProxyPassMatch) (xabbuh) -- `43543bb `_ #4748 Re-reading private service section (weaverryan) -- `e447e70 `_ #4743 [Book][Security] Fix typo and remove redundant sentence (xelaris) -- `97a9c7b `_ #4742 Formatting fix (WouterJ) -- `9819113 `_ #4702 Clarify tip for creating a new AppBundle (xelaris) -- `8f2fe87 `_ #4683 [Reference] update the configuration reference (xabbuh) -- `e889813 `_ #4677 Add exception to console exception log (adrienbrault) -- `9958c41 `_ #4656 Tried to clarify private services (WouterJ) -- `1d5966c `_ #4703 Fix representation (ifdattic) -- `aa9d982 `_ #4697 Set twig service as private (ifdattic) -- `ece2c81 `_ #4722 Improve readability (ifdattic) -- `dcc9516 `_ #4725 Remove horizontal scrollbar (ifdattic) -- `3eb14aa `_ #4727 Renamed example: "Acme\BlogBundle" -> "AppBundle" (muxator) -- `25dd825 `_ #4730 Fix typo: as => is (ifdattic) -- `760a441 `_ #4734 [BestPractices] add missing comma (xabbuh) -- `caa2be6 `_ #4737 [Book][Security] add missing versionadded directive (xabbuh) -- `8c1afb9 `_ #4738 [Contributing][Code] update year in license (xabbuh) -- `4ad72d0 `_ #4741 use the doc role for internal links (jms85, xabbuh) -- `57fdea6 `_ #4729 Fixed typo in factories.rst (nietonfir) - -December, 2014 --------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `00a13d6 `_ #4606 Completely re-reading the security book (weaverryan) -- `aa88f99 `_ #4609 Adding details about the changes to the PdoSessionHandler in 2.6 (weaverryan) -- `bd65c3c `_ #4673 [Reference] add validation config reference section (xabbuh) -- `55a32cf `_ #4173 use a global Composer installation (xabbuh) -- `c5e409b `_ #4526 Deploy Symfony application on Platform.sh. (GuGuss) -- `ddd56ea `_ #4449 Added cache_busting to default asset config (GeertDD) -- `c837ea1 `_ #4665 Documented the console environment variables (javiereguiluz) -- `0e45e29 `_ #4655 Document new progressbar methods (javiereguiluz) -- `f4a7196 `_ #4627 Rewrite the varnish cookbook article (dbu) -- `92a186d `_ #4654 Rewritten from scratch the chapter about installing Symfony (javiereguiluz) -- `90ef4ec `_ #4580 Updated installation instructions to use the new Symfony Installer (javiereguiluz) -- `f591e6e `_ #4532 GetResponse*Events stop after a response was set (Lumbendil) -- `a09fd7b `_ #4485 Added documentation about the DebugFormatter helper (WouterJ) -- `d327bae `_ #4557 Update pdo_session_storage.rst (spbentz) -- `71495e8 `_ #4528 Update web_server_configuration.rst (thePanz) -- `3b9d60d `_ #4517 [Reference] document configurable PropertyAccessor arguments (xabbuh) -- `9b330ef `_ #4507 Comply with best practices, Round 2 (WouterJ) -- `39a36bc `_ #4405 Finish 3744 (mickaelandrieu, xabbuh) -- `5363542 `_ #4188 Updated documentation regarding the SecurityContext split (iltar) -- `f30f753 `_ #4050 [Translation] added logging capability. (aitboudad) -- `db35c42 `_ #4591 Instructions for setting SYMFONY_ENV on Heroku (dzuelke) -- `8bba316 `_ #4457 [RFC] Clarification on formatting for bangs (!) (bryanagee) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `79db0b9 `_ #4699 Use new security.authorization_checker service (xelaris) -- `9c819b4 `_ #4713 [Security] Removed deprecated example about SecurityContext (iltar) -- `153565e `_ #4707 [Cookbook] Fix XML example for RTE (dunglas) -- `cad4d3f `_ #4582 Completed the needed context to successfully test commands with Helpers (peterrehm) -- `a137918 `_ #4641 Add missing autoload include in basic console application example (senkal) -- `0de8286 `_ #4513 [Contributing] update contribution guide for 2.7/3.0 (xabbuh) -- `8b611e2 `_ #4598 [ExpressionLanguage] add missing argument (xabbuh) -- `7ea4b10 `_ #4646 Update the_controller.rst (teggen) -- `a2ea256 `_ #4637 fixed StringExpressionLanguageProvider code example #4636 (danieleorler) -- `63be343 `_ #4630 [OptionsResolver] Fix namespace (xavren) -- `baf61a0 `_ #4623 [OptionsResolver] Fix Namespace link (xavren) -- `8246693 `_ #4613 Change refering block name from content to body (martin-cerny) -- `1750b9b `_ #4599 [Contributing] fix feature freeze dates (xabbuh) -- `8e2e988 `_ #4603 Replace form_enctype(form) with form_start(form). (xelaris) -- `7acf27c `_ #4552 required PHPUnit version in the docs should be updated to 4.2 (or later)... (jzawadzki) -- `df60ba7 `_ #4548 Remove ExpressionLanguage reference for 2.3 version (dangarzon) -- `727c92a `_ #4594 Missing attribute 'original' (Marcelsj) -- `97a9c43 `_ #4533 Add command to make symfony.phar executable. (xelaris) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `8bd694f `_ #4709 [Reference] fix wording (xabbuh) -- `1bd9ed4 `_ #4721 [Cookbook][Composer] fix note directive (xabbuh) -- `5055ef4 `_ #4715 Improve readability (ifdattic) -- `d3d6d22 `_ #4716 Fix typo: con => on (ifdattic) -- `afe8684 `_ #4720 Link fixed (kuldipem) -- `4b442a0 `_ #4695 Misc changes (ifdattic) -- `0db36ea `_ #4706 Fix typo: than in Twig => than Twig templates (ifdattic) -- `94b833e `_ #4679 General grammar and style fixes in the book (frne) -- `3f3464f `_ #4689 Update form_customization.rst (rodrigorigotti) -- `8d32393 `_ #4691 replace "or" with "," (timglabisch) -- `9b4d747 `_ #4670 Change PHPUnit link to avoid redirect to homepage (xelaris) -- `8ccffb0 `_ #4669 Harmonize PHPUnit version to 4.2 or above (xelaris) -- `84bf5e5 `_ #4667 Remove redundant "default" connection (xelaris) -- `ceca63f `_ #4653 update ordered list syntax (xabbuh) -- `459875b `_ #4550 Ref #3903 - Normalize methods listings (ternel) -- `87365fa `_ #4648 Update forms.rst (keefekwan) -- `70f2ae8 `_ #4640 [Book] link to the API documentation (xabbuh) -- `95fc487 `_ #4608 Removing some installation instructions (weaverryan) -- `96455e6 `_ #4539 Normalization of method listings (pedronofuentes) -- `bd44e6b `_ #4664 Spelling mistake tens to tons (albabar) -- `3b6341a `_ #4663 Removed double `````firewall_restriction````` entry (vlad-ghita) -- `815e0bf `_ #4551 Normalize the method listings on version 2.5 (pedronofuentes) -- `48cc9cd `_ #4647 Update controllers.rst (keefekwan) -- `2efed8c `_ #4660 Fix indentation of YAML example (xelaris) -- `b55ec30 `_ #4659 Fixed some code indentation (javiereguiluz) -- `18af18b `_ #4652 replace Symfony2 with Symfony (xabbuh) -- `a70c489 `_ #4649 Linked the PDO/DBAL Session article from the Doctrine category (javiereguiluz) -- `f672a66 `_ #4625 Added '-ing' title ending to unify titles look (kix) -- `9600950 `_ #4617 [Filesystem] filesystem headlines match method names (xabbuh) -- `8b006bb `_ #4607 [Best Practices] readd mistakenly removed label (xabbuh) -- `7dcce1b `_ #4585 When explaining how to install dependencies for running unit tests, (carlosbuenosvinos) -- `1c9270d `_ #4568 Update Symfony reference to 2.6 version (dangarzon) -- `33ca697 `_ #4561 Use the new build env on Travis (joshk) -- `107610e `_ #4531 [symfony] [Hackday] Fixed typos (pborreli) -- `3b1611d `_ #4519 remove service class parameters (xabbuh) -- `3bd17af `_ #4518 [Components][DependencyInjection] backport service factory improvements (xabbuh) -- `d203e5a `_ #4495 [Best Practices][Business Logic] link to a bundle's current (not master) docs (xabbuh) -- `0a9c146 `_ #4422 Fix typos in code (ifdattic) -- `4f0051d `_ #4574 fixed little typo (adridev) - -November, 2014 --------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `33554fc `_ #4456 New validation API usage in Class Constraint Validator (skwi) -- `135aae6 `_ #4433 Completely re-reading the controller chapter (weaverryan) -- `f748378 `_ #4498 Use new factory syntax (WouterJ) -- `59f0374 `_ #4490 Documented ExpressionLanguage extensibility (WouterJ) -- `ed241ab `_ #4487 Documented html5 option (WouterJ) -- `48a5af3 `_ #4486 Renamed empty_value to placeholder (WouterJ) -- `422e0f1 `_ #4465 Modifying the best practice to use form_start() instead of
    `_ #4463 [BestPractices] Proposing that we make the service names *just* a little bit longer (weaverryan) -- `9a22865 `_ #4446 [Book][Templating] refer to the VarDumper component for dump() (xabbuh) -- `ed5c61f `_ #4411 Added a reference to the Bootstrap 3 form theme (javiereguiluz) -- `766e01f `_ #4169 [Components][Form] document $deep and $flatten of getErrors() (xabbuh) -- `1d88a1b `_ #4443 Added the release dates for the upcoming Symfony 3 versions (javiereguiluz) -- `3329bd2 `_ #4424 [#4243] Tweaks to the new var-dumper component (weaverryan, nicolas-grekas) -- `9caea6f `_ #4336 [Form] Add entity manager instance support for em option (egeloen) -- `f2ab245 `_ #4374 [WCM] Revamped the Quick Start tutorial (javiereguiluz) -- `2c190ed `_ #4427 Update most important book articles to follow the best practices (WouterJ) -- `12a09ab `_ #4377 Added interlinking and fixed install template for reusable bundles (WouterJ) -- `8259d71 `_ #4425 Updating component usage to use composer require (weaverryan) -- `0e80aba `_ #4369 [reference][configuration][security]Added key_length for pbkdf2 encoder (Guillaume-Rossignol) -- `d1afa4d `_ #4243 [WIP] var-dumper component (nicolas-grekas) -- `5165419 `_ #4295 [Security] Hidden front controller for Nginx (phansys) -- `23f790a `_ #4058 Skip console commands from event listeners (tPl0ch) -- `4b98d48 `_ #3386 [Translation] added method to expose collected message (Grygir) -- `242d4f6 `_ #4319 Documentation for debug:event-dispatcher command (matthieuauger) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `9d599a0 `_ minor #4544 #4273 - fix doctrine version in How to Provide Model Classes for several Doctrine Implementations cookbook (ternel) -- `6aabece `_ #4273 - fix doctrine version in How to Provide Model Classes for several Doctrine Implementations cookbook -- `e96ebd3 `_ #4522 Add missing brackets to PropertyAccessor examples (loonytoons) -- `4f66d48 `_ #4506 SetDescription required on Product entities (yearofthegus) -- `85bf906 `_ #4444 fix elseif statement (MightyBranch) -- `ad14e78 `_ #4494 Updated the Symfony Installer installation instructions (javiereguiluz) -- `7cc4287 `_ #4442 replace doc role for bundle docs with external ref (xabbuh) -- `33bf462 `_ #4407 [Components][Console] array options need array default values (xabbuh) -- `2ab2e1f `_ #4342 Reworded a misleading Doctrine explanation (javiereguiluz) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `a109c4b `_ #4537 Update link to remove absolute URL (jms85, dangarzon) -- `05f5dba `_ #4536 Add Ryan Weaver as 10th core team member (ifdattic) -- `7b1ff2a `_ #4554 Changed url to PHP-CS-FIXER repository (jzawadzki) -- `9d599a0 `_ #4544 bug #4273 - fix doctrine version in How to Provide Model Classes for several Doctrine Implementations cookbook (ternel) -- `7b3500c `_ #4542 Update conventions.rst (csuarez) -- `5aaba1e `_ #4529 Best Practices: Update link title to match cookbook article title (dangarzon) -- `ab8e7f5 `_ #4530 Book: Update link title to match cookbook article title (dangarzon) -- `bf61658 `_ #4523 Add missing semicolons to PropertyAccess examples (loonytoons) -- `8beadce `_ #4496 [Book][Security] link to a bundle's current (not master) docs (xabbuh) -- `43809b1 `_ #4479 remove versionadded directives for old versions (xabbuh) -- `5db8386 `_ #4462 [Reference] Fixed lots of things using the review bot (WouterJ) -- `dbfaac1 `_ #4459 Fix up the final sentence to be a bit cleaner. (micheal) -- `3761e50 `_ #4514 [Contributing][Documentation] typo fix (xabbuh) -- `21afb4c `_ #4445 Removed unnecessary use statement (Alex Salguero) -- `3969fd6 `_ #4432 [Reference][Twig] tweaks to the Twig reference (xabbuh) -- `188dd1f `_ #4400 Continues #4307 (SamanShafigh, WouterJ) -- `c008733 `_ #4399 Explain form() and form_widget() in form customization (oopsFrogs, WouterJ) -- `2139754 `_ #4253 Adder and remover sidenote (kshishkin) -- `b81eb4d `_ #4488 Terrible mistake! Comma instead of semicolon... (nuvolapl) -- `0ee3ae7 `_ #4481 [Cookbook][Cache] add syntax highlighting for Varnish code blocks (xabbuh) -- `0577559 `_ #4418 use the C lexer for Varnish config examples (xabbuh) -- `97d8f61 `_ #4403 Improved naming (WouterJ) -- `6298595 `_ #4453 Fixed make file (WouterJ) -- `0c7dd72 `_ #4475 Fixed typos (pborreli) -- `b847b2d `_ #4480 Fix spelling (nurikabe) -- `0d91cc5 `_ #4461 Update doctrine.rst (guiguiboy) -- `81fc1c6 `_ #4448 [Book][HTTP Cache] moved inlined URL to the bottom of the file (xabbuh) -- `6995b07 `_ #4435 consistent table headlines (xabbuh) -- `0380d34 `_ #4447 [Book] tweaks to #4427 (xabbuh) -- `eb0d8ac `_ #4441 Updated first code-block``::`` bash (Nitaco) -- `41bc061 `_ #4106 removed references to documentation from external sources (fabpot, WouterJ) -- `c9a8dff `_ #4352 [Best Practices] update best practices index (xabbuh) -- `8a93c95 `_ #4437 Correct link to scopes page (mayeco) -- `91eb652 `_ #4438 Fix typo: Objected => Object (ifdattic) -- `5d6d0c2 `_ #4436 remove semicolons in PHP templates (xabbuh) -- `97c4b2e `_ #4434 remove unused label (xabbuh) -- `4be6786 `_ #4326 [Components][Form] Grammar improvement (fabschurt) -- `a27238e `_ #4313 Improved and fixed twig reference (WouterJ) -- `1ce9dc5 `_ #4398 A few small improvements to the EventDispatcher Component docs (GeertDD) -- `42abc66 `_ #4421 [Best Practices] removed unused links in business-logic (77web) -- `61c0bc5 `_ #4419 [DependencyInjection] Add missing space in code (michaelperrin) - -October, 2014 -------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `d7ef1c7 `_ #4348 Updated information about handling validation of embedded forms to Valid... (peterrehm) -- `691b13d `_ #4340 [Cookbook][Web Server] add sidebar for the built-in server in VMs (xabbuh) -- `bd85865 `_ #4299 [Serializer] Handle circular references. symfony/symfony#12098. (dunglas) -- `d79c48d `_ #4280 [Cookbook][Cache] Added config example for Varnish 4.0 (thierrymarianne) -- `5849f7f `_ #4168 [Components][Form] describe how to access form errors (xabbuh) -- `c10e9c1 `_ #4371 Added a code example for emailing on 4xx and 5xx errors without 404's (weaverryan) -- `1117741 `_ #4159 [WCM][OptionsResolver] Adjusted the OptionsResolver documentation to describe the 2.6 API (webmozart, peterrehm) -- `0c57939 `_ #4327 First import of the "Official Best Practices" book (javiereguiluz) -- `2cd6646 `_ #4293 Document error page preview (Symfony ~2.6) (mpdude) -- `142c826 `_ #4005 [Cookbook][Web server] description for running PHP's built-in web server in the background (xabbuh) -- `8dc90ef `_ #4224 [Components][HttpKernel] outline implications of the kernel.terminate event (xabbuh) -- `d3b5ba2 `_ #4085 [Component][Forms] add missing features introduced in 2.3 (xabbuh) -- `f433e64 `_ #4099 Composer installation verbosity tip (dannykopping) -- `f583a45 `_ #4204 [Reference][Constraints] validate `````null````` (Expression constraint in 2.6) (xabbuh) -- `925a162 `_ #4290 Updating library/bundle install docs to use "require" (weaverryan) -- `86c67e8 `_ #4233 2.5 Validation API changes (nicolassing, lashae, Rootie, weaverryan) -- `0f34bb8 `_ #3956 [Command] Added LockHelper (lyrixx) -- `278de83 `_ #3930 [Console] Add Process Helper documentation (romainneutron) -- `44f570b `_ #4294 Improve cookbook entry for error pages in 2.3~ (mpdude) -- `3b6c2b9 `_ #4269 [Cookbook][External Parameters] Enhance content (bicpi) -- `25a17fe `_ #4264 [#4003] A few more form_themes config changes (weaverryan) -- `5b65654 `_ #3912 [Security] Added remote_user firewall info and documentation for pre authenticated firewalls (Maxime Douailin, mdouailin) -- `62bafad `_ #4246 [Reference] add description for the `````validation_groups````` option (xabbuh) -- `5d505bb `_ #4206 Added note about ProgressBar changes (kbond) -- `c2342a7 `_ #4241 [Form] Added information about float choice lists (peterrehm) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `dde6919 `_ #4390 Update custom_constraint.rst (luciantugui) -- `68a2c7b `_ #4381 Updated Valid constraint reference (inso) -- `dbb25b9 `_ #4379 [OptionsResolver] Fix wrong namespace in example (rybakit) -- `db01e57 `_ #4362 Missing apostrophe in source example. (astery) -- `d49d51f `_ #4350 Removed extra parenthesis (sivolobov) -- `e6d7d8f `_ #4315 Update choice.rst (odolbeau) -- `1b15d57 `_ #4300 [Components][PropertyAccess] Fix PropertyAccessorBuilder usage (Thierry Geindre) -- `061324f `_ #4297 [Cookbook][Doctrine] Fix typo in XML configuration for custom SQL functions (jdecool) -- `f81b7ad `_ #4292 Fixed broken external link to DemoController Test (danielsan) -- `9591a04 `_ #4284 change misleading language identifier (Kristof Van Cauwenbergh, kristofvc) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `217bf5f `_ #4353 [Cookbook][Controller] fix route prefix in PHP code example (xabbuh) -- `a4f7d51 `_ #4396 Corrected latin abbreviation (GeertDD) -- `ebf2927 `_ #4387 Inline condition removed for easier reading (acidjames) -- `aa70028 `_ #4375 Removed the redundant usage of layer. (micheal) -- `f3dd676 `_ #4394 update Sphinx extension submodule reference (xabbuh) -- `6406a27 `_ #4391 Removed unused use UsernameNotFoundException (boekkooi) -- `9e03f2d `_ #4388 Minor spelling fix (GeertDD) -- `4dfd607 `_ #4356 Remove incoherence between Doctrine and Propel introduction paragraphs (arnaugm) -- `1d71332 `_ #4344 [Templating] Added a sentence that explains what a Template Helper is (iltar) -- `22b9b27 `_ #4372 Tweaks after proofreading the 2.6 OptionsResolver stuff (weaverryan, WouterJ) -- `9a76309 `_ #4384 fix typo (kokoon) -- `eb752cc `_ #4363 Fixed sentence (WouterJ) -- `3e8aa59 `_ #4376 Cleaned up javascript code (flip111) -- `06e7c5f `_ #4364 changed submit button label (OskarStark) -- `d1810ca `_ #4357 fix Twig-extensions links (mhor) -- `e2e2915 `_ #4359 Added missing closing parenthesis to example. (mattjanssen) -- `f1bb8bb `_ #4358 Fixed link to documentation standards (sivolobov) -- `65c891d `_ #4355 Missing space (ErikSaunier) -- `7359cb4 `_ #4196 Clarified the bundle base template bit. (Veltar) -- `6ceb8cb `_ #4345 Correct capitalization for the Content-Type header (GeertDD) -- `3e4c92a `_ #4104 Use ${APACHE_LOG_DIR} instead of /var/log/apache2 (xamgreen) -- `3da0776 `_ #4338 ESI Variable Details Continuation (Farkie, weaverryan) -- `7f461d2 `_ #4325 [Components][Form] Correct a typo (fabschurt) -- `d162329 `_ #4276 [Components][HttpFoundation] Make a small grammatical adjustment (fabschurt) -- `69bfac1 `_ #4322 [Components][DependencyInjection] Correct a typo: replace "then" by "the" (fabschurt) -- `8073239 `_ #4318 [Cookbook][Bundles] Correct a typo: remove unnecessary "the" word (fabschurt) -- `228111b `_ #4316 Remove horizontal scrollbar (ifdattic) -- `34e22d6 `_ #4317 Remove horizontal scrollbar and change event name to follow conventions (ifdattic) -- `090afab `_ #4287 support Varnish in configuration blocks (xabbuh) -- `1603463 `_ #4306 Improve readability (ifdattic) -- `e5fed9d `_ #4303 Fix spelling (nurikabe) -- `31d7905 `_ #4302 View documentation had a reference to the wrong twig template (milan) -- `ef11ef4 `_ #4250 Clarifying Bundle Best Practices is for *reusable* bundles (weaverryan) -- `430eabf `_ #4298 Book HTTP Fundamentals routing example fixed with routing.xml file (peterkokot) -- `a535c9f `_ #4285 Update security.rst (placid2000) -- `7ab6df9 `_ #4237 Finished #3886 (ahsio, WouterJ) -- `990b453 `_ #4245 [Contributing] tweaks to the contribution chapter (xabbuh) - -September, 2014 ---------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `e8a1501 `_ #4201 [Components][Process] `````mustRun()````` documentation (xabbuh) -- `eac0e51 `_ #4195 Added a note about the total deprecation of YUI (javiereguiluz) -- `e44c791 `_ #4047 Documented info method (WouterJ) -- `2962e14 `_ #4003 [Twig][Form] Moved twig.form.resources to a higher level (stefanosala) -- `d5d46ec `_ #4017 Clarify that route defaults don't need a placeholder (iamdto) -- `1d56da4 `_ #4239 Remove redundant references to trusting HttpCache (thewilkybarkid) -- `c306b68 `_ #4249 provide node path on configuration (desarrolla2) -- `9f0f14e `_ #4210 Move debug commands to debug namespace (matthieuauger) -- `9b4b36f `_ #4236 Javiereguiluz bundle install instructions (WouterJ) -- `ea068c2 `_ #4202 [Reference][Constraints] caution on `````null````` values in Expression constraint (xabbuh) -- `a578de9 `_ #4223 Revamped the documentation about "Contributing Docs" (javiereguiluz) -- `de60dbe `_ #4182 Added note about exporting SYMFONY_ENV (jpb0104) -- `a8dc2bf `_ #4166 Translation custom loaders (raulfraile) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `c289ac8 `_ #4279 Double-quotes instead of single quotes (UnexpectedValueException in Windows 8) (galdiolo) -- `5500e0b `_ #4267 Fix error in bundle installation standard example (WouterJ) -- `082755d `_ #4240 [Components][EventDispatcher] fix ContainerAwareEventDispatcher definition (xabbuh) -- `2319d6a `_ #4213 Handle "constraints" option in form unit testing (sarcher) -- `c567707 `_ #4222 [Components][DependencyInjection] do not reference services in parameters (xabbuh) -- `02d1091 `_ #4209 Fix method for adding placholders in progressBar (danez) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `df16779 `_ #4226 add note about parameters in imports (xabbuh) -- `c332063 `_ #4278 Missing word in DependencyInjection => Types of Injection (fabschurt) -- `287c7bf `_ #4275 added Nicolas to the list of mergers for the new var dumper component (fabpot) -- `3a4e226 `_ #4263 Fixed typo (zebba) -- `187c255 `_ #4259 Added feature freeze dates for Symfony versions (javiereguiluz) -- `efc1436 `_ #4247 [Reference] link translation DIC tags to components section (xabbuh) -- `17addb1 `_ #4238 Finished #3924 (WouterJ) -- `19a0c35 `_ #4252 Removed unnecessary comma (allejo) -- `9fd91d6 `_ #4219 Cache needs be cleared (burki94) -- `025f02e `_ #4220 Added a note about the side effects of enabling both PHP and Twig (javiereguiluz) -- `46fcb67 `_ #4218 Caution that roles should start with ``ROLE_`` (jrjohnson) -- `78eea60 `_ #4077 Removed outdated translations from the official list (WouterJ) -- `2cf9e47 `_ #4171 Fixed version for composer install (zomberg) -- `5c62b36 `_ #4216 Update Collection.rst (azarzag) -- `8591b87 `_ #4215 Fixed code highlighting (WouterJ) -- `8f01195 `_ #4212 Missing backtick, thanks to @Baptouuuu (WouterJ) -- `f276e34 `_ #4205 replace "Symfony2" with "Symfony" (xabbuh) -- `6db13ac `_ #4208 Added a note about the lacking features of Yaml Component (javiereguiluz) -- `f8c6201 `_ #4200 Moved 'contributing' images to their own directory (javiereguiluz) -- `b4650fa `_ #4199 fix name of the Yaml component (xabbuh) -- `9d89bb0 `_ #4190 add link to form testing chapter in test section (xabbuh) - -August, 2014 ------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `bccb080 `_ #4140 [Cookbook][Logging] document multiple recipients in XML configs (xabbuh) -- `7a6e3d1 `_ #4150 Added the schema_filter option to the reference (peterrehm) -- `be90d8a `_ #4142 [Cookbook][Configuration] tweaks for the web server configuration chapter (xabbuh) -- `5379f54 `_ #4086 [Reference][Constraints] Added hint about attaching the expression constraint to a form field (peterrehm) -- `041105c `_ #3883 Removed redundant POST request exclusion info (ryancastle) -- `4f9fef6 `_ #4000 [Cookbook] add cookbook article for the server:run command (xabbuh) -- `4ea4dfe `_ #3915 [Cookbook][Configuration] documentation of Apache + PHP-FPM (xabbuh) -- `79cb4f1 `_ #4069 document the namespace alias (dbu) -- `08bed5f `_ #4128 Finished #3759 (WouterJ) -- `4d5adaa `_ #4125 Added link to JSFiddle example (WouterJ) -- `75bda4b `_ #4124 Rebased #3965 (WouterJ) -- `e2f13a4 `_ #4039 [DomCrawler] Added node name getter (fejese) -- `3f92d5f `_ #3966 [Cookbook][Controller] Add note about invokable controller services (kbond) -- `fdb8a32 `_ #3950 [Components][EventDispatcher] describe the usage of the RegisterListenersPass (xabbuh) -- `7e09383 `_ #3940 Updated docs for Monolog "swift" handler in cookbook. (phansys) -- `9d7c999 `_ #3895 [Validator] Support "maxSize" given in KiB (jeremy-derusse) -- `8adfe98 `_ #3894 Rewrote Extension & Configuration docs (WouterJ) -- `cafea43 `_ #3888 Updated the example used to explain page creation (javiereguiluz) -- `df0cf68 `_ #3885 [RFR] Added "How to Organize Configuration Files" cookbook (javiereguiluz) -- `41116da `_ #4081 [Components][ClassLoader] documentation for the ClassMapGenerator class (xabbuh) -- `2b9cb7c `_ #4076 Fixed description of session storage of the ApiKeyAuthenticator (peterrehm) -- `35a0f66 `_ #4102 Adding a new entry about reverse proxies in the framework (weaverryan) -- `95c2066 `_ #4096 labels in submit buttons + new screenshot (ricardclau) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `5fac303 `_ #4165 Update voters.rst (gerryvdm) -- `4882b99 `_ #4164 Fixed minor typos. (ahsio) -- `eaaa35a `_ #4145 Fix documentation for group_sequence_provider (giosh94mhz) -- `155c3e8 `_ #4153 [Reference] fix namespace in Expression constraint (xabbuh) -- `2c93aa5 `_ #4147 [Cookbook][Logging] add missing Monolog handler type in XML config (xabbuh) -- `53b2c2b `_ #4139 cleaned up the code example (gondo) -- `b5c9f2a `_ #4138 fixed wrongly linked dependency (gondo) -- `b486b22 `_ #4131 Replaced old way of specifying http method by the new one (Baptouuuu) -- `93481d7 `_ #4120 Fix use mistakes (mbutkereit) -- `c0a0120 `_ #4119 Fix class name in ConsoleTerminateListener example (alOneh) -- `4629d8b `_ #4116 Fixed the code snippets for the expression language functions (stof) -- `d699255 `_ #4083 [Reference] field dependent empty_data option description (xabbuh) -- `3ffc20f `_ #4103 [Cookbook][Forms] fix PHP template file name (xabbuh) -- `234fa36 `_ #4095 Fix php template (piotrantosik) -- `01fb9f2 `_ #4093 See #4091 (dannykopping) -- `8f3a261 `_ #4092 See #4091 (dannykopping) -- `7d39b03 `_ #4079 Fixed typo in filesystem component (kohkimakimoto) -- `f0bde03 `_ #4075 Fixed typo in the yml validation (timothymctim) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `e9d317a `_ #4160 [Reference] consistent & complete config examples (xabbuh) -- `3e68ee7 `_ #4152 Adding 'attr' option to the Textarea options list (ronanguilloux) -- `a7f3297 `_ #4136 [Reference] fix from suffix to prefix (xabbuh) -- `c4eb628 `_ #4130 A set of small typos (Baptouuuu) -- `236d8e0 `_ #4137 fixed directive syntax (WouterJ) -- `6e90520 `_ #4135 [#3940] Adding php example for an array of emails (weaverryan) -- `b37ee61 `_ #4132 Use proper way to reference a doc page for legacy sessions (Baptouuuu) -- `189a123 `_ #4129 [Components] consistent & complete config examples (xabbuh) -- `5ab5246 `_ #4127 Second part of #3848 (WouterJ) -- `46f3108 `_ #4126 Rebased #3848 (WouterJ) -- `84e6e7f `_ #4114 [Book] consistent and complete config examples (xabbuh) -- `03fcab1 `_ #4112 [Contributing][Documentation] add order of translation formats (xabbuh) -- `650120a `_ #4002 added Github teams for the core team (fabpot) -- `10792c3 `_ #3959 [book][cache][tip] added cache annotations. (aitboudad) -- `ebaed21 `_ #3944 Update dbal.rst (bpiepiora) -- `16e346a `_ #3890 [Components][HttpFoundation] use a placeholder for the constructor arguments (xabbuh) -- `7bb4f34 `_ #4115 [Documentation] [Minor] Changes foobar.net in example.com (magnetik) -- `12d0b82 `_ #4113 tweaks to the new reverse proxy/load balancer chapter (xabbuh) -- `4cce133 `_ #4057 Update introduction.rst (carltondickson) -- `26141d6 `_ #4080 [Reference] order form type options alphabetically (xabbuh) -- `7806aa7 `_ #4117 Added a note about the automatic handling of the memory spool in the CLI (stof) -- `5959b6c `_ #4101 [Contributing] extended Symfony 2.4 maintenance (xabbuh) -- `e2056ad `_ #4072 [Contributing][Code] add note on Symfony SE forks for bug reports (xabbuh) -- `b8687dd `_ #4091 Put version into quotes, otherwise it fails in ZSH (dannykopping) -- `665c091 `_ #4087 Typo (tvlooy) -- `f95bbf3 `_ #4023 [Cookbook][Security] usage of a non-default entity manager in an entity user provider (xabbuh) -- `27b1003 `_ #4074 Fixed (again) a typo: Toolbet --> Toolbelt (javiereguiluz) -- `c97418f `_ #4073 Reworded bundle requirement (WouterJ) -- `e5d5eb8 `_ #4066 Update inherit_data_option.rst (Oylex) -- `9c08572 `_ #4064 Fixed typo on tag service (saro0h) - -July, 2014 ----------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `1b4c1c8 `_ #4045 Added a new "Deploying to Heroku Cloud" cookbook article (javiereguiluz) -- `f943eee `_ #4009 Remove "Controllers extends ContainerAware" best practice (tgalopin) -- `eae9ad0 `_ #3875 Added a note about customizing a form with more than one template (javiereguiluz) -- `2ae4f34 `_ #3746 [Validator] Disallow empty file in FileValidator (megazoll) -- `1938c2f `_ #3724 Updated ISBN validator docs (sprain) -- `7c71b18 `_ #2952 Enabling profiler in test (danieledangeli) -- `d6787b7 `_ #3989 adde stof as a merger (fabpot) -- `4a9e49e `_ #3946 DQL custom functions on doctrine reference page (healdropper) -- `2b2d9d3 `_ #3972 Added PSR-4 to Class Loaders list (dosten) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `1b695b5 `_ #4063 fix parent form types (xabbuh) -- `7901005 `_ #4048 $this->request replaced by $request (danielsan) -- `f6123f1 `_ #4031 Update form_events.rst (redstar504) -- `99932cf `_ #4010 [Console] Fixed documentation for ProgressBar (VasekPurchart) -- `06f8c31 `_ #4012 Fix xml route configuration for routing condition (xavierbriand) -- `a2a628f `_ #4025 added CVE 2014-4931 (fabpot) -- `a1435e5 `_ #3998 [Console] Fixed QuestionHelper examples (florianv) -- `b32f9f2 `_ #3771 Fix function example in expression language component (raulfraile) -- `eb813a5 `_ #3979 removed invalid processors option (ricoli) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `a4bdb97 `_ #4070 Added a note about permissions in the Quick Tour (javiereguiluz) -- `a7fe00f `_ #4068 Remove diff info from cookbook/security/voters.rst (pmartelletti) -- `b3f15b2 `_ #4059 eraseCredentials method typo (danielsan) -- `44091b1 `_ #4053 Update doctrine.rst (sr972) -- `b06ad60 `_ #4052 [Security] [Custom Provider] Use properties on WebserviceUser (entering) -- `a834a7e `_ #4042 [Cookbook] apply headline guidelines to the cookbook articles (xabbuh) -- `f25faf3 `_ #4046 Fixed a syntax error (javiereguiluz) -- `3c660d1 `_ #4044 Added editorconfig (WouterJ) -- `ae3ec04 `_ #4041 [Cookbook][Deployment] link to the deployment index (xabbuh) -- `2e4fc7f `_ #4030 enclose YAML strings containing % with quotes (xabbuh) -- `9520d92 `_ #4038 Update rendered tag (kirill-oficerov) -- `f5c2602 `_ #4036 Update page_creation.rst (redstar504) -- `c2eda93 `_ #4034 Update internals.rst (redstar504) -- `a5ad0df `_ #4035 Update version in Rework your Patch section (yguedidi) -- `eed8d64 `_ #4026 Updating Symfony version from 2.4 to 2.5 (danielsan) -- `12752c1 `_ #4013 Removed wrong reference to cookbook (gquemener) -- `ec832dc `_ #3994 [Console] Fix Console component $app to $this and use of getHelper() method (eko) -- `d8b037a `_ #4019 Update twig_reference.rst (redstar504) -- `7ea87e6 `_ #4016 Fixed the format of one letter-based list (javiereguiluz) -- `579a873 `_ #4015 Fixed bad indenting (the list was treated as a blockquote) (javiereguiluz) -- `4669620 `_ #4004 use GitHub instead of Github (xabbuh) -- `a3fe74f `_ #3993 [Console] Fix Console component getHelperSet()->get() to getHelper() (eko) -- `a41af7e `_ #3880 document the mysterious abc part of the header (greg0ire) -- `90773b0 `_ #3990 Move the section about collect: false to the cookbook entry (weaverryan) -- `2ae8281 `_ #3864 plug rules for static methods (cordoval) -- `d882cc0 `_ #3988 fix typos. (yositani2002) -- `b67a059 `_ #3986 Rebased #3982 - Some fixes (WouterJ) -- `801c756 `_ #3977 [WCM] removed call to deprecated getRequest() method (Baptouuuu) -- `4c1d4ae `_ #3968 Proofreading the new Azure deployment article (weaverryan) - -June, 2014 ----------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `5540e0b `_ #3963 [cookbook] [deployment] added cookbook showing how to deploy to the Microsoft Azure Website Cloud (hhamon) -- `6cba0f1 `_ #3936 Varnish only takes into account max-age (gonzalovilaseca) -- `3c95af5 `_ #3928 Reorder page from simple to advanced (rebased) (clemens-tolboom) -- `350b805 `_ #3916 [Component][EventDispatcher] documentation for the TraceableEventDispatcher (xabbuh) -- `1702133 `_ #3913 [Cookbook][Security] Added doc for x509 pre authenticated listener (zefrog) -- `32b9058 `_ #3909 Update the CssSelector component documentation (stof) -- `23b51c8 `_ #3901 Bootstraped the standards for "Files and Directories" (javiereguiluz) -- `8931c36 `_ #3889 Fixed the section about getting services from a command (javiereguiluz) -- `9fddab6 `_ #3877 Added a note about configuring several paths under the same namespace (javiereguiluz) -- `eadf281 `_ #3874 Updated the installation instructions for Symfony 2.5+ (javiereguiluz) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `aeffd12 `_ #3961 Fixing php coding (mvhirsch) -- `84332ff `_ #3945 Fixed missing component name in namespaces (WouterJ) -- `d8329dc `_ #3943 Fixing simple quotes in double quotes (ptitlazy) -- `04f4318 `_ #3934 Move __construct after the repository assignment (cmodijk) -- `0626f2b `_ #3897 Collection constraint (hhamon) -- `3387cb2 `_ #3871 Fix missing Front Controller (parthasarathigk) -- `8257be9 `_ #3891 Fixed wrong method call. (cmfcmf) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `75ee6b4 `_ #3969 [cookbook] [deployment] removed marketing introduction in Azure Deployme... (hhamon) -- `02aeade `_ #3967 fix typo. (yositani2002) -- `208b0dc `_ #3951 fix origin of AcmeDemoBundle (hice3000) -- `fba083e `_ #3957 [Cookbook][Bundles] fix typos in the prepend extension chapter (xabbuh) -- `c444b5d `_ #3948 update the Sphinx extensions to raise warnings when backslashes are not ... (xabbuh) -- `8fef7b7 `_ #3938 [Contributing][Documentation] don't render the list inside a blockquote (xabbuh) -- `b7a03f8 `_ #3937 properly escape backslashes in class and method directives (xabbuh) -- `882471f `_ #3935 Typo (greg0ire) -- `222a014 `_ #3933 render directory inside a code block (xabbuh) -- `0c2a9b3 `_ #3931 [Component][EventDispatcher] 2.5 specific documentation for the TraceableEventDispatcher (xabbuh) -- `b31ea51 `_ #3929 Update custom_authentication_provider.rst (verschoof) -- `7937864 `_ #3927 [Cookbook][Security] Explicit 'your_user_provider' configuration parameter (zefrog) -- `26d00d0 `_ #3925 Fixed the indentation of two code blocks (javiereguiluz) -- `351b2cf `_ #3922 update fabpot Sphinx extensions version (xabbuh) -- `3ddbe1b `_ #3923 Fixed the headers of one table (javiereguiluz) -- `35cbffc `_ #3920 [Components][Form] remove blank line to render the versionadded directive properly (xabbuh) -- `df9f31a `_ #3882 change version numbers in installation notes to be in line with the docu... (xabbuh) -- `ed496ae `_ #3887 [Components][Form] add versionadded for the data collector form extension (xabbuh) -- `36337e7 `_ #3906 Blockquote introductions (xabbuh) -- `5e0e119 `_ #3899 [RFR] Misc. fixes mostly related to formatting issues (javiereguiluz) -- `349cbeb `_ #3900 Fixed the formatting of the table headers (javiereguiluz) -- `1dc8b4a `_ #3898 clarifying the need of a factory for auth-provider (leberknecht) -- `0c20141 `_ #3896 Fixing comment typo for Doctrine findBy and findOneBy code example (beenanner) -- `b00573c `_ #3870 Fix wrong indentation for lists (WouterJ) - -May, 2014 ---------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `4fd1b49 `_ #3753 [DependencyInjection] Add documentation about service decoration (romainneutron) -- `f913dd7 `_ #3603 [Serializer] Support for is.* getters in GetSetMethodNormalizer (tiraeth) -- `e8511cb `_ #3776 Updated event_listener.rst (bfgasparin) -- `af8c20f `_ #3818 [Form customization] added block_name example. (aitboudad) -- `c788325 `_ #3841 [Cookbook][Logging] register processor per handler and per channel (xabbuh) -- `979533a `_ #3839 document how to test actions (greg0ire) -- `d8aaac3 `_ #3835 Updated framework.ide configuration (WouterJ) -- `a9648e8 `_ #3742 [2.5][Templating] Add documentation about generating versioned URLs (romainneutron) -- `f665e14 `_ #3704 [Form] Added documentation for Form Events (csarrazi) -- `14b9f14 `_ #3777 added docs for the core team (fabpot) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `0649c21 `_ #3869 Add a missing argument to the PdoSessionHandler (jakzal) -- `259a2b7 `_ #3866 [Book][Security]fixed Login when there is no session. (aitboudad) -- `9b7584f `_ #3863 Error in XML (tvlooy) -- `0cb9c3b `_ #3827 Update 'How to Create and store a Symfony2 Project in Git' (nicwortel) -- `4ed9a08 `_ #3830 Generate an APC prefix based on __FILE__ (trsteel88) -- `9a65412 `_ #3840 Update dialoghelper.rst (jdecoster) -- `1853fea `_ #3716 Fix issue #3712 (umpirsky) -- `baa9759 `_ #3791 Property access tweaks (weaverryan) -- `80d70a4 `_ #3779 [Book][Security] constants are defined in the SecurityContextInterface (xabbuh) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `302fa82 `_ #3872 Update hostname_pattern.rst (sofany) -- `50672f7 `_ #3867 fixed missing info about FosUserBundle. (aitboudad) -- `3e3004f `_ #3865 Fixed link. (aitboudad) -- `b32ec15 `_ #3856 Update voters_data_permission.rst (MarcomTeam) -- `bffe163 `_ #3859 Add filter cssrewrite (DOEO) -- `f617ff8 `_ #3764 Update testing.rst (NAYZO) -- `3792fee `_ #3858 Clarified Password Encoders example (WouterJ) -- `663d68c `_ #3857 Added little bit information about the route name (WouterJ) -- `797cbd5 `_ #3794 Adds link to new QuestionHelper (weaverryan) -- `4211bff `_ #3852 Fixed link and typo in type_guesser.rst (rpg600) -- `78ae7ec `_ #3845 added link to /cookbook/security/force_https. (aitboudad) -- `6c69362 `_ #3846 [Routing][Loader] added JMSI18nRoutingBundle (aitboudad) -- `136864b `_ #3844 [Components] Fixed some typos. (ahsio) -- `b0710bc `_ #3842 Update dialoghelper.rst (bijsterdee) -- `9f1a354 `_ #3804 [Components][DependencyInjection] add note about a use case that requires to compile the container (xabbuh) -- `d92c522 `_ #3769 Updated references to new Session() (scottwarren) -- `00f60a8 `_ #3837 More asset version details (weaverryan) -- `681ddc8 `_ #3843 [Changelog] fix literal positions (xabbuh) -- `1aa79d5 `_ #3834 fix the wording in versionadded directives (for the master branch) (xabbuh) -- `7288a33 `_ #3789 [Reference][Forms] Improvements to the form type (xabbuh) -- `72fae25 `_ #3790 [Reference][Forms] move versionadded directives for form options directly below the option's headline (xabbuh) -- `b4d4ac3 `_ #3838 fix filename typo in cookbook/form/unit_testing.rst (hice3000) -- `0b06287 `_ #3836 remove unnecessary rewrite from nginx conf (Burgov) -- `89d0dae `_ #3833 fix the wording in versionadded directives (for the 2.4 branch) (xabbuh) -- `e58e39f `_ #3832 fix the wording in versionadded directives (for the 2.3 branch) (xabbuh) -- `09d6ca1 `_ #3829 [Components] consistent headlines (xabbuh) -- `54e0882 `_ #3828 [Contributing] consistent headlines (xabbuh) -- `b1336d7 `_ #3823 Added empty line after if statements (zomberg) -- `79b9fdc `_ #3822 Update voters_data_permission.rst (mimol91) -- `69cb7b8 `_ #3821 Update custom_authentication_provider.rst (leberknecht) -- `9f602c4 `_ #3820 Update page_creation.rst (adreeun) -- `52518c0 `_ #3819 Update csrf_in_login_form.rst (micheal) -- `1adfd9b `_ #3802 Add a note about which types can be used in Symfony (fabpot) -- `fa27ded `_ #3801 [Cookbook][Form] Fixed Typo & missing word. (ahsio) -- `127beed `_ #3770 Update factories.rst (AlaaAttya) -- `822d985 `_ #3817 Update translation.rst (richardpi) -- `241d923 `_ #3813 [Reference][Forms]fix time field count. (yositani2002) -- `bc96f55 `_ #3812 [Cookbook][Configuration] Fixed broken link. (ahsio) -- `5867327 `_ #3809 Fixed typo (WouterJ) -- `678224e `_ #3808 Fixed broken link in "Handling Authentication Failure" (stacyhorton) - -April, 2014 ------------ - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `322972e `_ #3803 [Book][Validation] configuration examples for the GroupSequenceProvider (xabbuh) -- `9e129bc `_ #3752 [Console] Add documentation for QuestionHelper (romainneutron) -- `64a924d `_ #3756 [WCM][Console] Add Process Helper documentation (romainneutron) -- `d4ca16a `_ #3743 Improve examples in parent services (WouterJ) -- `be4b9d3 `_ #3729 Added documentation for the new ``PropertyAccessor::isReadable()`` and ``isWritable()`` methods (webmozart) -- `70a3893 `_ #3774 [Book][Internals] add description for the kernel.finish_request event (xabbuh) -- `1934720 `_ #3461 [Form] Deprecated max_length and pattern options (stefanosala) -- `d611e77 `_ #3701 [Serializer] add documentation for serializer callbacks (cordoval) -- `80c645c `_ #3719 Fixed event listeners priority (tony-co) -- `c062d81 `_ #3469 [Validator] - EmailConstraint reference (egulias) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `f801e2e `_ #3805 Add missing autocomplete argument in askAndValidate method (ifdattic) -- `a81d367 `_ #3786 replaceArguments should be setArguments (RobinvdVleuten) -- `33b64e1 `_ #3788 Fix link for StopwatchEvent class (rpg600) -- `2ebabfb `_ #3792 Update commands_as_services.rst (mimol91) -- `529d4ce `_ #3761 buildViewBottomUp has been renamed to finishView (Nyholm) -- `d743139 `_ #3768 the Locale component does not have elements tagged with @api (xabbuh) -- `2b8e44d `_ #3747 Fix Image constraint class and validator link (weaverryan) -- `fa362ca `_ #3741 correct RuntimeException reference (shieldo) -- `d92545e `_ #3734 [book] [testing] fixed the path of the phpunit.xml file (javiereguiluz) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `136f98c `_ #3784 [Expression Langage] be consistent in "print/print out" uses (mickaelandrieu) -- `1094a13 `_ #3807 Added some exceptions to the method order in CS (stof) -- `55442b5 `_ #3800 Fixed another blockquote rendering issue (WouterJ) -- `969fd71 `_ #3785 ensure that destination directories don't exist before creating them (xabbuh) -- `79322ff `_ #3799 Fix list to not render in a block quote (WouterJ) -- `1a6f730 `_ #3793 language tweak for the tip introduced in #3743 (xabbuh) -- `dda9e88 `_ #3778 Adding information on internal reverse proxy (tcz) -- `d36bbd9 `_ #3765 [WIP] make headlines consistent with our standards (xabbuh) -- `daa81a0 `_ #3766 [Book] add note about services and the service container in the form cha... (xabbuh) -- `4529858 `_ #3767 [Book] link to the bc promise in the stable API description (xabbuh) -- `a5471b3 `_ #3775 Fixed variable naming (peterrehm) -- `703c2a6 `_ #3772 [Cookbook][Sessions] some language improvements (xabbuh) -- `3d30b56 `_ #3773 modify Symfony CMF configuration values in the build process so that the... (xabbuh) -- `cfd6d7c `_ #3758 [Book][Routing] Fixed typo on PHP version of a route definition (saro0h) -- `cedfdce `_ #3757 Fixed a typo in the request formats configuration page (gquemener) -- `6bd134c `_ #3754 ignore more files and directories which are created when building the documentation (xabbuh) -- `610462e `_ #3755 [Cookbook][Security] Firewall resitrction tweaks, fix markup, add to toc (xabbuh) -- `0a21718 `_ #3695 Firewall backport (weaverryan) -- `54d6a9e `_ #3736 [book] Misc. routing fixes (javiereguiluz) -- `f149dcf `_ #3739 [book] [forms] misc. fixes and tweaks (javiereguiluz) -- `ce582ec `_ #3735 [book] [controller] fixed the code of a session sample code (javiereguiluz) -- `499ba5c `_ #3733 [book] [validation] fixed typos (javiereguiluz) -- `4d0ff8f `_ #3732 Update routing.rst. Explain using url() v. path(). (ackerman) -- `44c6273 `_ #3727 Added a note about inlined private services (javiereguiluz) - -March, 2014 ------------ - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `3b640aa `_ #3644 made some small addition about our BC promise and semantic versioning (fabpot) -- `2d1ecd9 `_ #3525 Update file_uploads.rst (juanmf) -- `b1e8f56 `_ #3368 The host parameter has to be in defaults, not requirements (MarieMinasyan) -- `b34fb64 `_ #3619 [Validator] Uuid constraint reference (colinodell) -- `d7027c0 `_ #3418 [Validation] Add "hasser" support (bicpi) -- `4fd5fc1 `_ #3539 [Stopwatch] Describe retrieval of StopwatchEvent (jochenvdv) -- `1908a15 `_ #3696 [Console] Added standalone PSR-3 compliant logger (dunglas) -- `c75b1a7 `_ #3621 [Console] Command as service (gnugat) -- `00a462a `_ minor #3658 Fix PSR coding standards error (ifdattic) -- `acf255d `_ #3328 [WIP] Travis integration (WouterJ) -- `450146e `_ #3681 Enhanced Firewall Restrictions docs (danez) -- `3e7028d `_ #3659 [Internals] Complete notification description for kernel.terminate (bicpi) -- `db3cde7 `_ #3124 Add note about the property attribute (Property Accessor) (raziel057) -- `5965ec8 `_ #3420 [Cookbook][Configuration] add configuration cookbook handlig parameters in Configurator class (cordoval) -- `dcf8e6e `_ #3402 Added documentation about new requests formats configuration (gquemener) -- `a1050eb `_ #3411 [Cookbook][Dynamic Form Modification] Add AJAX sample (bicpi) -- `842fd30 `_ #3683 [TwigBundle] Add documentation about generating absolute URL with the asset function (romainneutron) -- `fc1576a `_ #3664 [Process] Add doc for ``Process::disableOutput`` and ``Process::enableOutput`` (romainneutron) -- `3731e2e `_ #3686 Documentation of the new PSR-4 class loader. (derrabus) -- `5b915c2 `_ #3629 Added documentation for translation:debug (florianv) -- `6951460 `_ #3601 Added documentation for missing ctype extension (slavafomin) -- `df63740 `_ #3627 added docs for the new Table console helper (fabpot) -- `96bd81b `_ #3626 added documentation for the new Symfony 2.5 progress bar (fabpot) -- `b02c16a `_ #3565 added information on AuthenticationFailureHandlerInterface (samsamm777) -- `2657ee7 `_ #3597 Document how to create a custom type guesser (WouterJ) -- `5ad1599 `_ #3577 Development of custom error pages is impractical if you need to set kernel.debug=false (mpdude) -- `3f4b319 `_ #3610 [HttpFoundation] Add doc for ``Request::getContent()`` method (bicpi) -- `56bc266 `_ #3589 Finishing the Templating component docs (WouterJ) -- `d881181 `_ #3588 Documented all form variables (WouterJ) -- `5cda1c7 `_ #3311 Use KernelTestCase instead of WebTestCase for testing code only requiring the Container (johnkary) -- `e96e12d `_ #3234 [Cookbook] New cookbok: How to use the Cloud to send Emails (bicpi) -- `d5d64ce `_ #3436 [Reference][Form Types] Add missing docs for "action" and "method" option (bicpi) -- `3df34af `_ #3490 Tweaking Doctrine book chapter (WouterJ) -- `b9608a7 `_ #3594 New Data Voter Article (continuation) (weaverryan) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `cad38ae `_ #3721 tweaks to the Console logger (xabbuh) -- `06c56c1 `_ #3709 [Components][Security] Fix #3708 (bicpi) -- `aadc61d `_ #3707 make method supportsClass() in custom voter compatible with the interface's documentation (xabbuh) -- `65150f9 `_ #3637 Update render_without_controller.rst (94noni) -- `9fcccc7 `_ #3634 Fix goal of “framework.profiler.only_exceptions“ option which profile on each exceptions on controller (not only 500) (stephpy) -- `9dd8d96 `_ #3689 Fix cache warmer description (WouterJ) -- `6221f35 `_ #3671 miss extends keyword in define BlogController class (ghanbari) -- `4ce7a15 `_ #3543 Fix the definition of customizing form's global errors. (mtrojanowski) -- `5d4a3a4 `_ #3343 [Testing] Fix phpunit test dir paths (bicpi) -- `badaae7 `_ #3622 [Components][Routing] Fix addPrefix() sample code (bicpi) -- `de0a5e1 `_ #3665 [Cookbook][Test] fix sample code (inalgnu) -- `4ef746a `_ #3614 [Internals] Fix Profiler:find() arguments (bicpi) -- `0c41762 `_ #3600 [Security][Authentication] Fix instructions for creating password encoders (bicpi) -- `0ab1f24 `_ #3593 Clarified Default and ClassName groups (WouterJ) -- `178984b `_ #3648 [Routing] Remove outdated tip about sticky locale (bicpi) -- `fc28453 `_ #3039 use DebugClassLoader class from Decomponent instead of the one from ... (xabbuh) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `abca098 `_ #3726 Minor tweaks after merging #3644 by @stof and @xabbuh (weaverryan) -- `d16be31 `_ #3725 Minor tweaks related to #3368 (weaverryan) -- `aa9bb25 `_ #3636 Update security.rst (nomack84) -- `78425c6 `_ #3722 add "Commands as Services" chapter to the cookbook's map (xabbuh) -- `9f26da8 `_ #3720 [#3539] A backport of a sentence - the parts that apply to 2.3 (weaverryan) -- `4b611d6 `_ #3717 [master] Fixed versionadded blocks (WouterJ) -- `5a3ba1b `_ #3715 change variable name to a better fitting one (xabbuh) -- `499eb6c `_ #3714 [2.4] Versionadded consistency (WouterJ) -- `e7580c0 `_ #3713 Updated versionadded directives to use "introduced" (WouterJ) -- `e15afe0 `_ #3711 Simplified the Travis configuration (stof) -- `db1cda5 `_ #3700 [Cookbook][Security] Firewall restrictions tweaks (xabbuh) -- `5035837 `_ #3706 Add support for nginx (guiditoito) -- `00a462a `_ #3658 Fix PSR coding standards error (ifdattic) -- `868de1e `_ #3698 Dynamic form modification cookbook: Fix inclusion of code (michaelperrin) -- `15a9d25 `_ #3697 [Console] Change Command namespaces (dunglas) -- `41b2eb8 `_ #3693 Tweak to Absolute URL generation (weaverryan) -- `bd473db `_ #3563 Add another tip to setup permissions (tony-co) -- `67129b1 `_ #3611 [Reference][Forms] add an introductory table containing all options of the basic form type (xabbuh) -- `fd8f7ae `_ #3694 fix the referenced documents names (xabbuh) -- `d617011 `_ #3657 Fix typos, remove trailing whitespace. (ifdattic) -- `1b4f6a6 `_ #3656 Minimize horizontal scrolling, add missing characters, remove trailing whitespace. (ifdattic) -- `7c0c5d1 `_ #3653 Http cache validation rewording (weaverryan) -- `0fb2c5f `_ #3651 [Reference][Forms] remove the label_attr option which is not available in the button type (xabbuh) -- `69ac21b `_ #3642 Fixed some typos and formatting issues (javiereguiluz) -- `93c35d0 `_ #3641 Added some examples to the "services as parameters" section (javiereguiluz) -- `12a6676 `_ #3640 [minor] fixed one typo and one formatting issue (javiereguiluz) -- `9967b0c `_ #3638 [#3116] Fixing wrong table name - singular is used elsewhere (weaverryan) -- `4fbf1cd `_ #3635 [QuickTour] close opened literals (xabbuh) -- `27b3410 `_ #3692 [Book][Translations] fixing a code block (xabbuh) -- `2192c32 `_ #3650 Fixing some build errors (xabbuh) -- `fa3f531 `_ #3677 [Reference][Forms] Remove variables section from tables (xabbuh) -- `cd6d1de `_ #3676 remove unnecessary code block directive (xabbuh) -- `07822b8 `_ #3675 add missing code block directive (xabbuh) -- `739f43f `_ #3669 Fixed syntax highlighting (rvanlaarhoven) -- `1f384bc `_ #3631 Added documentation for message option of the ``True`` constraint (naitsirch) -- `f6a41b9 `_ #3630 Minor tweaks to form action/method (weaverryan) -- `ae755e0 `_ #3628 Added anchor for permissions (WouterJ) -- `6380113 `_ #3667 Update index.rst (NAYZO) -- `97ef2f7 `_ #3566 Changes ACL permission setting hints (MicheleOnGit) -- `9f7d742 `_ #3654 [Cookbook][Security] Fix VoterInterface signature (bicpi) -- `0a65b6f `_ #3608 [Reference][Forms] add versionadded directive for multiple option of file type (xabbuh) -- `e34204e `_ #3605 Fixed a plural issue (benjaminpaap) -- `e7d5a45 `_ #3599 [CHANGELOG] fix reference to contributing docs (xabbuh) -- `3582bf1 `_ #3598 add changelog to hidden toctree (xabbuh) -- `58b7f96 `_ #3596 [HTTP Cache] Validation model: Fix header name (bicpi) -- `6d1378e `_ #3592 Added a tip about hardcoding URLs in functional tests (javiereguiluz) -- `04cf9f8 `_ #3595 Collection of fixes and improvements (bicpi) -- `2ed0943 `_ #3645 Adjusted the BC rules to be consistent (stof) -- `664a0be `_ #3633 Added missing PHP syntax coloration (DerekRoth) -- `1714a31 `_ #3585 Use consistent method chaining in BlogBundle sample application (ockcyp) -- `cb61f4f `_ #3581 Add missing hyphen in HTTP Fundamentals page (ockcyp) - -February, 2014 --------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `9dcf467 `_ #3613 Javiereguiluz revamped quick tour (weaverryan) -- `89c6f1d `_ #3439 [Review] Added detailed Backwards Compatibility Promise text (webmozart) -- `0029408 `_ #3558 Created Documentation CHANGELOG (WouterJ) -- `f6dd678 `_ #3548 Update forms.rst (atmosf3ar) -- `9676f2c `_ #3523 [Components][EventDispatcher] describe that the event name and the event dispatcher are passed to even... (xabbuh) -- `5c367b4 `_ #3517 Fixed OptionsResolver component docs (WouterJ) -- `527c8b6 `_ #3496 Added a section about using named assets (vmattila) -- `8ccfe85 `_ #3491 Added doc for named encoders (tamirvs) -- `46377b2 `_ #3486 Documenting createAccessDeniedException() method (klaussilveira) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `5c4336a `_ #3570 Callback: [Validator, validate] expects validate to be static (nixilla) -- `5c367b4 `_ #3517 Fixed OptionsResolver component docs (WouterJ) -- `adcbb5d `_ #3615 Fixes to cookbook/doctrine/registration_form.rst (Crushnaut) -- `a21fb26 `_ #3559 Remove reference to copying parameters.yml from Git cookbook (pwaring) -- `de71a51 `_ #3551 [Cookbook][Dynamic Form Modification] Fix sample code (rybakit) -- `143db2f `_ #3550 Update introduction.rst (taavit) -- `384538b `_ #3549 Fixed createPropertyAccessorBuilder usage (antonbabenko) -- `642e776 `_ #3544 Fix build errors (xabbuh) -- `d275302 `_ #3541 Update generic_event.rst (Lumbendil) -- `819949c `_ #3537 Add missing variable assignment (colinodell) -- `d7e8262 `_ #3535 fix form type name. (yositani2002) -- `821af3b `_ #3493 Type fix in remove.rst (weaverryan) -- `003230f `_ #3530 Update form_customization.rst (dczech) -- `a43f15a `_ #3519 [Book][Service Container] Fix syntax highlighting (iamdto) -- `86e02c6 `_ #3514 Fixed some small typos in code example (RobinvdVleuten) -- `696313c `_ #3513 [Component-DI] Fixed typo (saro0h) -- `27dcebd `_ #3509 Fix typo: side.bar.twig => sidebar.twig (ifdattic) -- `0dc8c26 `_ #3507 Fix a typo (missing `````) in ``:doc:`` link (ifdattic) -- `272197b `_ #3504 fix include directive so that the contents are really included (xabbuh) -- `e385d28 `_ #3503 file extension correction xfliff to xliff (nixilla) -- `6d34aa6 `_ #3478 Update custom_password_authenticator.rst (piotras-s) -- `a171700 `_ #3477 Api key user provider should use "implements" instead of "extends" (skowi) -- `7fe0de3 `_ #3475 Fixed doc for framework.session.cookie_lifetime refrence. (tyomo4ka) -- `8155e4c `_ #3473 Update proxy_examples.rst (AZielinski) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `0928249 `_ #3568 Update checkbox_compound.rst.inc (joshuaadickerson) -- `38def3b `_ #3567 Update checkbox_compound.rst.inc (joshuaadickerson) -- `15d8ab8 `_ #3553 Minimize horizontal scrolling in code blocks to improve readability (ifdattic) -- `5120863 `_ #3547 Update acl.rst (iqfoundry) -- `b7ac326 `_ #3557 Minimize horizontal scrolling in code block to improve readability (ifdattic) -- `d974c77 `_ #3556 Fix PSR error (ifdattic) -- `f4bb017 `_ #3555 Wrap variables in {} for safer interpolation (ifdattic) -- `5f02bca `_ #3552 Fix typos (ifdattic) -- `6e32c47 `_ #3546 Fix README: contributions should be based off 2.3 or higher (colinodell) -- `ffa8f76 `_ #3545 Example of getting entity managers directly from the container (colinodell) -- `6a2a55b `_ #3579 Fix build errors (xabbuh) -- `dce2e23 `_ #3532 Added tip for Entity Listeners (slavafomin) -- `73adf8b `_ #3528 Clarify service parameters usages (WouterJ) -- `7e75b64 `_ #3533 Moving the new named algorithms into their own cookbook entry (weaverryan) -- `f634600 `_ #3531 Remove horizontal scrolling in code block (ifdattic) -- `9ba4fa7 `_ #3527 Changes to components domcrawler (ifdattic) -- `8973c81 `_ #3526 Changes for Console component (ifdattic) -- `6848bed `_ #3538 Rebasing #3518 (weaverryan) -- `c838df8 `_ #3511 [Component-DI] Removed useless else statement in code example (saro0h) -- `1af6742 `_ #3510 add empty line (lazyants) -- `1131247 `_ #3508 Add 'in XML' for additional clarity (ifdattic) -- `a650b93 `_ #3506 Nykopol overriden options (weaverryan) -- `ab10035 `_ #3505 replace Akamaï with Akamai (xabbuh) -- `7f56c20 `_ #3501 [Security] Fix markup (tyx) -- `80a90ba `_ #3500 Minimize horizontal scrolling in code blocks (improve readability) (ifdattic) -- `e5bc4ea `_ #3498 Remove second empty data (xabbuh) -- `d084d87 `_ #3485 [Cookbook][Assetic] Fix "javascripts" tag name typo (bicpi) -- `3250aba `_ #3481 Fix code block (minimise horizontal scrolling), typo in yaml (ifdattic) - -January, 2014 -------------- - -New Documentation -~~~~~~~~~~~~~~~~~ - -- `d52f3f8 `_ #3454 [Security] Add host option (ghostika) -- `11e079b `_ #3446 [WCM] Documented deprecation of the apache router. (jakzal) -- `0a0bf4c `_ #3437 Add info about callback in options resolver (marekkalnik) -- `6db5f23 `_ #3426 New Feature: Change the Default Command in the Console component (danielcsgomes) -- `6b3c424 `_ #3428 Translation - Added info about JsonFileLoader added in 2.4 (singles) - -Fixed Documentation -~~~~~~~~~~~~~~~~~~~ - -- `fb22fa0 `_ #3456 remove duplicate label (xabbuh) -- `a87fe18 `_ #3470 Fixed typo (danielcsgomes) -- `c205bc6 `_ #3468 enclose YAML string with double quotes to fix syntax highlighting (xabbuh) -- `89963cc `_ #3463 Fix typos in cookbook/testing/database (ifdattic) -- `e0a52ec `_ #3460 remove confusing outdated note on interactive rebasing (xabbuh) -- `6831b13 `_ #3455 [Contributing][Code] fix indentation so that the text is rendered properly (xabbuh) -- `ea5816f `_ #3433 [WIP][Reference][Form Types] Update "radio" form type (bicpi) -- `42c80d1 `_ #3448 Overridden tweak (weaverryan) -- `bede4c3 `_ #3447 Fix error in namespace when use TokenInterface (joanteixi) -- `d9d7c58 `_ #3444 Fix issue #3442 (ifdattic) -- `a6ad607 `_ #3441 [Expression]Change title 'Accessing Public Methods' (Pyrech) -- `9e2e64b `_ #3427 Removed code references to Symfony Standard Distribution (danielcsgomes) -- `3c2c5fc `_ #3435 Update custom_password_authenticator.rst (boardyuk) -- `26b8146 `_ #3415 [#3334] the data_class option was not introduced in 2.4 (xabbuh) -- `0b2a491 `_ #3414 add missing code-block directive (xabbuh) -- `4988118 `_ #3432 [Reference][Form Types] Add "max_length" option in form type (nykopol) -- `26a7b1b `_ #3423 [Session Configuration] add clarifying notes on session save handler proxies (cordoval) -- `f2f5e9a `_ #3421 [Contributing] Cleaning the "contributing patch" page a bit (lemoinem) - -Minor Documentation Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- `f285d93 `_ #3451 some language tweaks (AE, third-person perspective) (xabbuh) -- `b9bbe5d `_ #3499 Fix YAML syntax highlight + remove trailing whitespace (ifdattic) -- `2b7e0f6 `_ #3497 Fix highlighting (WouterJ) -- `2746067 `_ #3472 Fixed `````versionadded````` inconsistencies in Symfony 2.5+ (danielcsgomes) -- `a535ae0 `_ #3471 Fixed `````versionadded````` inconsistencies in Symfony 2.3 (danielcsgomes) -- `f077a8e `_ #3465 change wording in versionadded example to be consistent with what we use... (xabbuh) -- `f9f7548 `_ #3462 Replace ... with etc (ifdattic) -- `65efcc4 `_ #3445 [Reference][Form Types] Add missing (but existing) options to "form" type (bicpi) -- `1d1b91d `_ #3431 [Config] add cautionary note on ini file loader limitation (cordoval) -- `f2eaf9b `_ #3419 doctrine file upload example uses dir -- caution added (cordoval) -- `72b53ad `_ #3404 [#3276] Trying to further clarify the session storage directory details (weaverryan) -- `67b7bbd `_ #3413 [Cookbook][Bundles] improve explanation of code block for bundle removal (cordoval) -- `7c5a914 `_ #3369 Indicate that Group Sequence Providers can use YAML (karptonite) -- `1e0311e `_ #3416 add empty_data option where required option is used (xabbuh) -- `2be3f52 `_ #3422 [Cookbook][Custom Authentication Provider] add a note of warning for when forbidding anonymous users (cordoval) -- `e255de9 `_ #3429 [Reference][Form Types] Document "with_minutes" time/datetime option (bicpi) diff --git a/index.rst b/index.rst index 5d86033a0cb..7ff07db698c 100644 --- a/index.rst +++ b/index.rst @@ -3,11 +3,6 @@ Symfony Documentation ===================== -.. toctree:: - :hidden: - - changelog - Quick Tour ---------- diff --git a/setup/new_project_svn.rst b/setup/new_project_svn.rst deleted file mode 100644 index 937fc37d1ec..00000000000 --- a/setup/new_project_svn.rst +++ /dev/null @@ -1,138 +0,0 @@ -.. index:: - single: Set Up; Subversion - -.. _how-to-create-and-store-a-symfony2-project-in-subversion: - -How to Create and Store a Symfony Project in Subversion -======================================================= - -.. tip:: - - This entry is specifically about Subversion, and based on principles found - in :doc:`/setup/new_project_git`. - -Once you've read through :doc:`/page_creation` and become familiar with -using Symfony, you'll no-doubt be ready to start your own project. The -preferred method to manage Symfony projects is using `Git`_ but some prefer -to use `Subversion`_ which is totally fine!. In this article, you'll learn how -to manage your project using `SVN`_ in a similar manner you would do with -`Git`_. - -.. tip:: - - This is **a** method to tracking your Symfony project in a Subversion - repository. There are several ways to do and this one is simply one that - works. - -The Subversion Repository -------------------------- - -For this article it's assumed that your repository layout follows the -widespread standard structure: - -.. code-block:: text - - myproject/ - branches/ - tags/ - trunk/ - -.. tip:: - - Most Subversion hosting should follow this standard practice. This - is the recommended layout in `Version Control with Subversion`_ and the - layout used by most free hosting (see :ref:`svn-hosting`). - -Initial Project Setup ---------------------- - -To get started, you'll need to download Symfony and get the basic Subversion setup. -First, download and get your Symfony project running by following the -:doc:`Installation ` article. - -Once you have your new project directory and things are working, follow along -with these steps: - -#. Checkout the Subversion repository that will host this project. Suppose - it is hosted on `Google code`_ and called ``myproject``: - - .. code-block:: terminal - - $ svn checkout http://myproject.googlecode.com/svn/trunk myproject - -#. Copy the Symfony project files in the Subversion folder: - - .. code-block:: terminal - - $ mv Symfony/* myproject/ - -#. Now, set the ignore rules. Not everything *should* be stored in your Subversion - repository. Some files (like the cache) are generated and others (like - the database configuration) are meant to be customized on each machine. - This makes use of the ``svn:ignore`` property, so that specific files can - be ignored. - - .. code-block:: terminal - - $ cd myproject/ - $ svn add --depth=empty app var var/cache var/log app/config web - - $ svn propset svn:ignore "vendor" . - $ svn propset svn:ignore "bootstrap*" var/ - $ svn propset svn:ignore "parameters.yml" app/config/ - $ svn propset svn:ignore "*" var/cache/ - $ svn propset svn:ignore "*" var/log/ - $ svn propset svn:ignore "*" var/sessions/ - - $ svn propset svn:ignore "bundles" web - - $ svn ci -m "commit basic Symfony ignore list (vendor, var/bootstrap*, app/config/parameters.yml, var/cache/*, var/log/*, public/bundles)" - -#. The rest of the files can now be added and committed to the project: - - .. code-block:: terminal - - $ svn add --force . - $ svn ci -m "add basic Symfony Standard 3.X.Y" - -That's it! Since the ``app/config/parameters.yml`` file is ignored, you can -store machine-specific settings like database passwords here without committing -them. The ``parameters.yml.dist`` file *is* committed, but is not read by -Symfony. And by adding any new keys you need to both files, new developers -can quickly clone the project, copy this file to ``parameters.yml``, customize -it, and start developing. - -At this point, you have a fully-functional Symfony project stored in your -Subversion repository. The development can start with commits in the Subversion -repository. - -You can continue to follow along with the :doc:`/page_creation` article -to learn more about how to configure and develop inside your application. - -.. include:: _vendor_deps.rst.inc - -.. _svn-hosting: - -Subversion Hosting Solutions ----------------------------- - -The biggest difference between `Git`_ and `SVN`_ is that Subversion *needs* a -central repository to work. You then have several solutions: - -- Self hosting: create your own repository and access it either through the - filesystem or the network. To help in this task you can read `Version Control - with Subversion`_. - -- Third party hosting: there are a lot of serious free hosting solutions - available like `GitHub`_, `Google code`_, `SourceForge`_ or `Gna`_. Some of them offer - Git hosting as well. - -.. _`Git`: http://git-scm.com/ -.. _`SVN`: http://subversion.apache.org/ -.. _`Subversion`: http://subversion.apache.org/ -.. _`Symfony Standard Edition`: https://symfony.com/download -.. _`Version Control with Subversion`: http://svnbook.red-bean.com/ -.. _`GitHub`: https://github.com/ -.. _`Google code`: http://code.google.com/hosting/ -.. _`SourceForge`: http://sourceforge.net/ -.. _`Gna`: http://gna.org/ From aec8b0ee7c0ea89f93e230520fc64f37b3c096b7 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 23 Nov 2017 17:21:15 +0100 Subject: [PATCH 0123/2437] Tweaks --- translation.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/translation.rst b/translation.rst index 74e11e5bfc3..7cd4ca01a47 100644 --- a/translation.rst +++ b/translation.rst @@ -48,17 +48,20 @@ to learn even more. Overall, the process has several steps: .. _translation-configuration: -Configuration -------------- +Installation +------------ -In a :doc:`Symfony Flex ` based application, run this command to -add translation support: +In applications using :doc:`Symfony Flex `, run this command to +install the translator before using it: .. code-block:: terminal $ composer require translator -This command creates an initial config file where you can define the default +Configuration +------------- + +The previous creates an initial config file where you can define the default locale of the app and the :ref:`fallback locales ` used when Symfony can't find some translation: From 2b0236f329c9d44bfa83b5e53e2d4abeabf1d4a2 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 23 Nov 2017 20:12:03 -0500 Subject: [PATCH 0124/2437] updating the rest of the Doctrine docs --- doctrine.rst | 62 +++++++-- doctrine/associations.rst | 158 ++++++++++++++++++----- doctrine/custom_dql_functions.rst | 6 +- doctrine/dbal.rst | 80 +++--------- doctrine/event_listeners_subscribers.rst | 7 +- doctrine/lifecycle_callbacks.rst | 4 +- doctrine/mongodb_session_storage.rst | 155 +--------------------- doctrine/multiple_entity_managers.rst | 11 +- doctrine/pdo_session_storage.rst | 95 ++++---------- doctrine/registration_form.rst | 89 +++---------- doctrine/resolve_target_entity.rst | 6 +- doctrine/reverse_engineering.rst | 10 +- security/entity_provider.rst | 3 +- 13 files changed, 279 insertions(+), 407 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index 1386f336a50..5eba0395996 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -23,7 +23,7 @@ code: .. code-block:: terminal - composer require orm maker + composer require doctrine maker Configuring the Database ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -36,7 +36,7 @@ The database connection information is stored as an environment variable called # .env # customize this line! - DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?charset=utf8mb4&serverVersion=5.7" + DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name" # to use sqlite: # DATABASE_URL="sqlite://%kernel.project_dir%/var/app.db" @@ -48,6 +48,9 @@ database for you: $ php bin/console doctrine:database:create +There are more optiosn in ``config/packages/doctrine.yaml`` that you can configure, +including your ``server_version`` (e.g. 5.7 if you're using MySQL 5.7), which may +affect how Doctrine functions. .. tip:: @@ -75,7 +78,6 @@ You now have a new ``src/Entity/Product.php`` file:: /** * @ORM\Entity(repositoryClass="App\Repository\ProductRepository") - * @ORM\Table() */ class Product { @@ -140,7 +142,7 @@ in the database. This is usually done with annotations: .. code-block:: yaml - # src/Resources/config/doctrine/Product.orm.yml + # config/doctrine/Product.orm.yml App\Entity\Product: type: entity id: @@ -159,7 +161,7 @@ in the database. This is usually done with annotations: .. code-block:: xml - + render('product/show.html.twig', ['product' => $product]); + // return $this->render('product/show.html.twig', ['product' => $product]); } Try it out! @@ -472,7 +476,40 @@ the :ref:`doctrine-queries` section. If the number of database queries is too high, the icon will turn yellow to indicate that something may not be correct. Click on the icon to open the - Symfony Profiler and see the exact queries that were executed. + Symfony Profiler and see the exact queries that were executed. If you don't + see the web debug toolbar, try running ``composer require profiler`` to install + it. + +Automatically Fetching Objects (ParamConverter) +----------------------------------------------- + +In many cases, you can use the `SensioFrameworkExtraBundle`_ to do the query +for you automatically! First, install the bundle in case you don't have it: + +.. code-block:: terminal + + $ composer require annotations + +Now, simplify your controller:: + + // src/Controller/ProductController.php + + use App\Entity\Product; + // ... + + /** + * @Route("/product/{id}", name="product_show") + */ + public function showAction(Product $product) + { + // use the Product! + // ... + } + +That's it! The bundle uses the ``{id}`` from the route to query for the ``Product`` +by the ``id`` column. If it's not found, a 404 page is generated. + +There are many more options you can use. Read more about the `ParamConverter`_. Updating an Object ------------------ @@ -692,14 +729,11 @@ Learn more .. _`Query Builder`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html .. _`Doctrine Query Language`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html .. _`Mapping Types Documentation`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#property-mapping -.. _`Property Mapping`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#property-mapping .. _`Reserved SQL keywords documentation`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#quoting-reserved-words -.. _`Creating Classes for the Database`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#creating-classes-for-the-database .. _`DoctrineMongoDBBundle`: https://symfony.com/doc/current/bundles/DoctrineMongoDBBundle/index.html -.. _`migrations`: https://symfony.com/doc/current/bundles/DoctrineMigrationsBundle/index.html .. _`DoctrineFixturesBundle`: https://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html -.. _`FrameworkExtraBundle documentation`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html -.. _`newer utf8mb4 character set`: https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html .. _`Transactions and Concurrency`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html .. _`DoctrineMigrationsBundle`: https://github.com/doctrine/DoctrineMigrationsBundle .. _`NativeQuery`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html +.. _`SensioFrameworkExtraBundle`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html +.. _`ParamConverter`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html diff --git a/doctrine/associations.rst b/doctrine/associations.rst index b9a0fd45569..318b907b72d 100644 --- a/doctrine/associations.rst +++ b/doctrine/associations.rst @@ -290,6 +290,14 @@ about your database, and instead *only* think about your objects. Instead of set the category's integer id onto ``Product``, you set the entire ``Category`` *object*. Doctrine takes care of the rest when saving. +.. sidebar:: Updating the Relationship from the Inverse Side + + Could you also call ``$category->setProducts()`` to set the relationship? Actually, + no! Earlier, you did *not* add a ``setProducts()`` method on ``Category``. That's + on purpose: you can *only* set data on the *owning* side of the relationship. In + other words, if you call ``$category->setProducts()`` only, that is *completely* + ignored when saving. For more details, see: `associations-inverse-side`_. + Fetching Related Objects ------------------------ @@ -330,24 +338,21 @@ the category (i.e. it's "lazily loaded"). Because we mapped the optiona ``OneToMany`` side, you can also query in the other direction:: - public function showProductsAction($categoryId) + public function showProductsAction($id) { $category = $this->getDoctrine() ->getRepository(Category::class) - ->find($categoryId); + ->find($id); $products = $category->getProducts(); // ... } -TODO TODO, STARTING HERE!!!!!!!!!!!!!!!!!! - -In this case, the same things occur: you first query out for a single ``Category`` -object, and then Doctrine makes a second query to retrieve the related ``Product`` -objects, but only once/if you ask for them (i.e. when you call ``getProducts()``). -The ``$products`` variable is an array of all ``Product`` objects that relate -to the given ``Category`` object via their ``category_id`` value. +In this case, the same things occur: you first query for a single ``Category`` +object. Then, only when (and if) you access the products, Doctrine makes a second +query to retrieve the related ``Product`` objects. This extra query can be avoided +by adding JOINs. .. sidebar:: Relationships and Proxy Classes @@ -357,7 +362,7 @@ to the given ``Category`` object via their ``category_id`` value. $product = $this->getDoctrine() ->getRepository(Product::class) - ->find($productId); + ->find($id); $category = $product->getCategory(); @@ -371,8 +376,8 @@ to the given ``Category`` object via their ``category_id`` value. actually need that data (e.g. until you call ``$category->getName()``). The proxy classes are generated by Doctrine and stored in the cache directory. - And though you'll probably never even notice that your ``$category`` - object is actually a proxy object, it's important to keep it in mind. + You'll probably never even notice that your ``$category`` object is actually + a proxy object. In the next section, when you retrieve the product and category data all at once (via a *join*), Doctrine will return the *true* ``Category`` @@ -381,7 +386,7 @@ to the given ``Category`` object via their ``category_id`` value. Joining Related Records ----------------------- -In the above examples, two queries were made - one for the original object +In the examples above, two queries were made - one for the original object (e.g. a ``Category``) and one for the related object(s) (e.g. the ``Product`` objects). @@ -397,34 +402,129 @@ following method to the ``ProductRepository`` class:: // src/Repository/ProductRepository.php public function findOneByIdJoinedToCategory($productId) { - $query = $this->getEntityManager() - ->createQuery( - 'SELECT p, c FROM App:Product p - JOIN p.category c - WHERE p.id = :id' - )->setParameter('id', $productId); - - try { - return $query->getSingleResult(); - } catch (\Doctrine\ORM\NoResultException $e) { - return null; - } + return $this->createQueryBuilder('p') + // p.category refers to the "category" property on product + ->innerJoin('p.category', 'c') + // selects all the category data to avoid the query + ->addSelect('c') + ->andWhere('p.id = :id') + ->setParameter('id', $productId) + ->getQuery() + ->getOneOrNullResult(); } +This will *still* return an array of ``Product`` objects. But now, when you call +``$product->getCategory()`` and use that data, no second query is made. + Now, you can use this method in your controller to query for a ``Product`` object and its related ``Category`` with just one query:: - public function showAction($productId) + public function showAction($id) { $product = $this->getDoctrine() ->getRepository(Product::class) - ->findOneByIdJoinedToCategory($productId); + ->findOneByIdJoinedToCategory($id); $category = $product->getCategory(); // ... } +.. _associations-inverse-side: + +Setting Information from the Inverse Side +----------------------------------------- + +So far, you've updated the relationship by calling ``$product->setCategory($category)``. +This is no accident: you *must* set the relationship on the *owning* side. The owning +side is always where the ``ManyToOne`` mapping is set (for a ``ManyToMany`` relation, +you can choose which side is the owning side). + +Does this means it's not possible to call ``$category->setProducts()``? Actually, +it *is* possible, by writing clever methods. First, instead of a ``setProducts()`` +method, create a ``addProduct()`` method:: + + // src/Entity/Category.php + + // ... + class Category + { + // ... + + public function addProduct(Product $product) + { + if ($this->products->contains($product)) { + return; + } + + $this->products[] = $product; + // set the *owning* side! + $product->setCategory($this); + } + } + +That's it! The *key* is ``$product->setCategory($this)``, which sets the *owning* +side. Now, when you save, the relationship *will* update in the database. + +What about *removing* a ``Product`` from a ``Category``? Add a ``removeProduct()`` +method:: + + // src/Entity/Category.php + + // ... + class Category + { + // ... + + public function removeProduct(Product $product) + { + $this->products->removeElement($product); + // set the owning side to null + $product->setCategory(null); + } + } + +To make this work, you *now* need to allow ``null`` to be passed to ``Product::setCategory()``: + +.. code-block:: diff + + // src/Entity/Product.php + + // ... + class Product + { + // ... + + - public function getCategory(): Category + + public function getCategory(): ?Category + // ... + + - public function setCategory(Category $category) + + public function setCategory(Category $category = null) + { + $this->category = $category; + } + } + +And that's it! Now, if you call ``$category->removeProduct($product)``, the ``category_id`` +on that ``Product`` will be set to ``null`` in the database. + +But, instead of setting the ``category_id`` to null, what if you want the ``Product`` +to be *deleted* if it becomes "orphaned" (i.e. without a ``Category``)? To choose +that behavior, use the `orphanRemoval`_ option inside ``Category``:: + + // src/Entity/Category.php + + // ... + + /** + * @ORM\OneToMany(targetEntity="App\Entity\Product", mappedBy="category", orphanRemoval=true) + */ + private $products; + +Thanks to this, if the ``Product`` is removed from the ``Category``, it will be +removed from the database entirely. + More Information on Associations -------------------------------- @@ -437,7 +537,7 @@ Doctrine's `Association Mapping Documentation`_. If you're using annotations, you'll need to prepend all annotations with ``@ORM\`` (e.g. ``@ORM\OneToMany``), which is not reflected in Doctrine's - documentation. You'll also need to include the ``use Doctrine\ORM\Mapping as ORM;`` - statement, which *imports* the ``ORM`` annotations prefix. + documentation. .. _`Association Mapping Documentation`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html +.. _`orphanRemoval`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#orphan-removal diff --git a/doctrine/custom_dql_functions.rst b/doctrine/custom_dql_functions.rst index e19c9a26eb6..e63e1437865 100644 --- a/doctrine/custom_dql_functions.rst +++ b/doctrine/custom_dql_functions.rst @@ -13,7 +13,7 @@ In Symfony, you can register your custom DQL functions as follows: .. code-block:: yaml - # app/config/config.yml + # config/packages/doctrine.yaml doctrine: orm: # ... @@ -28,7 +28,7 @@ In Symfony, you can register your custom DQL functions as follows: .. code-block:: xml - + - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('doctrine', array( - 'dbal' => array( - 'driver' => 'pdo_mysql', - 'dbname' => 'Symfony', - 'user' => 'root', - 'password' => null, - 'charset' => 'UTF8', - 'server_version' => '5.6', - ), - )); - -For full DBAL configuration options, or to learn how to configure multiple -connections, see :ref:`reference-dbal-configuration`. - -You can then access the Doctrine DBAL connection by accessing the -``database_connection`` service:: +You can then access the Doctrine DBAL connection by autowiring the ``Connection`` +object:: use Doctrine\DBAL\Driver\Connection; @@ -95,6 +49,8 @@ You can then access the Doctrine DBAL connection by accessing the } } +This will pass you the ``database_connection`` service. + Registering custom Mapping Types -------------------------------- @@ -106,7 +62,7 @@ mapping types, read Doctrine's `Custom Mapping Types`_ section of their document .. code-block:: yaml - # app/config/config.yml + # config/packages/doctrine.yaml doctrine: dbal: types: @@ -115,7 +71,7 @@ mapping types, read Doctrine's `Custom Mapping Types`_ section of their document .. code-block:: xml - + + loadFromExtension('doctrine', array( 'dbal' => array( 'mapping_types' => array( diff --git a/doctrine/event_listeners_subscribers.rst b/doctrine/event_listeners_subscribers.rst index 3340ea13997..acb98ac43d4 100644 --- a/doctrine/event_listeners_subscribers.rst +++ b/doctrine/event_listeners_subscribers.rst @@ -207,8 +207,7 @@ to the tag like so: .. code-block:: yaml services: - my.listener: - class: App\EventListener\SearchIndexer + App\EventListener\SearchIndexer: tags: - { name: doctrine.event_listener, event: postPersist, lazy: true } @@ -219,7 +218,7 @@ to the tag like so: xmlns:doctrine="http://symfony.com/schema/dic/doctrine"> - + @@ -230,7 +229,7 @@ to the tag like so: use App\EventListener\SearchIndexer; $container - ->register('my.listener', SearchIndexer::class) + ->autowire(SearchIndexer::class) ->addTag('doctrine.event_listener', array('event' => 'postPersist', 'lazy' => 'true')) ; diff --git a/doctrine/lifecycle_callbacks.rst b/doctrine/lifecycle_callbacks.rst index 6f7bf14a6e4..42344c8098d 100644 --- a/doctrine/lifecycle_callbacks.rst +++ b/doctrine/lifecycle_callbacks.rst @@ -44,7 +44,7 @@ the current date, only when the entity is first persisted (i.e. inserted): .. code-block:: yaml - # src/Resources/config/doctrine/Product.orm.yml + # config/doctrine/Product.orm.yml App\Entity\Product: type: entity # ... @@ -53,7 +53,7 @@ the current date, only when the entity is first persisted (i.e. inserted): .. code-block:: xml - + - - - - - - - - - - - - - mongodb://%mongodb_username%:%mongodb_password%@%mongodb_host%:27017 - - - mongodb://%mongodb_host%:27017 - - - - mongo_client - %mongo.session.options% - - - - .. code-block:: php - - use Symfony\Component\DependencyInjection\Reference; - use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; - - $container->loadFromExtension('framework', array( - 'session' => array( - // ... - 'handler_id' => 'session.handler.mongo', - 'cookie_lifetime' => 2592000, // optional, it is set to 30 days here - 'gc_maxlifetime' => 2592000, // optional, it is set to 30 days here - ), - )); - - $container->register('mongo_client', \MongoClient::class) - ->setArguments(array( - // if using a username and password - array('mongodb://%mongodb_username%:%mongodb_password%@%mongodb_host%:27017'), - // if not using a username and password - array('mongodb://%mongodb_host%:27017'), - )); - - $container->register('session.handler.mongo', MongoDbSessionHandler::class) - ->setArguments(array( - new Reference('mongo_client'), - '%mongo.session.options%', - )); - -The parameters used above should be defined somewhere in your application, often in your main -parameters configuration: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/parameters.yml - parameters: - # ... - mongo.session.options: - database: session_db # your MongoDB database name - collection: session # your MongoDB collection name - mongodb_host: 1.2.3.4 # your MongoDB server's IP - mongodb_username: my_username - mongodb_password: my_password - - .. code-block:: xml - - - - - - - - session_db - - session - - - 1.2.3.4 - my_username - my_password - - - - .. code-block:: php - - use Symfony\Component\DependencyInjection\Reference; - - $container->setParameter('mongo.session.options', array( - 'database' => 'session_db', // your MongoDB database name - 'collection' => 'session', // your MongoDB collection name - )); - $container->setParameter('mongodb_host', '1.2.3.4'); // your MongoDB server's IP - $container->setParameter('mongodb_username', 'my_username'); - $container->setParameter('mongodb_password', 'my_password'); +To see how to configure a similar handler, see :doc:`/doctrine/pdo_session_storage`. Setting Up the MongoDB Collection --------------------------------- -Because MongoDB uses dynamic collection schemas, you do not need to do anything to initialize your -session collection. However, you may want to add an index to improve garbage collection performance. -From the `MongoDB shell`_: +You do not need to do anything to initialize your session collection. However, you +may want to add an index to improve garbage collection performance. From the +`MongoDB shell`_: .. code-block:: javascript use session_db db.session.ensureIndex( { "expires_at": 1 }, { expireAfterSeconds: 0 } ) -.. _installed and configured a MongoDB server: http://docs.mongodb.org/manual/installation/ .. _MongoDB shell: http://docs.mongodb.org/v2.2/tutorial/getting-started-with-the-mongo-shell/ diff --git a/doctrine/multiple_entity_managers.rst b/doctrine/multiple_entity_managers.rst index fca2155f5c9..a7fa6ce29be 100644 --- a/doctrine/multiple_entity_managers.rst +++ b/doctrine/multiple_entity_managers.rst @@ -22,6 +22,7 @@ The following configuration code shows how you can configure two entity managers .. code-block:: yaml + # config/packages/doctrine.yaml doctrine: dbal: default_connection: default @@ -58,6 +59,7 @@ The following configuration code shows how you can configure two entity managers .. code-block:: xml + loadFromExtension('doctrine', array( 'dbal' => array( 'default_connection' => 'default', @@ -172,15 +175,17 @@ When working with multiple connections to create your databases: # Play only with "customer" connection $ php bin/console doctrine:database:create --connection=customer -When working with multiple entity managers to update your schema: +When working with multiple entity managers to generate migrations: .. code-block:: terminal # Play only with "default" mappings - $ php bin/console doctrine:schema:update --force + $ php bin/console doctrine:migrations:diff + $ php bin/console doctrine:migrations:migrate # Play only with "customer" mappings - $ php bin/console doctrine:schema:update --force --em=customer + $ php bin/console doctrine:migrations:diff --em=customer + $ php bin/console doctrine:migrations:migrate --em=customer If you *do* omit the entity manager's name when asking for it, the default entity manager (i.e. ``default``) is returned:: diff --git a/doctrine/pdo_session_storage.rst b/doctrine/pdo_session_storage.rst index e215bb31721..6ce018432bd 100644 --- a/doctrine/pdo_session_storage.rst +++ b/doctrine/pdo_session_storage.rst @@ -17,19 +17,22 @@ To use it, first register a new handler service: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml services: # ... Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler: - public: false arguments: - 'mysql:dbname=mydatabase' - { db_username: myuser, db_password: mypassword } + # If you're using Doctrine & want to re-use that connection, then: + # comment-out the above 2 lines and uncomment the line below + # - !service { class: PDO, factory: 'database_connection:getWrappedConnection' } + .. code-block:: xml - + register(PdoSessionHandler::class) + $storageDefinition = $container->autowire(PdoSessionHandler::class) ->setArguments(array( 'mysql:dbname=mydatabase', array('db_username' => 'myuser', 'db_password' => 'mypassword') @@ -67,7 +70,7 @@ Next, tell Symfony to use your service as the session handler: .. code-block:: yaml - # app/config/config.yml + # config/packages/doctrine.yaml framework: session: # ... @@ -75,7 +78,7 @@ Next, tell Symfony to use your service as the session handler: .. code-block:: xml - + @@ -83,7 +86,7 @@ Next, tell Symfony to use your service as the session handler: .. code-block:: php - // app/config/config.php + // config/packages/doctrine.php use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; // ... @@ -106,19 +109,18 @@ a second array argument to ``PdoSessionHandler``: .. code-block:: yaml - # app/config/config.yml + # config/services.yaml services: # ... Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler: - public: false arguments: - 'mysql:dbname=mydatabase' - { db_table: sessions, db_username: myuser, db_password: mypassword } .. code-block:: xml - + register(PdoSessionHandler::class) + $container->autowire(PdoSessionHandler::class) ->setArguments(array( 'mysql:dbname=mydatabase', array('db_table' => 'sessions', 'db_username' => 'myuser', 'db_password' => 'mypassword') @@ -168,60 +170,6 @@ These are parameters that you must configure: ``db_lifetime_col`` (default ``sess_lifetime``): The name of the lifetime column in your session table (INTEGER). - -Sharing your Database Connection Information --------------------------------------------- - -With the given configuration, the database connection settings are defined for -the session storage connection only. This is OK when you use a separate -database for the session data. - -But if you'd like to store the session data in the same database as the rest -of your project's data, you can use the connection settings from the -``parameters.yml`` file by referencing the database-related parameters defined there: - -.. configuration-block:: - - .. code-block:: yaml - - services: - # ... - - Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler: - public: false - arguments: - - 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%' - - { db_username: '%database_user%', db_password: '%database_password%' } - - .. code-block:: xml - - - - - - - mysql:host=%database_host%;port=%database_port%;dbname=%database_name% - - %database_user% - %database_password% - - - - - - .. code-block:: php - - // ... - $container->register(PdoSessionHandler::class) - ->setArguments(array( - 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%', - array('db_username' => '%database_user%', 'db_password' => '%database_password%') - )) - ; - .. _example-sql-statements: Preparing the Database to Store Sessions @@ -231,6 +179,19 @@ Before storing sessions in the database, you must create the table that stores the information. The following sections contain some examples of the SQL statements you may use for your specific database engine. +A great way to run this on production is to generate an empty migration, and then +add this SQL inside: + +.. code-block:: terminal + + $ php bin/console doctrine:migrations:generate + +Find the correct SQL below and put it inside that file. Then execute it with: + +.. code-block:: terminal + + $ php bin/console doctrine:migrations:migrate + MySQL ~~~~~ diff --git a/doctrine/registration_form.rst b/doctrine/registration_form.rst index 24b8941d8da..b423850ab2f 100644 --- a/doctrine/registration_form.rst +++ b/doctrine/registration_form.rst @@ -10,6 +10,12 @@ Creating a registration form is pretty easy - it *really* means just creating a form that will update some ``User`` model object (a Doctrine entity in this example) and then save it. +First, make sure you have all the dependencies you need installed: + +.. code-block:: terminal + + $ composer require doctrine form security + .. tip:: The popular `FOSUserBundle`_ provides a registration form, reset password @@ -271,14 +277,14 @@ encoder in the security configuration: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yml security: encoders: App\Entity\User: bcrypt .. code-block:: xml - + loadFromExtension('security', array( @@ -304,76 +310,20 @@ encoder in the security configuration: In this case the recommended ``bcrypt`` algorithm is used. If needed, check out the :ref:`user password encoding ` article. -.. note:: - - If you decide to NOT use annotation routing (shown above), then you'll - need to create a route to this controller: - - .. configuration-block:: - - .. code-block:: yaml - - # config/routes.yaml - user_registration: - path: /register - defaults: { _controller: AppBundle:Registration:register } - - .. code-block:: xml - - - - - - - AppBundle:Registration:register - - - - .. code-block:: php - - // config/routes.php - use Symfony\Component\Routing\RouteCollection; - use Symfony\Component\Routing\Route; - - $collection = new RouteCollection(); - $collection->add('user_registration', new Route('/register', array( - '_controller' => 'AppBundle:Registration:register', - ))); - - return $collection; - Next, create the template: -.. configuration-block:: - - .. code-block:: html+twig - - {# templates/registration/register.html.twig #} - - {{ form_start(form) }} - {{ form_row(form.username) }} - {{ form_row(form.email) }} - {{ form_row(form.plainPassword.first) }} - {{ form_row(form.plainPassword.second) }} - - - {{ form_end(form) }} - - .. code-block:: html+php - - +.. code-block:: html+twig - start($form) ?> - row($form['username']) ?> - row($form['email']) ?> + {# templates/registration/register.html.twig #} - row($form['plainPassword']['first']) ?> - row($form['plainPassword']['second']) ?> + {{ form_start(form) }} + {{ form_row(form.username) }} + {{ form_row(form.email) }} + {{ form_row(form.plainPassword.first) }} + {{ form_row(form.plainPassword.second) }} - - end($form) ?> + + {{ form_end(form) }} See :doc:`/form/form_customization` for more details. @@ -385,7 +335,8 @@ your database schema using this command: .. code-block:: terminal - $ php bin/console doctrine:schema:update --force + $ php bin/console doctrine:migrations:diff + $ php bin/console doctrine:migrations:migrate That's it! Head to ``/register`` to try things out! diff --git a/doctrine/resolve_target_entity.rst b/doctrine/resolve_target_entity.rst index 4bf4aba7566..c2563f7b4dd 100644 --- a/doctrine/resolve_target_entity.rst +++ b/doctrine/resolve_target_entity.rst @@ -112,7 +112,7 @@ about the replacement: .. code-block:: yaml - # app/config/config.yml + # config/packages/doctrine.yaml doctrine: # ... orm: @@ -122,7 +122,7 @@ about the replacement: .. code-block:: xml - + Date: Thu, 23 Nov 2017 20:18:28 -0500 Subject: [PATCH 0125/2437] tweaks thanks to @yceruto --- doctrine.rst | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index 5eba0395996..ada7af29348 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -130,12 +130,12 @@ in the database. This is usually done with annotations: private $id; /** - * @ORM\Column(type="string", length=100, nullable=false) + * @ORM\Column(type="string", length=100) */ private $name; /** - * @ORM\Column(type="decimal", scale=2, nullable=false) + * @ORM\Column(type="decimal", scale=2, nullable=true) */ private $price; } @@ -153,11 +153,10 @@ in the database. This is usually done with annotations: name: type: string length: 100 - nullable: false price: type: decimal scale: 2 - nullable: false + nullable: true .. code-block:: xml @@ -172,8 +171,8 @@ in the database. This is usually done with annotations: - - + + @@ -455,8 +454,8 @@ Once you have a repository object, you have many helper methods:: // query for multiple Product objects matching the name, ordered by price $products = $repository->findBy( - array('name' => 'Keyboard'), - array('price' => 'ASC') + ['name' => 'Keyboard'], + ['price' => 'ASC'] ); // find *all* Product objects @@ -584,6 +583,10 @@ But what if you need a more complex query? When you generated your entity with class ProductRepository extends ServiceEntityRepository { + public function __construct(RegistryInterface $registry) + { + parent::__construct($registry, Product::class); + } } When you fetch your repository (i.e. ``->getRepository(Product::class)``, it is @@ -598,6 +601,8 @@ a new method for this to your repository:: // ... class ProductRepository extends ServiceEntityRepository { + // ... + /** * @param $price * @return Product[] @@ -672,7 +677,7 @@ Or directly with SQL if you need to:: ORDER BY p.price ASC '; $stmt = $conn->prepare($sql); - $stmt->execute(array('price' => 10)); + $stmt->execute(['price' => 10]); // returns an array of arrays (i.e. a raw data set) return $stmt->fetchAll(); From 04603c7f497a885597240a91f3752c6efb7832a0 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 23 Nov 2017 20:20:53 -0500 Subject: [PATCH 0126/2437] Fixing build problems --- doctrine.rst | 4 ++-- security/entity_provider.rst | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/doctrine.rst b/doctrine.rst index ada7af29348..92875f9b562 100644 --- a/doctrine.rst +++ b/doctrine.rst @@ -636,7 +636,7 @@ write custom queries. Now, you can call this method on the repository:: // ... -If you're in a :ref:`services-constructor-injection`_, you can type-hint the +If you're in a :ref:`services-constructor-injection`, you can type-hint the ``ProductRepository`` class and inject it like normal. For more details, see the `Query Builder`_ Documentation from Doctrine. @@ -730,7 +730,7 @@ Learn more .. _`Doctrine`: http://www.doctrine-project.org/ .. _`MongoDB`: https://www.mongodb.org/ -.. _`Basic Mapping Documentation`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html +.. _`Doctrine's Mapping Types documentation`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html .. _`Query Builder`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/query-builder.html .. _`Doctrine Query Language`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html .. _`Mapping Types Documentation`: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#property-mapping diff --git a/security/entity_provider.rst b/security/entity_provider.rst index 53a534485ae..aff5dfdba03 100644 --- a/security/entity_provider.rst +++ b/security/entity_provider.rst @@ -447,11 +447,6 @@ interface only requires one method: ``loadUserByUsername($username)``:: } } -.. tip:: - - Don't forget to add the repository class to the - :doc:`mapping definition of your entity `. - To finish this, just remove the ``property`` key from the user provider in ``security.yml``: From 3e463f67d2c4664bef9b15ce01aa5f205ab928e0 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 23 Nov 2017 20:22:39 -0500 Subject: [PATCH 0127/2437] updating link to be version independent --- deployment.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment.rst b/deployment.rst index c272b85fdf8..dd38b4617fd 100644 --- a/deployment.rst +++ b/deployment.rst @@ -257,4 +257,4 @@ Learn More .. _`Heroku`: https://devcenter.heroku.com/articles/getting-started-with-symfony .. _`platform.sh`: https://docs.platform.sh/frameworks/symfony.html .. _`Azure`: https://azure.microsoft.com/en-us/develop/php/ -.. _`fortrabbit`: https://help.fortrabbit.com/install-symfony-3-uni +.. _`fortrabbit`: https://help.fortrabbit.com/install-symfony From 175a4e89b6a71c760b0ea4e09dc6f27876247053 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 23 Nov 2017 20:30:42 -0500 Subject: [PATCH 0128/2437] minor tweaks --- best_practices/configuration.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/best_practices/configuration.rst b/best_practices/configuration.rst index f87d5336cd4..63b987d45b4 100644 --- a/best_practices/configuration.rst +++ b/best_practices/configuration.rst @@ -18,9 +18,10 @@ application behavior. .. best-practice:: Define the infrastructure-related configuration options as environment - variables in the ``.env`` file at the root of the project. + variables. During development, use the ``.env`` file at the root of your + project to set these. -By default, Symfony adds this kind of options to the ``.env`` file when +By default, Symfony adds these types of options to the ``.env`` file when installing new dependencies in the app: .. code-block:: bash From d450dab8884ef9a882ed27c6c39bb04cd2624ee8 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 23 Nov 2017 20:54:09 -0500 Subject: [PATCH 0129/2437] [#8732] Minor tweaks --- configuration.rst | 26 ++++++++++++++++++++++---- configuration/environments.rst | 15 ++++----------- configuration/external_parameters.rst | 2 ++ 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/configuration.rst b/configuration.rst index 3c5060ff7ad..88e96cb92e5 100644 --- a/configuration.rst +++ b/configuration.rst @@ -72,7 +72,7 @@ instance, the framework bundle is configured in ``config/packages/framework.yaml ]); The top-level key (here ``framework``) references configuration for a specific -bundle (``FrameworkBundle`` in this case). +bundle (:doc:`FrameworkBundle ` in this case). .. sidebar:: Configuration Formats @@ -207,12 +207,30 @@ a controller - see :ref:`service-container-parameters`. .. _config-dot-env: .. _config-parameters-yml: -The .env File -~~~~~~~~~~~~~ +The .env File & Environment Variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There is also a ``.env`` file which is loaded. Its contents become environment variables in the dev environment, making it easier to reference environment -variables in your code. +variables in your code. When you install packages, more environment variables are +added to this file. But you can also add your own variables. + +Environment variables can be referenced in any other configuration files by using +a special syntax. For example, if you install the ``doctrine`` package, then you +will have an environment variable called ``DATABASE_URL`` in your ``.env`` file. +This is referenced inside ``config/packages/doctrine.yaml``: + +.. code-block:: yaml + + # config/packages/doctrine.yaml + doctrine: + dbal: + url: '%env(DATABASE_URL)%' + + # the resolve: prefix will resolve parameters *inside* the env variable + # url: '%env(resolve:DATABASE_URL)%' + +For more details about environment variables, see :ref:`config-env-vars`. The ``.env`` file is special, because it defines the values that usually change on each server. For example, the database credentials on your local development diff --git a/configuration/environments.rst b/configuration/environments.rst index df77a79b73d..0c251e57495 100644 --- a/configuration/environments.rst +++ b/configuration/environments.rst @@ -176,9 +176,10 @@ always run the application in the dev environment, independent of the Selecting the Environment for Console Commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -By default, Symfony commands are executed in the ``dev`` environment and with the -debug mode enabled. Use the ``--env`` and ``--no-debug`` options to modify this -behavior: +By default, Symfony commands are executed in whatever environment is defined by +the ``APP_ENV`` environment variable (usually configured in your ``.env`` file). + +Use the ``--env`` and ``--no-debug`` options to modify this behavior: .. code-block:: terminal @@ -191,14 +192,6 @@ behavior: # 'test' environment and debug disabled $ php bin/console command_name --env=test --no-debug -In addition to the ``--env`` and ``--no-debug`` options, the behavior of Symfony -commands can also be controlled with the same environment variables used by -``public/index.php``. - -These environment variables are very useful for production servers because they -allow you to ensure that commands always run in the ``prod`` environment without -having to add any command option. - .. index:: single: Environments; Creating a new environment diff --git a/configuration/external_parameters.rst b/configuration/external_parameters.rst index 3dfff4479de..942cfaaf687 100644 --- a/configuration/external_parameters.rst +++ b/configuration/external_parameters.rst @@ -10,6 +10,8 @@ credentials outside of your project code. Database configuration is one such example. The flexibility of the Symfony service container allows you to easily do this. +.. _config-env-vars: + Environment Variables --------------------- From 09fb4b1c597a14e3f8ca1e7884183999d38461c3 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 23 Nov 2017 21:10:01 -0500 Subject: [PATCH 0130/2437] Clarifying that our code is just additions --- bundles/override.rst | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/bundles/override.rst b/bundles/override.rst index a019fee8e7f..2928bb354d9 100644 --- a/bundles/override.rst +++ b/bundles/override.rst @@ -46,21 +46,24 @@ Services & Configuration If you want to modify service definitions of another bundle, you can use a compiler pass to change the class of the service or to modify method calls. In the following example, the implementing class for the ``original-service-id`` is changed to -``App\YourService``:: +``App\YourService``: + +.. code-block:: diff // src/Kernel.php namespace App; - use App\Service\YourService; - use Symfony\Component\DependencyInjection\ContainerBuilder; + // ... + + use App\Service\YourService; + + use Symfony\Component\DependencyInjection\ContainerBuilder; class Kernel extends BaseKernel { - public function process(ContainerBuilder $container) - { - $definition = $container->findDefinition('original-service-id'); - $definition->setClass(YourService::class); - } + + public function process(ContainerBuilder $container) + + { + + $definition = $container->findDefinition('original-service-id'); + + $definition->setClass(YourService::class); + + } } For more information on compiler passes, see :doc:`/service_container/compiler_passes`. From 8634e409758b296cc043094cefe94a559e4ded53 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 23 Nov 2017 21:13:10 -0500 Subject: [PATCH 0131/2437] typo --- serializer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serializer.rst b/serializer.rst index c79964d067d..c7a3f0ee945 100644 --- a/serializer.rst +++ b/serializer.rst @@ -126,7 +126,7 @@ stored in one of the following locations: .. _serializer-enabling-metadata-cache: -Configruing the Metadata Cache +Configuring the Metadata Cache ------------------------------ The metadata for the serializer is automatically cached. To configure the cache, From 9c4b9fe35816a7a982ccefc246a5616efb0f4be8 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 22 Nov 2017 19:41:14 +0100 Subject: [PATCH 0132/2437] (WIP) Updated security/* articles to Symfony 4 --- security/access_control.rst | 8 ++++---- security/access_denied_handler.rst | 2 +- security/api_key_authentication.rst | 6 +++--- security/csrf_in_login_form.rst | 4 ++-- security/custom_password_authenticator.rst | 2 +- security/custom_provider.rst | 8 ++++---- security/firewall_restriction.rst | 24 +++++++++++----------- security/force_https.rst | 4 ++-- security/form_login.rst | 10 ++++----- security/form_login_setup.rst | 6 +++--- security/guard_authentication.rst | 2 +- security/impersonating_user.rst | 4 ++-- security/json_login_setup.rst | 4 ++-- security/ldap.rst | 8 ++++---- security/multiple_guard_authenticators.rst | 4 ++-- security/multiple_user_providers.rst | 4 ++-- security/named_encoders.rst | 6 +++--- security/pre_authenticated.rst | 4 ++-- security/remember_me.rst | 2 +- security/user_checkers.rst | 2 +- security/voters.rst | 2 +- 21 files changed, 58 insertions(+), 58 deletions(-) diff --git a/security/access_control.rst b/security/access_control.rst index 6377a8eed3c..16ab831a78b 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -33,7 +33,7 @@ Take the following ``access_control`` entries as an example: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... access_control: @@ -171,7 +171,7 @@ pattern so that it is only accessible by requests from the local server itself: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... access_control: @@ -252,7 +252,7 @@ key: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... access_control: @@ -300,7 +300,7 @@ the user will be redirected to ``https``: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... access_control: diff --git a/security/access_denied_handler.rst b/security/access_denied_handler.rst index 3e912bd73e0..72278602ff2 100644 --- a/security/access_denied_handler.rst +++ b/security/access_denied_handler.rst @@ -38,7 +38,7 @@ configure it under your firewall: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml firewalls: # ... diff --git a/security/api_key_authentication.rst b/security/api_key_authentication.rst index 897792c90e9..36c3e6dd5de 100644 --- a/security/api_key_authentication.rst +++ b/security/api_key_authentication.rst @@ -292,7 +292,7 @@ and ``provider`` keys: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -364,7 +364,7 @@ If you have defined ``access_control``, make sure to add a new entry: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -423,7 +423,7 @@ configuration or set it to ``false``: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/csrf_in_login_form.rst b/security/csrf_in_login_form.rst index 79230f10062..39ea8c46351 100644 --- a/security/csrf_in_login_form.rst +++ b/security/csrf_in_login_form.rst @@ -59,7 +59,7 @@ use the default provider available in the security component: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -171,7 +171,7 @@ After this, you have protected your login form against CSRF attacks. .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/custom_password_authenticator.rst b/security/custom_password_authenticator.rst index f44f0c0aedf..abc622f0499 100644 --- a/security/custom_password_authenticator.rst +++ b/security/custom_password_authenticator.rst @@ -153,7 +153,7 @@ using the ``simple_form`` key: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/custom_provider.rst b/security/custom_provider.rst index ce471820ecf..1145e109943 100644 --- a/security/custom_provider.rst +++ b/security/custom_provider.rst @@ -9,7 +9,7 @@ When a user submits a username and password, the authentication layer asks the configured user provider to return a user object for a given username. Symfony then checks whether the password of this user is correct and generates a security token so the user stays authenticated during the current session. -Out of the box, Symfony has four user providers: ``memory``, ``entity``, +Out of the box, Symfony has four user providers: ``memory``, ``entity``, ``ldap`` and ``chain``. In this entry you'll see how you can create your own user provider, which could be useful if your users are accessed via a custom database, a file, or - as shown in this example - a web service. @@ -185,7 +185,7 @@ to the list of providers in the "security" section. Choose a name for the user p .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -233,7 +233,7 @@ users, e.g. by filling in a login form. You can do this by adding a line to the .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -301,7 +301,7 @@ is compared to the hashed password returned by your ``getPassword()`` method. .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/firewall_restriction.rst b/security/firewall_restriction.rst index 80e2bbc5212..36cf40fa48b 100644 --- a/security/firewall_restriction.rst +++ b/security/firewall_restriction.rst @@ -5,25 +5,25 @@ How to Restrict Firewalls to a Specific Request =============================================== When using the Security component, you can create firewalls that match certain request options. -In most cases, matching against the URL is sufficient, but in special cases you can further +In most cases, matching against the URL is sufficient, but in special cases you can further restrict the initialization of a firewall against other options of the request. .. note:: - You can use any of these restrictions individually or mix them together to get - your desired firewall configuration. + You can use any of these restrictions individually or mix them together to get + your desired firewall configuration. Restricting by Pattern ---------------------- -This is the default restriction and restricts a firewall to only be initialized if the request URL -matches the configured ``pattern``. +This is the default restriction and restricts a firewall to only be initialized if the request URL +matches the configured ``pattern``. .. configuration-block:: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml # ... security: @@ -64,23 +64,23 @@ matches the configured ``pattern``. ), )); -The ``pattern`` is a regular expression. In this example, the firewall will only be +The ``pattern`` is a regular expression. In this example, the firewall will only be activated if the URL starts (due to the ``^`` regex character) with ``/admin``. If -the URL does not match this pattern, the firewall will not be activated and subsequent +the URL does not match this pattern, the firewall will not be activated and subsequent firewalls will have the opportunity to be matched for this request. Restricting by Host ------------------- -If matching against the ``pattern`` only is not enough, the request can also be matched against -``host``. When the configuration option ``host`` is set, the firewall will be restricted to +If matching against the ``pattern`` only is not enough, the request can also be matched against +``host``. When the configuration option ``host`` is set, the firewall will be restricted to only initialize if the host from the request matches against the configuration. .. configuration-block:: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml # ... security: @@ -138,7 +138,7 @@ the provided HTTP methods. .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml # ... security: diff --git a/security/force_https.rst b/security/force_https.rst index f06136a5255..b8e0c5bdaf8 100644 --- a/security/force_https.rst +++ b/security/force_https.rst @@ -13,7 +13,7 @@ to use HTTPS then you could use the following configuration: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -61,7 +61,7 @@ role: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/form_login.rst b/security/form_login.rst index b436e89054b..9a8d685740a 100644 --- a/security/form_login.rst +++ b/security/form_login.rst @@ -42,7 +42,7 @@ a relative/absolute URL or a Symfony route name: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -99,7 +99,7 @@ previously requested URL and always redirect to the default page: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -198,7 +198,7 @@ parameter is included in the request, you may use the value of the .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -264,7 +264,7 @@ option to define a new target via a relative/absolute URL or a Symfony route nam .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -351,7 +351,7 @@ redirects can be customized using the ``target_path_parameter`` and .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/form_login_setup.rst b/security/form_login_setup.rst index cabea4f4179..3d8d9c47b9f 100644 --- a/security/form_login_setup.rst +++ b/security/form_login_setup.rst @@ -18,7 +18,7 @@ First, enable form login under your firewall: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -300,7 +300,7 @@ all URLs (including the ``/login`` URL), will cause a redirect loop: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml # ... access_control: @@ -338,7 +338,7 @@ fixes the problem: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml # ... access_control: diff --git a/security/guard_authentication.rst b/security/guard_authentication.rst index 5cb50da2463..b8aca32129b 100644 --- a/security/guard_authentication.rst +++ b/security/guard_authentication.rst @@ -260,7 +260,7 @@ Finally, configure your ``firewalls`` key in ``security.yml`` to use this authen .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index dad015da174..4d12591fa46 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -23,7 +23,7 @@ firewall listener: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -129,7 +129,7 @@ setting: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/json_login_setup.rst b/security/json_login_setup.rst index d6f9debc1ff..8b5b0f9b182 100644 --- a/security/json_login_setup.rst +++ b/security/json_login_setup.rst @@ -11,7 +11,7 @@ First, enable the JSON login under your firewall: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -151,7 +151,7 @@ The security configuration should be: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/ldap.rst b/security/ldap.rst index 42195fd6b4d..3814b78f36f 100644 --- a/security/ldap.rst +++ b/security/ldap.rst @@ -127,7 +127,7 @@ use the ``ldap`` user provider. .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -326,7 +326,7 @@ Configuration example for form login .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -380,7 +380,7 @@ Configuration example for HTTP Basic .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -433,7 +433,7 @@ Configuration example for form login and query_string .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/multiple_guard_authenticators.rst b/security/multiple_guard_authenticators.rst index 778fc24d75f..1b7a3d4dec8 100644 --- a/security/multiple_guard_authenticators.rst +++ b/security/multiple_guard_authenticators.rst @@ -22,7 +22,7 @@ This is how your security configuration can look in action: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... firewalls: @@ -93,7 +93,7 @@ the solution is to split the configuration into two separate firewalls: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... firewalls: diff --git a/security/multiple_user_providers.rst b/security/multiple_user_providers.rst index 2643654ad4a..1de0c7be8b9 100644 --- a/security/multiple_user_providers.rst +++ b/security/multiple_user_providers.rst @@ -10,7 +10,7 @@ creating a new provider that chains the two together: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: providers: chain_provider: @@ -92,7 +92,7 @@ to use a specific provider: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: firewalls: secured_area: diff --git a/security/named_encoders.rst b/security/named_encoders.rst index 0ed0b696c29..b019cdc5c11 100644 --- a/security/named_encoders.rst +++ b/security/named_encoders.rst @@ -11,7 +11,7 @@ to apply to all instances of a specific class: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... encoders: @@ -61,7 +61,7 @@ named encoders: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... encoders: @@ -133,7 +133,7 @@ you must register a service for it in order to use it as a named encoder: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... encoders: diff --git a/security/pre_authenticated.rst b/security/pre_authenticated.rst index 966b657d52d..6e036018257 100644 --- a/security/pre_authenticated.rst +++ b/security/pre_authenticated.rst @@ -32,7 +32,7 @@ Enable the x509 authentication for a particular firewall in the security configu .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -111,7 +111,7 @@ corresponding firewall in your security configuration: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: firewalls: secured_area: diff --git a/security/remember_me.rst b/security/remember_me.rst index 0a5ddcc471a..16db931be27 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -14,7 +14,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... diff --git a/security/user_checkers.rst b/security/user_checkers.rst index 2a40d64fab3..701568bd802 100644 --- a/security/user_checkers.rst +++ b/security/user_checkers.rst @@ -69,7 +69,7 @@ is the service id of your user checker: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml # ... security: diff --git a/security/voters.rst b/security/voters.rst index c253aed2402..ec63062c93f 100644 --- a/security/voters.rst +++ b/security/voters.rst @@ -289,7 +289,7 @@ security configuration: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: access_decision_manager: strategy: unanimous From a668558795b9d3b8cc08479e36a0c1c1683189d1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 22 Nov 2017 20:51:06 +0100 Subject: [PATCH 0133/2437] Updated security/* articles to Symfony 4 --- security/access_control.rst | 6 ++-- security/access_denied_handler.rst | 1 + security/api_key_authentication.rst | 8 +++--- security/csrf_in_login_form.rst | 12 ++++---- security/custom_authentication_provider.rst | 4 +-- security/custom_password_authenticator.rst | 6 ++-- security/custom_provider.rst | 14 +++++----- security/entity_provider.rst | 4 +-- security/expressions.rst | 17 ++++++----- security/firewall_restriction.rst | 6 ++-- security/force_https.rst | 4 +-- security/form_login.rst | 10 +++---- security/form_login_setup.rst | 21 +++++++------- security/guard_authentication.rst | 8 +++--- security/impersonating_user.rst | 31 +++++++++++++++------ security/json_login_setup.rst | 14 +++++----- security/ldap.rst | 11 +++++--- security/multiple_guard_authenticators.rst | 4 +-- security/multiple_user_providers.rst | 4 +-- security/named_encoders.rst | 19 +++++++------ security/password_encoding.rst | 4 +-- security/pre_authenticated.rst | 4 +-- security/remember_me.rst | 10 +++---- security/securing_services.rst | 26 +++++++++-------- security/security_checker.rst | 18 ++++++------ security/user_checkers.rst | 2 +- security/voters.rst | 8 +++--- 27 files changed, 153 insertions(+), 123 deletions(-) diff --git a/security/access_control.rst b/security/access_control.rst index 16ab831a78b..de0e114bda9 100644 --- a/security/access_control.rst +++ b/security/access_control.rst @@ -44,7 +44,7 @@ Take the following ``access_control`` entries as an example: .. code-block:: xml - + + + App\Security\AccessDeniedHandler diff --git a/security/api_key_authentication.rst b/security/api_key_authentication.rst index 36c3e6dd5de..f0fabab6020 100644 --- a/security/api_key_authentication.rst +++ b/security/api_key_authentication.rst @@ -211,7 +211,7 @@ The ``$userProvider`` might look something like this:: Next, make sure this class is registered as a service. If you're using the :ref:`default services.yaml configuration `, that happens automatically. A little later, you'll reference this service in -your :ref:`security.yml configuration `. +your :ref:`security.yaml configuration `. .. note:: @@ -310,7 +310,7 @@ and ``provider`` keys: .. code-block:: xml - + + + + loadFromExtension('framework', array( 'csrf_protection' => null, )); @@ -72,7 +72,7 @@ use the default provider available in the security component: .. code-block:: xml - + + cachePool->getItem(md5($nonce)); - + // Validate that the nonce is *not* in cache // if it is, this could be a replay attack if ($cacheItem->isHit()) { throw new NonceExpiredException('Previously used nonce detected'); } - + // Store the item in cache for 5 minutes $cacheItem->set(null)->expiresAfter(300); $this->cachePool->save($cacheItem); diff --git a/security/custom_password_authenticator.rst b/security/custom_password_authenticator.rst index abc622f0499..3817ebabc30 100644 --- a/security/custom_password_authenticator.rst +++ b/security/custom_password_authenticator.rst @@ -131,10 +131,10 @@ inside of it. Inside this method, the password encoder is needed to check the password's validity:: - $passwordValid = $this->encoder->isPasswordValid($user, $token->getCredentials()); + $passwordValid = $this->encoder->isPasswordValid($user, $token->getCredentials()); This is a service that is already available in Symfony and it uses the password algorithm -that is configured in the security configuration (e.g. ``security.yml``) under +that is configured in the security configuration (e.g. ``security.yaml``) under the ``encoders`` key. Below, you'll see how to inject that into the ``TimeAuthenticator``. .. _security-password-authenticator-config: @@ -168,7 +168,7 @@ using the ``simple_form`` key: .. code-block:: xml - + `, this happens automatically. -Modify ``security.yml`` ------------------------ +Modify ``security.yaml`` +------------------------ Everything comes together in your security configuration. Add the user provider -to the list of providers in the "security" section. Choose a name for the user provider +to the list of providers in the "security" config. Choose a name for the user provider (e.g. "webservice") and mention the ``id`` of the service you just defined. .. configuration-block:: @@ -195,7 +195,7 @@ to the list of providers in the "security" section. Choose a name for the user p .. code-block:: xml - + + + `. To finish this, just remove the ``property`` key from the user provider in -``security.yml``: +``security.yaml``: .. configuration-block:: diff --git a/security/expressions.rst b/security/expressions.rst index e9ea4fdb6b8..13970159ecd 100644 --- a/security/expressions.rst +++ b/security/expressions.rst @@ -15,7 +15,7 @@ accepts an :class:`Symfony\\Component\\ExpressionLanguage\\Expression` object:: use Symfony\Component\ExpressionLanguage\Expression; // ... - public function indexAction() + public function index() { $this->denyAccessUnlessGranted(new Expression( '"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())' @@ -70,17 +70,20 @@ Additionally, you have access to a number of functions inside the expression: The ``is_remember_me()`` and ``is_authenticated_fully()`` functions are *similar* to using ``IS_AUTHENTICATED_REMEMBERED`` and ``IS_AUTHENTICATED_FULLY`` with the ``isGranted()`` function - but they are **not** the same. The - following shows the difference:: + following controller snippet shows the difference:: use Symfony\Component\ExpressionLanguage\Expression; + use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; // ... - $ac = $this->get('security.authorization_checker'); - $access1 = $ac->isGranted('IS_AUTHENTICATED_REMEMBERED'); + public function index(AuthorizationCheckerInterface $auth) + { + $access1 = $auth->isGranted('IS_AUTHENTICATED_REMEMBERED'); - $access2 = $ac->isGranted(new Expression( - 'is_remember_me() or is_fully_authenticated()' - )); + $access2 = $auth->isGranted(new Expression( + 'is_remember_me() or is_fully_authenticated()' + )); + } Here, ``$access1`` and ``$access2`` will be the same value. Unlike the behavior of ``IS_AUTHENTICATED_REMEMBERED`` and ``IS_AUTHENTICATED_FULLY``, diff --git a/security/firewall_restriction.rst b/security/firewall_restriction.rst index 36cf40fa48b..6ca8203b4f6 100644 --- a/security/firewall_restriction.rst +++ b/security/firewall_restriction.rst @@ -34,7 +34,7 @@ matches the configured ``pattern``. .. code-block:: xml - + + + + + + + + + + + - AppBundle:Security:login + App\Controller\SecurityController::login .. code-block:: php // config/routes.php + use App\Controller\SecurityController; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Route; $collection = new RouteCollection(); $collection->add('login', new Route('/login', array( - '_controller' => 'AppBundle:Security:login', + '_controller' => array(SecurityController::class, 'login'), ))); return $collection; -Great! Next, add the logic to ``loginAction()`` that displays the login form:: +Great! Next, add the logic to ``login()`` that displays the login form:: // src/Controller/SecurityController.php use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; - public function loginAction(Request $request, AuthenticationUtils $authUtils) + public function login(Request $request, AuthenticationUtils $authUtils) { // get the login error if there is one $error = $authUtils->getLastAuthenticationError(); @@ -308,7 +309,7 @@ all URLs (including the ``/login`` URL), will cause a redirect loop: .. code-block:: xml - + + `, that happens automatically. -Finally, configure your ``firewalls`` key in ``security.yml`` to use this authenticator: +Finally, configure your ``firewalls`` key in ``security.yaml`` to use this authenticator: .. configuration-block:: @@ -283,7 +283,7 @@ Finally, configure your ``firewalls`` key in ``security.yml`` to use this authen .. code-block:: xml - + `. Then, type-hint ``CsrfTokenManagerInterface`` in your ``__construct()`` method -(or manually configure the ``security.csrf.token_manager`` service to be passed) -and add the following logic:: +(or manually configure the ``Symfony\Component\Security\Csrf\CsrfTokenManagerInterface`` +service to be passed) and add the following logic:: // src/Security/ExampleFormAuthenticator.php // ... diff --git a/security/impersonating_user.rst b/security/impersonating_user.rst index 4d12591fa46..a952c284b6e 100644 --- a/security/impersonating_user.rst +++ b/security/impersonating_user.rst @@ -34,7 +34,7 @@ firewall listener: .. code-block:: xml - + get('security.authorization_checker'); - $tokenStorage = $this->get('security.token_storage'); + private $authChecker; + private $tokenStorage; - if ($authChecker->isGranted('ROLE_PREVIOUS_ADMIN')) { - foreach ($tokenStorage->getToken()->getRoles() as $role) { - if ($role instanceof SwitchUserRole) { - $impersonatorUser = $role->getSource()->getUser(); - break; + public function __construct(AuthorizationCheckerInterface $authChecker, TokenStorageInterface $tokenStorage) + { + $this->authChecker = $authChecker; + $this->tokenStorage = $tokenStorage; + } + + public function someMethod() + { + // ... + + if ($authChecker->isGranted('ROLE_PREVIOUS_ADMIN')) { + foreach ($tokenStorage->getToken()->getRoles() as $role) { + if ($role instanceof SwitchUserRole) { + $impersonatorUser = $role->getSource()->getUser(); + break; + } } } } @@ -140,7 +153,7 @@ setting: .. code-block:: xml - + + - AppBundle:Security:login + App\Controller\SecurityController::login @@ -111,7 +111,7 @@ path: $collection = new RouteCollection(); $collection->add('login', new Route('/login', array( - '_controller' => 'AppBundle:Security:login', + '_controller' => 'App\Controller\SecurityController::login', ))); return $collection; @@ -165,7 +165,7 @@ The security configuration should be: .. code-block:: xml - + + loadFromExtension('security', array( @@ -340,7 +341,7 @@ Configuration example for form login .. code-block:: xml - + loadFromExtension('security', array( @@ -394,7 +396,7 @@ Configuration example for HTTP Basic .. code-block:: xml - + loadFromExtension('security', array( @@ -448,7 +451,7 @@ Configuration example for form login and query_string .. code-block:: xml - + + + + + + + + + id="App\Security\Encoder\MyCustomPasswordEncoder" /> .. code-block:: php // app/config/security.php + // ... + use App\Security\Encoder\MyCustomPasswordEncoder; + $container->loadFromExtension('security', array( // ... 'encoders' => array( 'app_encoder' => array( - 'id' => 'app.password_encoder_service' + 'id' => MyCustomPasswordEncoder::class ), ), )); -This creates an encoder named ``app_encoder`` from a service named -``app.password_encoder_service``. +This creates an encoder named ``app_encoder`` from a service with the ID +``App\Security\Encoder\MyCustomPasswordEncoder``. diff --git a/security/password_encoding.rst b/security/password_encoding.rst index 7ffceb57647..2a3c6509eb8 100644 --- a/security/password_encoding.rst +++ b/security/password_encoding.rst @@ -17,7 +17,7 @@ in the following way from a controller:: use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; - public function registerAction(UserPasswordEncoderInterface $encoder) + public function register(UserPasswordEncoderInterface $encoder) { // whatever *your* User object is $user = new App\Entity\User(); @@ -29,7 +29,7 @@ in the following way from a controller:: In order for this to work, just make sure that you have the encoder for your user class (e.g. ``App\Entity\User``) configured under the ``encoders`` -key in ``config/security.yaml``. +key in ``config/packages/security.yaml``. The ``$encoder`` object also has an ``isPasswordValid()`` method, which takes the ``User`` object as the first argument and the plain password to check diff --git a/security/pre_authenticated.rst b/security/pre_authenticated.rst index 6e036018257..883243e9c1b 100644 --- a/security/pre_authenticated.rst +++ b/security/pre_authenticated.rst @@ -44,7 +44,7 @@ Enable the x509 authentication for a particular firewall in the security configu .. code-block:: xml - + + diff --git a/security/remember_me.rst b/security/remember_me.rst index 16db931be27..d964127a7d3 100644 --- a/security/remember_me.rst +++ b/security/remember_me.rst @@ -32,7 +32,7 @@ the session lasts using a cookie with the ``remember_me`` firewall option: .. code-block:: xml - + denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); @@ -261,7 +261,7 @@ your controller using annotations: /** * @Security("is_granted('IS_AUTHENTICATED_FULLY')") */ - public function editAction($name) + public function edit($name) { // ... } @@ -278,12 +278,12 @@ your controller using annotations: * Once the user has entered their username and password, assuming the user receives the ``ROLE_USER`` role per your configuration, the user will have the ``IS_AUTHENTICATED_FULLY`` role and be able to access - any page in the account section, including the ``editAction()`` controller. + any page in the account section, including the ``edit()`` controller. * If the user's session ends, when the user returns to the site, they will be able to access every account page - except for the edit page - without being forced to re-authenticate. However, when they try to access the - ``editAction()`` controller, they will be forced to re-authenticate, since + ``edit()`` controller, they will be forced to re-authenticate, since they are not, yet, fully authenticated. For more information on securing services or methods in this way, diff --git a/security/securing_services.rst b/security/securing_services.rst index 56b53420629..0b24092a7d6 100644 --- a/security/securing_services.rst +++ b/security/securing_services.rst @@ -7,20 +7,23 @@ How to Secure any Service or Method in your Application In the security article, you can see how to :ref:`secure a controller ` by requesting -the ``security.authorization_checker`` service from the Service Container and -checking the current user's role:: +the ``Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface`` +service from the Service Container and checking the current user's role:: // ... + use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; - public function helloAction($name) + public function hello(AuthorizationCheckerInterface $authChecker) { - $this->denyAccessUnlessGranted('ROLE_ADMIN'); + if (!$authChecker->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException(); + } // ... } -You can also secure *any* service by injecting the ``security.authorization_checker`` +You can also secure *any* service by injecting the authorization checker service into it. For a general introduction to injecting dependencies into services see the :doc:`/service_container` article. For example, suppose you have a ``NewsletterManager`` class that sends out emails and you want to @@ -41,7 +44,8 @@ Before you add security, the class looks something like this:: } Your goal is to check the user's role when the ``sendNewsletter()`` method is -called. The first step towards this is to inject the ``security.authorization_checker`` +called. The first step towards this is to inject the +``Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface`` service into the object:: // src/Newsletter/NewsletterManager.php @@ -52,16 +56,16 @@ service into the object:: class NewsletterManager { - protected $authorizationChecker; + protected $authChecker; - public function __construct(AuthorizationCheckerInterface $authorizationChecker) + public function __construct(AuthorizationCheckerInterface $authChecker) { - $this->authorizationChecker = $authorizationChecker; + $this->authChecker = $authChecker; } public function sendNewsletter() { - if (!$this->authorizationChecker->isGranted('ROLE_NEWSLETTER_ADMIN')) { + if (!$this->authChecker->isGranted('ROLE_NEWSLETTER_ADMIN')) { throw new AccessDeniedException(); } @@ -72,7 +76,7 @@ service into the object:: } If you're using the :ref:`default services.yaml configuration `, -Symfony will automatically pass the ``security.authorization_checker`` to your service +Symfony will automatically pass the authorization checker to your service thanks to autowiring and the ``AuthorizationCheckerInterface`` type-hint. If the current user does not have the ``ROLE_NEWSLETTER_ADMIN``, they will diff --git a/security/security_checker.rst b/security/security_checker.rst index 0316c1bd7ec..d77552fd70b 100644 --- a/security/security_checker.rst +++ b/security/security_checker.rst @@ -5,9 +5,17 @@ How to Check for Known Security Vulnerabilities in Your Dependencies ==================================================================== When using lots of dependencies in your Symfony projects, some of them may -contain security vulnerabilities. That's why Symfony includes a command called +contain security vulnerabilities. That's why Symfony provides a command called ``security:check`` that checks your ``composer.lock`` file to find any known -security vulnerability in your installed dependencies: +security vulnerability in your installed dependencies. + +First, install the security checker in your project: + +.. code-block:: terminal + + $ composer require security-checker + +Then run this command: .. code-block:: terminal @@ -24,10 +32,4 @@ FriendsOfPHP organization. any of your dependencies is affected by a known security vulnerability. Therefore, you can easily integrate it in your build process. -.. note:: - - To enable the ``security:check`` command, make sure the - `SensioDistributionBundle`_ is installed and enabled in your application. - .. _`security advisories database`: https://github.com/FriendsOfPHP/security-advisories -.. _`SensioDistributionBundle`: https://github.com/sensiolabs/SensioDistributionBundle diff --git a/security/user_checkers.rst b/security/user_checkers.rst index 701568bd802..9287a9c51dd 100644 --- a/security/user_checkers.rst +++ b/security/user_checkers.rst @@ -81,7 +81,7 @@ is the service id of your user checker: .. code-block:: xml - + + Date: Fri, 24 Nov 2017 12:01:10 +0100 Subject: [PATCH 0134/2437] Updated the main security article --- security.rst | 149 +++++++++++++++++++++++++++------------------------ 1 file changed, 78 insertions(+), 71 deletions(-) diff --git a/security.rst b/security.rst index e3db5a33535..b32a64a865d 100644 --- a/security.rst +++ b/security.rst @@ -16,7 +16,7 @@ sections: #. Installing security support; -#. Initial ``security.yml`` setup (*authentication*); +#. Initial ``security.yaml`` setup (*authentication*); #. Denying access to your app (*authorization*); @@ -38,34 +38,32 @@ install the security feature before using it: .. _security-firewalls: .. _firewalls-authentication: +.. _initial-security-yml-setup-authentication: -1) Initial security.yml Setup (Authentication) ----------------------------------------------- +1) Initial security.yaml Setup (Authentication) +----------------------------------------------- -The security system is configured in ``app/config/security.yml``. The default -configuration looks like this: +The security system is configured in ``config/packages/security.yaml``. The +default configuration looks like this: .. configuration-block:: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: providers: - in_memory: - memory: ~ - + in_memory: { memory: ~ } firewalls: dev: pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false - main: anonymous: ~ .. code-block:: xml - + loadFromExtension('security', array( 'providers' => array( 'in_memory' => array( @@ -150,7 +148,7 @@ To activate this, add the ``http_basic`` key under your firewall: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -162,7 +160,7 @@ To activate this, add the ``http_basic`` key under your firewall: .. code-block:: xml - + loadFromExtension('security', array( // ... 'firewalls' => array( @@ -210,20 +208,20 @@ example, if you use annotations, create something like this:: /** * @Route("/admin") */ - public function adminAction() + public function admin() { return new Response('Admin page!'); } } -Next, add an ``access_control`` entry to ``security.yml`` that requires the +Next, add an ``access_control`` entry to ``security.yaml`` that requires the user to be logged in to access this URL: .. configuration-block:: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... firewalls: @@ -237,7 +235,7 @@ user to be logged in to access this URL: .. code-block:: xml - + loadFromExtension('security', array( // ... 'firewalls' => array( @@ -312,14 +310,14 @@ configuring it. Symfony has a built-in way to or you can :doc:`create your own user provider `. The easiest (but most limited) way, is to configure Symfony to load hardcoded -users directly from the ``security.yml`` file itself. This is called an "in memory" +users directly from the ``security.yaml`` file itself. This is called an "in memory" provider, but it's better to think of it as an "in configuration" provider: .. configuration-block:: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: providers: in_memory: @@ -335,7 +333,7 @@ provider, but it's better to think of it as an "in configuration" provider: .. code-block:: xml - + loadFromExtension('security', array( 'providers' => array( 'in_memory' => array( @@ -398,7 +396,7 @@ To fix this, add an ``encoders`` key: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -408,7 +406,7 @@ To fix this, add an ``encoders`` key: .. code-block:: xml - + loadFromExtension('security', array( // ... @@ -468,7 +466,7 @@ If you'd like to load your users via the Doctrine ORM, that's easy! See C) Encoding the User's Password ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Whether your users are stored in ``security.yml``, in a database or somewhere +Whether your users are stored in ``security.yaml``, in a database or somewhere else, you'll want to encode their passwords. The best algorithm to use is ``bcrypt``: @@ -476,7 +474,7 @@ else, you'll want to encode their passwords. The best algorithm to use is .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -487,7 +485,7 @@ else, you'll want to encode their passwords. The best algorithm to use is .. code-block:: xml - + loadFromExtension('security', array( // ... @@ -534,7 +532,7 @@ It will give you something like this: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -551,7 +549,7 @@ It will give you something like this: .. code-block:: xml - + loadFromExtension('security', array( // ... @@ -616,7 +614,7 @@ D) Configuration Done! ~~~~~~~~~~~~~~~~~~~~~~ Congratulations! You now have a working authentication system that uses HTTP -basic auth and loads users right from the ``security.yml`` file. +basic auth and loads users right from the ``security.yaml`` file. Your next steps depend on your setup: @@ -657,7 +655,7 @@ Roles ~~~~~ When a user logs in, they receive a set of roles (e.g. ``ROLE_ADMIN``). In -the example above, these are hardcoded into ``security.yml``. If you're +the example above, these are hardcoded into ``security.yaml``. If you're loading users from the database, these are probably stored on a column in your table. @@ -691,7 +689,7 @@ Add Code to Deny Access There are **two** ways to deny access to something: -#. :ref:`access_control in security.yml ` +#. :ref:`access_control in security.yaml ` allows you to protect URL patterns (e.g. ``/admin/*``). This is easy, but less flexible; @@ -710,7 +708,7 @@ URL pattern. You saw this earlier, where anything matching the regular expressio .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -725,7 +723,7 @@ URL pattern. You saw this earlier, where anything matching the regular expressio .. code-block:: xml - + loadFromExtension('security', array( // ... @@ -776,7 +774,7 @@ matches the URL. .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -786,7 +784,7 @@ matches the URL. .. code-block:: xml - + loadFromExtension('security', array( // ... @@ -839,20 +837,34 @@ You can easily deny access from inside a controller:: // ... - public function helloAction($name) + public function hello($name) { // The second parameter is used to specify on what object the role is tested. $this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!'); - // Old way : - // if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { - // throw $this->createAccessDeniedException('Unable to access this page!'); - // } - // ... } -In both cases, a special +.. tip:: + + The ``denyAccessUnlessGranted()`` is a shortcut provided by the optional + :ref:`base controller provided by Symfony `. + It's equivalent to the following code:: + + use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface + use Symfony\Component\Security\Core\Exception\AccessDeniedException; + // ... + + public function hello($name, AuthorizationCheckerInterface $authChecker) + { + if (false === $authChecker->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException('Unable to access this page!'); + } + + // ... + } + +If access is not granted, a special :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException` is thrown, which ultimately triggers a 403 HTTP response inside Symfony. @@ -873,7 +885,7 @@ using annotations:: /** * @Security("has_role('ROLE_ADMIN')") */ - public function helloAction($name) + public function hello($name) { // ... } @@ -922,11 +934,9 @@ user is logged in (you don't care about roles), then you can use // ... - public function helloAction($name) + public function hello($name) { - if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { - throw $this->createAccessDeniedException(); - } + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); // ... } @@ -1000,14 +1010,13 @@ After authentication, the ``User`` object of the current user can be accessed via the ``security.token_storage`` service. From inside a controller, this will look like:: - use Symfony\Component\Security\Core\User\UserInterface; - - public function indexAction() + public function index() { $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); $user = $this->getUser(); - // or you can also type-hint a method argument with UserInterface: e.g. "UserInterface $user" + // or you can also type-hint a method argument with this class: + // Symfony\Component\Security\Core\User\UserInterface (e.g. "UserInterface $user") } .. tip:: @@ -1021,7 +1030,7 @@ if your User object has a ``getFirstName()`` method, you could use that:: use Symfony\Component\HttpFoundation\Response; // ... - public function indexAction() + public function index() { // ... @@ -1039,7 +1048,7 @@ this is a quirk. If you're not logged in, the user is technically the string :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface\\UserInterface` and being logged-in is optional, you can allow a null value for the argument:: - public function indexAction(UserInterface $user = null) + public function index(UserInterface $user = null) { // $user is null when not logged-in or anon. } @@ -1049,13 +1058,11 @@ the User object, and use the ``isGranted()`` method (or :ref:`access_control `) to do this:: // yay! Use this to see if the user is logged in - if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) { - throw $this->createAccessDeniedException(); - } + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); // boo :(. Never check for the User object to see if they're logged in if ($this->getUser()) { - + // ... } Retrieving the User in a Template @@ -1099,7 +1106,7 @@ the firewall can handle this automatically for you when you activate the .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -1112,7 +1119,7 @@ the firewall can handle this automatically for you when you activate the .. code-block:: xml - + loadFromExtension('security', array( // ... @@ -1203,7 +1210,7 @@ rules by creating a role hierarchy: .. code-block:: yaml - # app/config/security.yml + # config/packages/security.yaml security: # ... @@ -1213,7 +1220,7 @@ rules by creating a role hierarchy: .. code-block:: xml - + loadFromExtension('security', array( // ... From 889e1531b9f597da69a41f5c21db045df1e51250 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 24 Nov 2017 15:30:32 +0100 Subject: [PATCH 0135/2437] Remove some small email articles --- _build/redirection_map | 6 +++-- email.rst | 50 ++++++++++++++++++++++++++++++++++++---- email/cloud.rst | 52 ------------------------------------------ email/gmail.rst | 46 ------------------------------------- 4 files changed, 49 insertions(+), 105 deletions(-) delete mode 100644 email/cloud.rst delete mode 100644 email/gmail.rst diff --git a/_build/redirection_map b/_build/redirection_map index 146e731e460..f5e87b0f3d9 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -150,10 +150,10 @@ /cookbook/doctrine/registration_form /doctrine/registration_form /cookbook/doctrine/resolve_target_entity /doctrine/resolve_target_entity /cookbook/doctrine/reverse_engineering /doctrine/reverse_engineering -/cookbook/email/cloud /email/cloud +/cookbook/email/cloud /email /cookbook/email/dev_environment /email/dev_environment /cookbook/email/email /email -/cookbook/email/gmail /email/gmail +/cookbook/email/gmail /email /cookbook/email/index /email /cookbook/email/spool /email/spool /cookbook/email/testing /email/testing @@ -348,6 +348,8 @@ /components/yaml/index /components/yaml /deployment/tools /deployment /install/bundles /setup/bundles +/email/gmail /email +/email/cloud /email /event_dispatcher/class_extension /event_dispatcher /form /forms /form/use_virtual_forms /form/inherit_data_option diff --git a/email.rst b/email.rst index 501173490ad..0a8b8694bd6 100644 --- a/email.rst +++ b/email.rst @@ -37,9 +37,6 @@ environment variable in the ``.env`` file: # use this to disable email delivery MAILER_URL=null://localhost - # use this to send emails via Gmail (don't use this in production) - MAILER_URL=gmail://username:password@localhost - # use this to configure a traditional SMTP server MAILER_URL=smtp://localhost:25?encryption=ssl&auth_mode=login&username=&password= @@ -107,6 +104,49 @@ The ``$message`` object supports many more options, such as including attachment adding HTML content, and much more. Refer to the `Creating Messages`_ section of the Swift Mailer documentation for more details. +Using Gmail to Send Emails +-------------------------- + +During development, you might prefer to send emails using Gmail instead of +setting up a regular SMTP server. To do that, update the ``MAILER_URL`` of your +``.env`` file to this: + +.. code-block:: bash + + # username is your full Gmail or Google Apps email address + MAILER_URL=gmail://username:password@localhost + +The ``gmail`` transport is simply a shortcut that uses the ``smtp`` transport, +``ssl`` encryption, ``login`` auth mode and ``smtp.gmail.com`` host. If your app +uses other encryption or auth mode, you must override those values +(:doc:`see mailer config reference `): + +.. code-block:: bash + + # username is your full Gmail or Google Apps email address + MAILER_URL=gmail://username:password@localhost?encryption=tls&auth_mode=oauth + +If your Gmail account uses 2-Step-Verification, you must `generate an App password`_ +and use it as the value of the mailer password. You must also ensure that you +`allow less secure apps to access your Gmail account`_. + +Using Cloud Services to Send Emails +----------------------------------- + +Cloud mailing services are a popular option for companies that don't want to set +up and maintain their own reliable mail servers. In Symfony apps, using these +services is as simple as updating the value of ``MAILER_URL`` in the ``.env`` +file. For example, for `Amazon SES`_ (Simple Email Service): + +.. code-block:: bash + + # The host will be different depending on your AWS zone + # The username/password credentials are obtained from the Amazon SES console + MAILER_URL=smtp://email-smtp.us-east-1.amazonaws.com:587?encryption=tls&username=YOUR_SES_USERNAME&password=YOUR_SES_PASSWORD + +Use the same technique for other mail services, as most of the time there is +nothing more to it than configuring an SMTP endpoint. + Learn more ---------- @@ -114,8 +154,6 @@ Learn more :maxdepth: 1 email/dev_environment - email/gmail - email/cloud email/spool email/testing @@ -125,3 +163,5 @@ Learn more .. _`Mandrill`: https://mandrill.com/ .. _`SendGrid`: https://sendgrid.com/ .. _`Amazon SES`: http://aws.amazon.com/ses/ +.. _`generate an App password`: https://support.google.com/accounts/answer/185833 +.. _`allow less secure apps to access your Gmail account`: https://support.google.com/accounts/answer/6010255 diff --git a/email/cloud.rst b/email/cloud.rst deleted file mode 100644 index 3166405141f..00000000000 --- a/email/cloud.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. index:: - single: Emails; Using the cloud - -How to Use the Cloud to Send Emails -=================================== - -Requirements for sending emails from a production system differ from your -development setup as you don't want to be limited in the number of emails, -the sending rate or the sender address. Thus, -:doc:`using Gmail ` or similar services is not an -option. If setting up and maintaining your own reliable mail server causes -you a headache there's a simple solution: Leverage the cloud to send your -emails. - -This article shows how easy it is to integrate -`Amazon's Simple Email Service (SES)`_ into Symfony. - -.. note:: - - You can use the same technique for other mail services, as most of the - time there is nothing more to it than configuring an SMTP endpoint. - -Symfony's mailer uses the ``MAILER_URL`` environment variable to store the -SMTP connection parameters, including the security credentials. Get those -parameters from the `SES console`_ and update the value of ``MAILER_URL`` in -the ``.env`` file: - -.. code-block:: bash - - MAILER_URL=smtp://email-smtp.us-east-1.amazonaws.com:587?encryption=tls&username=YOUR_SES_USERNAME&password=YOUR_SES_PASSWORD - -And that's it, you're ready to start sending emails through the cloud! - -.. note:: - - If you intend to use Amazon SES, please note the following: - - * You have to sign up to `Amazon Web Services (AWS)`_; - - * Every sender address used in the ``From`` or ``Return-Path`` (bounce - address) header needs to be confirmed by the owner. You can also - confirm an entire domain; - - * Initially you are in a restricted sandbox mode. You need to request - production access before being allowed to send to arbitrary - recipients; - - * SES may be subject to a charge. - -.. _`Amazon's Simple Email Service (SES)`: http://aws.amazon.com/ses -.. _`SES console`: https://console.aws.amazon.com/ses -.. _`Amazon Web Services (AWS)`: http://aws.amazon.com diff --git a/email/gmail.rst b/email/gmail.rst deleted file mode 100644 index a8d456edaa4..00000000000 --- a/email/gmail.rst +++ /dev/null @@ -1,46 +0,0 @@ -.. index:: - single: Emails; Gmail - -How to Use Gmail to Send Emails -=============================== - -During development, instead of using a regular SMTP server to send emails, you -might find using Gmail easier and more practical. The Symfony mailer makes -it really easy. - -In the ``.env`` file used in your development machine, change the ``MAILER_URL`` -environment variable to this: - -.. code-block:: bash - - MAILER_URL=gmail://YOUR_GMAIL_USERNAME:YOUR_GMAIL_PASSWORD@localhost - -Redefining the Default Configuration Parameters ------------------------------------------------ - -The ``gmail`` transport is simply a shortcut that uses the ``smtp`` transport -and sets these options: - -============== ================== -Option Value -============== ================== -``encryption`` ``ssl`` -``auth_mode`` ``login`` -``host`` ``smtp.gmail.com`` -============== ================== - -If your application uses ``tls`` encryption or ``oauth`` authentication, you -must override the default options by defining the ``encryption`` and ``auth_mode`` -parameters. - -If your Gmail account uses 2-Step-Verification, you must `generate an App password`_ -and use it as the value of the ``mailer_password`` parameter. You must also ensure -that you `allow less secure apps to access your Gmail account`_. - -.. seealso:: - - See the :doc:`Swiftmailer configuration reference ` - for more details. - -.. _`generate an App password`: https://support.google.com/accounts/answer/185833 -.. _`allow less secure apps to access your Gmail account`: https://support.google.com/accounts/answer/6010255 From 90ad1af399825e947c6e25e64d19029b94fcb4d4 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 24 Nov 2017 15:47:50 +0100 Subject: [PATCH 0136/2437] Fixed the Gmail reference --- email.rst | 2 ++ reference/configuration/swiftmailer.rst | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/email.rst b/email.rst index 0a8b8694bd6..714d8e0bec2 100644 --- a/email.rst +++ b/email.rst @@ -104,6 +104,8 @@ The ``$message`` object supports many more options, such as including attachment adding HTML content, and much more. Refer to the `Creating Messages`_ section of the Swift Mailer documentation for more details. +.. _email-using-gmail: + Using Gmail to Send Emails -------------------------- diff --git a/reference/configuration/swiftmailer.rst b/reference/configuration/swiftmailer.rst index 2bf47c40859..1b22abf375a 100644 --- a/reference/configuration/swiftmailer.rst +++ b/reference/configuration/swiftmailer.rst @@ -58,7 +58,7 @@ transport The exact transport method to use to deliver emails. Valid values are: * smtp -* gmail (see :doc:`/email/gmail`) +* gmail (see :ref:`email-using-gmail`) * mail (deprecated in SwiftMailer since version 5.4.5) * sendmail * null (same as setting `disable_delivery`_ to ``true``) From c40a9d9201e7c73693ffab88077821c91e2a9748 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 24 Nov 2017 15:51:03 +0100 Subject: [PATCH 0137/2437] Fixed the last references to security.yml --- security/entity_provider.rst | 2 +- security/form_login_setup.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/security/entity_provider.rst b/security/entity_provider.rst index f78d62c9ed0..bed6a01a7c3 100644 --- a/security/entity_provider.rst +++ b/security/entity_provider.rst @@ -24,7 +24,7 @@ Introduction Loading users via a Doctrine entity has 2 basic steps: #. :ref:`Create your User entity ` -#. :ref:`Configure security.yml to load from your entity ` +#. :ref:`Configure security.yaml to load from your entity ` Afterwards, you can learn more about :ref:`forbidding inactive users `, :ref:`using a custom query ` diff --git a/security/form_login_setup.rst b/security/form_login_setup.rst index 2534ce34bf1..78db3a9f4ff 100644 --- a/security/form_login_setup.rst +++ b/security/form_login_setup.rst @@ -231,7 +231,7 @@ Finally, create the template: The form can look like anything, but it usually follows some conventions: * The ```` element sends a ``POST`` request to the ``login`` route, since - that's what you configured under the ``form_login`` key in ``security.yml``; + that's what you configured under the ``form_login`` key in ``security.yaml``; * The username field has the name ``_username`` and the password field has the name ``_password``. From ef2a0449cf58558269f7777cda07bb7579bdefdc Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 24 Nov 2017 15:53:38 +0100 Subject: [PATCH 0138/2437] Remove App\Bridge\Doctrine\ namespace --- reference/configuration/doctrine.rst | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index d5d8efd97e8..a21e77ad6ed 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -20,7 +20,7 @@ Full Default Configuration # A collection of custom types # Example some_custom_type: - class: App\Bridge\Doctrine\DBAL\MyCustomType + class: App\DBAL\MyCustomType commented: true @@ -163,17 +163,17 @@ Full Default Configuration # a collection of string functions string_functions: # example - # test_string: App\Bridge\Doctrine\DQL\StringFunction + # test_string: App\DQL\StringFunction # a collection of numeric functions numeric_functions: # example - # test_numeric: App\Bridge\Doctrine\DQL\NumericFunction + # test_numeric: App\DQL\NumericFunction # a collection of datetime functions datetime_functions: # example - # test_datetime: App\Bridge\Doctrine\DQL\DatetimeFunction + # test_datetime: App\DQL\DatetimeFunction # Register SQL Filters in the entity manager filters: @@ -204,14 +204,14 @@ Full Default Configuration user="user" password="secret" driver="pdo_mysql" - driver-class="App\Bridge\Doctrine\DBAL\MyDatabaseDriver" + driver-class="App\DBAL\MyDatabaseDriver" path="%kernel.project_dir%/var/data/data.sqlite" memory="true" unix-socket="/tmp/mysql.sock" - wrapper-class="App\Bridge\Doctrine\DBAL\MyConnectionWrapper" + wrapper-class="App\DBAL\MyConnectionWrapper" charset="UTF8" logging="%kernel.debug%" - platform-service="App\Bridge\Doctrine\DBAL\MyDatabasePlatformService" + platform-service="App\DBAL\MyDatabasePlatformService" server-version="5.6" keep-slave="false" > @@ -219,7 +219,7 @@ Full Default Configuration string - App\Bridge\Doctrine\DBAL\MyCustomType + App\DBAL\MyCustomType - App\Bridge\Doctrine\DQL\StringFunction + App\DQL\StringFunction - App\Bridge\Doctrine\DQL\NumericFunction + App\DQL\NumericFunction - App\Bridge\Doctrine\DQL\DatetimeFunction + App\DQL\DatetimeFunction @@ -301,7 +301,7 @@ The following block shows all possible configuration keys: password: secret driver: pdo_mysql # the DBAL driverClass option - driver_class: App\Bridge\Doctrine\DBAL\MyDatabaseDriver + driver_class: App\DBAL\MyDatabaseDriver # the DBAL driverOptions option options: foo: bar @@ -309,15 +309,15 @@ The following block shows all possible configuration keys: memory: true unix_socket: /tmp/mysql.sock # the DBAL wrapperClass option - wrapper_class: App\Bridge\Doctrine\DBAL\MyConnectionWrapper + wrapper_class: App\DBAL\MyConnectionWrapper charset: UTF8 logging: '%kernel.debug%' - platform_service: App\Bridge\Doctrine\DBAL\MyDatabasePlatformService + platform_service: App\DBAL\MyDatabasePlatformService server_version: 5.6 mapping_types: enum: string types: - custom: App\Bridge\Doctrine\DBAL\MyCustomType + custom: App\DBAL\MyCustomType .. code-block:: xml @@ -339,19 +339,19 @@ The following block shows all possible configuration keys: user="user" password="secret" driver="pdo_mysql" - driver-class="App\Bridge\Doctrine\DBAL\MyDatabaseDriver" + driver-class="App\DBAL\MyDatabaseDriver" path="%kernel.project_dir%/var/data/data.sqlite" memory="true" unix-socket="/tmp/mysql.sock" - wrapper-class="App\Bridge\Doctrine\DBAL\MyConnectionWrapper" + wrapper-class="App\DBAL\MyConnectionWrapper" charset="UTF8" logging="%kernel.debug%" - platform-service="App\Bridge\Doctrine\DBAL\MyDatabasePlatformService" + platform-service="App\DBAL\MyDatabasePlatformService" server-version="5.6"> bar string - App\Bridge\Doctrine\DBAL\MyCustomType + App\DBAL\MyCustomType @@ -480,7 +480,7 @@ The following example shows an overview of the caching configurations: # the 'service' type requires to define the 'id' option too query_cache_driver: type: service - id: App\Bridge\Doctrine\ORM\MyCacheService + id: App\ORM\MyCacheService Mapping Configuration ~~~~~~~~~~~~~~~~~~~~~ From e80995b979dd8a3ee7c8a126ab3f77882401f3ff Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 24 Nov 2017 15:55:56 +0100 Subject: [PATCH 0139/2437] Fixed PHP form theme resources --- reference/configuration/framework.rst | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index af484a46ea1..58602365003 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -1371,8 +1371,8 @@ A list of all resources for form theming in PHP. This setting is not required if you're using the Twig format for your templates, in that case refer to :ref:`the form article `. -Assume you have custom global form themes in -``src/Resources/views/Form``, you can configure this like: +Assume you have custom global form themes in ``templates/form_themes/``, you can +configure this like: .. configuration-block:: @@ -1383,7 +1383,7 @@ Assume you have custom global form themes in templating: form: resources: - - 'WebsiteBundle:Form' + - 'form_themes' .. code-block:: xml @@ -1397,17 +1397,11 @@ Assume you have custom global form themes in http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - - - WebsiteBundle:Form - + form_themes - - @@ -1418,7 +1412,7 @@ Assume you have custom global form themes in 'templating' => array( 'form' => array( 'resources' => array( - 'WebsiteBundle:Form' + 'form_themes' ), ), ), From 206bf70c45e4b992c664c40efe3a5146e95fd6d2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 24 Nov 2017 16:12:49 +0100 Subject: [PATCH 0140/2437] Updated Doctrine config reference about bundles --- reference/configuration/doctrine.rst | 35 +++++++++++----------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index a21e77ad6ed..5c5ea0c5b48 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -492,42 +492,35 @@ you can control. The following configuration options exist for a mapping: type .... -One of ``annotation``, ``xml``, ``yml``, ``php`` or ``staticphp``. This -specifies which type of metadata type your mapping uses. +One of ``annotation`` (the default value), ``xml``, ``yml``, ``php`` or +``staticphp``. This specifies which type of metadata type your mapping uses. dir ... -Path to the mapping or entity files (depending on the driver). If this path -is relative it is assumed to be relative to the bundle root. This only works -if the name of your mapping is a bundle name. If you want to use this option -to specify absolute paths you should prefix the path with the kernel parameters -that exist in the DIC (for example ``%kernel.project_dir%``). +Absolute path to the mapping or entity files (depending on the driver). The +default value is ``%kernel.project_dir%/src/Entity/``. prefix ...... -A common namespace prefix that all entities of this mapping share. This -prefix should never conflict with prefixes of other defined mappings otherwise -some of your entities cannot be found by Doctrine. This option defaults -to the bundle namespace + ``Entity``, for example for an application bundle -called AcmeHelloBundle prefix would be ``Acme\HelloBundle\Entity``. +A common namespace prefix that all entities of this mapping share. This prefix +should never conflict with prefixes of other defined mappings otherwise some of +your entities cannot be found by Doctrine. This option defaults to +``App\Entity`` because it's recommended to store the entities in ``src/Entity/``. alias ..... Doctrine offers a way to alias entity namespaces to simpler, shorter names -to be used in DQL queries or for Repository access. When using a bundle -the alias defaults to the bundle name. +to be used in DQL queries or for Repository access. It's default value is ``App``. is_bundle ......... -This option is a derived value from ``dir`` and by default is set to ``true`` -if dir is relative proved by a ``file_exists()`` check that returns ``false``. -It is ``false`` if the existence check returns ``true``. In this case an -absolute path was specified and the metadata files are most likely in a -directory outside of a bundle. +This option is ``false`` by default and it's considered a legacy option. It was +only useful in previous Symfony versions, when it was recommended to use bundles +to organize the application code. Custom Mapping Entities in a Bundle ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -593,9 +586,7 @@ directory instead: Mapping Entities Outside of a Bundle ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You can also create new mappings, for example outside of the Symfony folder. - -For example, the following looks for entity classes in the ``App\Entity`` +For example, the following looks for entity classes in the ``Entity`` namespace in the ``src/Entity`` directory and gives them an ``App`` alias (so you can say things like ``App:Post``): From c34b0bf4235996e9d55df1e1fab73b70ce3f5a2e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 11:11:01 +0100 Subject: [PATCH 0141/2437] Removed the deprecated class_loader component --- _build/redirection_map | 7 + components/class_loader.rst | 67 +-------- .../class_loader/cache_class_loader.rst | 15 -- components/class_loader/class_loader.rst | 75 ---------- .../class_loader/class_map_generator.rst | 128 ------------------ .../class_loader/debug_class_loader.rst | 8 -- components/class_loader/map_class_loader.rst | 41 ------ components/class_loader/psr4_class_loader.rst | 61 --------- 8 files changed, 9 insertions(+), 393 deletions(-) delete mode 100644 components/class_loader/cache_class_loader.rst delete mode 100644 components/class_loader/class_loader.rst delete mode 100644 components/class_loader/class_map_generator.rst delete mode 100644 components/class_loader/debug_class_loader.rst delete mode 100644 components/class_loader/map_class_loader.rst delete mode 100644 components/class_loader/psr4_class_loader.rst diff --git a/_build/redirection_map b/_build/redirection_map index 146e731e460..2e17fc24b8e 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -291,6 +291,13 @@ /components/browser_kit/introduction /components/browser_kit /components/class_loader/introduction /components/class_loader /components/class_loader/index /components/class_loader +/components/class_loader/cache_class_loader /components/class_loader +/components/class_loader/class_loader /components/class_loader +/components/class_loader/class_map_generator /components/class_loader +/components/class_loader/debug_class_loader /components/class_loader +/components/class_loader/map_class_loader /components/class_loader +/components/class_loader/map_class_loader /components/class_loader +/components/class_loader/psr4_class_loader /components/class_loader /components/config/introduction /components/config /components/config/index /components/config /components/console/helpers/tablehelper /components/console/helpers/table diff --git a/components/class_loader.rst b/components/class_loader.rst index 74c275a055a..f3268b1ca71 100644 --- a/components/class_loader.rst +++ b/components/class_loader.rst @@ -4,72 +4,9 @@ The ClassLoader Component ========================= - The ClassLoader component provides tools to autoload your classes and - cache their locations for performance. - .. caution:: - The ClassLoader component was deprecated in Symfony 3.3 and it will be - removed in 4.0. As an alternative, use any of the `class loading optimizations`_ - provided by Composer. - -Usage ------ - -Whenever you reference a class that has not been required or included yet, -PHP uses the `autoloading mechanism`_ to delegate the loading of a file -defining the class. Symfony provides three autoloaders, which are able to -load your classes: - -* :doc:`/components/class_loader/class_loader`: loads classes that follow - the `PSR-0`_ class naming standard; - -* :doc:`/components/class_loader/psr4_class_loader`: loads classes that follow - the `PSR-4`_ class naming standard; - -* :doc:`/components/class_loader/map_class_loader`: loads classes using - a static map from class name to file path. - -Additionally, the Symfony ClassLoader component ships with a wrapper class -which makes it possible -:doc:`to cache the results of a class loader `. - -When using the :doc:`Debug component `, you -can also use a special :ref:`DebugClassLoader ` -that eases debugging by throwing more helpful exceptions when a class could -not be found by a class loader. - -Installation ------------- - -You can install the component in 2 different ways: - -* :doc:`Install it via Composer ` (``symfony/class-loader`` - on `Packagist`_); -* Use the official Git repository (https://github.com/symfony/class-loader). - -.. include:: /components/require_autoload.rst.inc - -Learn More ----------- - -.. toctree:: - :glob: - :maxdepth: 1 - - class_loader/class_loader - class_loader/class_map_generator.rst - class_loader/debug_class_loader.rst - class_loader/map_class_loader.rst - class_loader/psr4_class_loader.rst - -.. toctree:: - :hidden: - - class_loader/cache_class_loader + The ClassLoader component was removed in Symfony 4.0. As an alternative, use + any of the `class loading optimizations`_ provided by Composer. -.. _PSR-0: http://www.php-fig.org/psr/psr-0/ -.. _PSR-4: http://www.php-fig.org/psr/psr-4/ -.. _`autoloading mechanism`: http://php.net/manual/en/language.oop5.autoload.php -.. _Packagist: https://packagist.org/packages/symfony/class-loader .. _`class loading optimizations`: https://getcomposer.org/doc/articles/autoloader-optimization.md diff --git a/components/class_loader/cache_class_loader.rst b/components/class_loader/cache_class_loader.rst deleted file mode 100644 index a75f743826c..00000000000 --- a/components/class_loader/cache_class_loader.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. index:: - single: APC; ApcClassLoader - single: ClassLoader; ApcClassLoader - single: ClassLoader; Cache - single: ClassLoader; XcacheClassLoader - single: XCache; XcacheClassLoader - -Cache a Class Loader -==================== - -The ``ApcClassLoader``, the ``WinCacheClassLoader`` and the ``XcacheClassLoader`` -are deprecated since Symfony 3.3. As an alternative, use any of the -`class loading optimizations`_ provided by Composer. - -.. _`class loading optimizations`: https://getcomposer.org/doc/articles/autoloader-optimization.md diff --git a/components/class_loader/class_loader.rst b/components/class_loader/class_loader.rst deleted file mode 100644 index adf9b6e52b2..00000000000 --- a/components/class_loader/class_loader.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. index:: - single: ClassLoader; PSR-0 Class Loader - -The PSR-0 Class Loader -====================== - -If your classes and third-party libraries follow the `PSR-0`_ standard, -you can use the :class:`Symfony\\Component\\ClassLoader\\ClassLoader` class -to load all of your project's classes. - -.. tip:: - - You can use both the ``ApcClassLoader`` and the ``XcacheClassLoader`` - to :doc:`cache ` a ``ClassLoader`` - instance. - -Usage ------ - -Registering the :class:`Symfony\\Component\\ClassLoader\\ClassLoader` autoloader -is straightforward:: - - require_once '/path/to/src/Symfony/Component/ClassLoader/ClassLoader.php'; - - use Symfony\Component\ClassLoader\ClassLoader; - - $loader = new ClassLoader(); - - // to enable searching the include path (eg. for PEAR packages) - $loader->setUseIncludePath(true); - - // ... register namespaces and prefixes here - see below - - $loader->register(); - -Use :method:`Symfony\\Component\\ClassLoader\\ClassLoader::addPrefix` or -:method:`Symfony\\Component\\ClassLoader\\ClassLoader::addPrefixes` to register -your classes:: - - // register a single namespaces - $loader->addPrefix('Symfony', __DIR__.'/vendor/symfony/symfony/src'); - - // register several namespaces at once - $loader->addPrefixes(array( - 'Symfony' => __DIR__.'/../vendor/symfony/symfony/src', - 'Monolog' => __DIR__.'/../vendor/monolog/monolog/src', - )); - - // register a prefix for a class following the PEAR naming conventions - $loader->addPrefix('Twig_', __DIR__.'/vendor/twig/twig/lib'); - - $loader->addPrefixes(array( - 'Swift_' => __DIR__.'/vendor/swiftmailer/swiftmailer/lib/classes', - 'Twig_' => __DIR__.'/vendor/twig/twig/lib', - )); - -Classes from a sub-namespace or a sub-hierarchy of `PEAR`_ classes can be -looked for in a location list to ease the vendoring of a sub-set of classes -for large projects:: - - $loader->addPrefixes(array( - 'Doctrine\Common' => __DIR__.'/vendor/doctrine/common/lib', - 'Doctrine\DBAL\Migrations' => __DIR__.'/vendor/doctrine/migrations/lib', - 'Doctrine\DBAL' => __DIR__.'/vendor/doctrine/dbal/lib', - 'Doctrine' => __DIR__.'/vendor/doctrine/orm/lib', - )); - -In this example, if you try to use a class in the ``Doctrine\Common`` namespace -or one of its children, the autoloader will first look for the class under -the ``doctrine-common`` directory. If not found, it will then fallback to -the default ``Doctrine`` directory (the last one configured) before giving -up. The order of the prefix registrations is significant in this case. - -.. _PEAR: http://pear.php.net/manual/en/standards.naming.php -.. _PSR-0: http://www.php-fig.org/psr/psr-0/ diff --git a/components/class_loader/class_map_generator.rst b/components/class_loader/class_map_generator.rst deleted file mode 100644 index da1a9c73ab4..00000000000 --- a/components/class_loader/class_map_generator.rst +++ /dev/null @@ -1,128 +0,0 @@ -.. index:: - single: Autoloading; Class Map Generator - single: ClassLoader; Class Map Generator - -The Class Map Generator -======================= - -Loading a class usually is an easy task given the `PSR-0`_ and `PSR-4`_ -standards. Thanks to the Symfony ClassLoader component or the autoloading -mechanism provided by Composer, you don't have to map your class names to -actual PHP files manually. Nowadays, PHP libraries usually come with autoloading -support through Composer. - -But from time to time you may have to use a third-party library that comes -without any autoloading support and therefore forces you to load each class -manually. For example, imagine a library with the following directory structure: - -.. code-block:: text - - library/ - ├── bar/ - │   ├── baz/ - │   │   └── Boo.php - │   └── Foo.php - └── foo/ - ├── bar/ - │   └── Foo.php - └── Bar.php - -These files contain the following classes: - -=========================== ================ -File Class Name -=========================== ================ -``library/bar/baz/Boo.php`` ``Acme\Bar\Baz`` -``library/bar/Foo.php`` ``Acme\Bar`` -``library/foo/bar/Foo.php`` ``Acme\Foo\Bar`` -``library/foo/Bar.php`` ``Acme\Foo`` -=========================== ================ - -To make your life easier, the ClassLoader component comes with a -:class:`Symfony\\Component\\ClassLoader\\ClassMapGenerator` class that makes -it possible to create a map of class names to files. - -Generating a Class Map ----------------------- - -To generate the class map, simply pass the root directory of your class -files to the -:method:`Symfony\\Component\\ClassLoader\\ClassMapGenerator::createMap` -method:: - - use Symfony\Component\ClassLoader\ClassMapGenerator; - - var_dump(ClassMapGenerator::createMap(__DIR__.'/library')); - -Given the files and class from the table above, you should see an output -like this: - -.. code-block:: text - - Array - ( - [Acme\Foo] => /var/www/library/foo/Bar.php - [Acme\Foo\Bar] => /var/www/library/foo/bar/Foo.php - [Acme\Bar\Baz] => /var/www/library/bar/baz/Boo.php - [Acme\Bar] => /var/www/library/bar/Foo.php - ) - -Dumping the Class Map ---------------------- - -Writing the class map to the console output is not really sufficient when -it comes to autoloading. Luckily, the ``ClassMapGenerator`` provides the -:method:`Symfony\\Component\\ClassLoader\\ClassMapGenerator::dump` method -to save the generated class map to the filesystem:: - - use Symfony\Component\ClassLoader\ClassMapGenerator; - - ClassMapGenerator::dump(__DIR__.'/library', __DIR__.'/class_map.php'); - -This call to ``dump()`` generates the class map and writes it to the ``class_map.php`` -file in the same directory with the following contents:: - - '/var/www/library/foo/Bar.php', - 'Acme\\Foo\\Bar' => '/var/www/library/foo/bar/Foo.php', - 'Acme\\Bar\\Baz' => '/var/www/library/bar/baz/Boo.php', - 'Acme\\Bar' => '/var/www/library/bar/Foo.php', - ); - -Instead of loading each file manually, you'll only have to register the -generated class map with, for example, the -:class:`Symfony\\Component\\ClassLoader\\MapClassLoader`:: - - use Symfony\Component\ClassLoader\MapClassLoader; - - $mapping = include __DIR__.'/class_map.php'; - $loader = new MapClassLoader($mapping); - $loader->register(); - - // you can now use the classes: - use Acme\Foo; - - $foo = new Foo(); - - // ... - -.. note:: - - The example assumes that you already have autoloading working (e.g. - through `Composer`_ or one of the other class loaders from the ClassLoader - component. - -Besides dumping the class map for one directory, you can also pass an array -of directories for which to generate the class map (the result actually -is the same as in the example above):: - - use Symfony\Component\ClassLoader\ClassMapGenerator; - - ClassMapGenerator::dump( - array(__DIR__.'/library/bar', __DIR__.'/library/foo'), - __DIR__.'/class_map.php' - ); - -.. _`PSR-0`: http://www.php-fig.org/psr/psr-0 -.. _`PSR-4`: http://www.php-fig.org/psr/psr-4 -.. _`Composer`: https://getcomposer.org diff --git a/components/class_loader/debug_class_loader.rst b/components/class_loader/debug_class_loader.rst deleted file mode 100644 index 1bd3446af27..00000000000 --- a/components/class_loader/debug_class_loader.rst +++ /dev/null @@ -1,8 +0,0 @@ -Debugging a Class Loader -======================== - -.. caution:: - - The ``DebugClassLoader`` from the ClassLoader component was deprecated - in Symfony 2.5 and removed in Symfony 3.0. Use the - :ref:`DebugClassLoader provided by the Debug component `. diff --git a/components/class_loader/map_class_loader.rst b/components/class_loader/map_class_loader.rst deleted file mode 100644 index f9bd70abfa4..00000000000 --- a/components/class_loader/map_class_loader.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. index:: - single: ClassLoader; MapClassLoader - -MapClassLoader -============== - -The :class:`Symfony\\Component\\ClassLoader\\MapClassLoader` allows you -to autoload files via a static map from classes to files. This is useful -if you use third-party libraries which don't follow the `PSR-0`_ standards -and so can't use the -:doc:`PSR-0 class loader `. - -The ``MapClassLoader`` can be used along with the -:doc:`PSR-0 class loader ` by -configuring and calling the ``register()`` method on both. - -.. note:: - - The default behavior is to append the ``MapClassLoader`` on the autoload - stack. If you want to use it as the first autoloader, pass ``true`` - when calling the ``register()`` method. Your class loader will then - be prepended on the autoload stack. - -Usage ------ - -Using it is as easy as passing your mapping to its constructor when creating -an instance of the ``MapClassLoader`` class:: - - require_once '/path/to/src/Symfony/Component/ClassLoader/MapClassLoader.php'; - - $mapping = array( - 'Foo' => '/path/to/Foo', - 'Bar' => '/path/to/Bar', - ); - - $loader = new MapClassLoader($mapping); - - $loader->register(); - -.. _PSR-0: http://www.php-fig.org/psr/psr-0/ diff --git a/components/class_loader/psr4_class_loader.rst b/components/class_loader/psr4_class_loader.rst deleted file mode 100644 index dc66614892b..00000000000 --- a/components/class_loader/psr4_class_loader.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. index:: - single: ClassLoader; PSR-4 Class Loader - -The PSR-4 Class Loader -====================== - -Libraries that follow the `PSR-4`_ standard can be loaded with the ``Psr4ClassLoader``. - -.. note:: - - If you manage your dependencies via Composer, you get a PSR-4 compatible - autoloader out of the box. Use this loader in environments where Composer - is not available. - -.. tip:: - - All Symfony components follow PSR-4. - -Usage ------ - -The following example demonstrates how you can use the -:class:`Symfony\\Component\\ClassLoader\\Psr4ClassLoader` autoloader to use -Symfony's Yaml component. Imagine, you downloaded both the ClassLoader and -Yaml component as ZIP packages and unpacked them to a ``libs`` directory. -The directory structure will look like this: - -.. code-block:: text - - libs/ - ClassLoader/ - Psr4ClassLoader.php - ... - Yaml/ - Yaml.php - ... - config.yml - demo.php - -In ``demo.php`` you are going to parse the ``config.yml`` file. To do that, you -first need to configure the ``Psr4ClassLoader``:: - - use Symfony\Component\ClassLoader\Psr4ClassLoader; - use Symfony\Component\Yaml\Yaml; - - require __DIR__.'/lib/ClassLoader/Psr4ClassLoader.php'; - - $loader = new Psr4ClassLoader(); - $loader->addPrefix('Symfony\Component\Yaml\\', __DIR__.'/lib/Yaml'); - $loader->register(); - - $data = Yaml::parse(file_get_contents(__DIR__.'/config.yml')); - -First of all, the class loader is loaded manually using a ``require`` -statement, since there is no autoload mechanism yet. With the -:method:`Symfony\\Component\\ClassLoader\\Psr4ClassLoader::addPrefix` call, you -tell the class loader where to look for classes with the -``Symfony\Component\Yaml\`` namespace prefix. After registering the autoloader, -the Yaml component is ready to be used. - -.. _PSR-4: http://www.php-fig.org/psr/psr-4/ From a8bc89c006aa227aa47a137d303ea8aedc97dfc6 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 11:15:28 +0100 Subject: [PATCH 0142/2437] Removed the deprecated Console Dialog Helper --- _build/redirection_map | 1 + components/console/helpers/dialoghelper.rst | 12 ------------ 2 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 components/console/helpers/dialoghelper.rst diff --git a/_build/redirection_map b/_build/redirection_map index 2e17fc24b8e..1e0245956ea 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -302,6 +302,7 @@ /components/config/index /components/config /components/console/helpers/tablehelper /components/console/helpers/table /components/console/helpers/progresshelper /components/console/helpers/progressbar +/components/console/helpers/dialoghelper /components/console/helpers/questionhelper /components/console/introduction /components/console /components/console/index /components/console /components/debug/class_loader /components/debug diff --git a/components/console/helpers/dialoghelper.rst b/components/console/helpers/dialoghelper.rst deleted file mode 100644 index 8618ffcba17..00000000000 --- a/components/console/helpers/dialoghelper.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. index:: - single: Console Helpers; Dialog Helper - -Dialog Helper -============= - -.. caution:: - - The Dialog Helper was deprecated in Symfony 2.5 and removed in - Symfony 3.0. You should now use the - :doc:`Question Helper ` instead, - which is simpler to use. From a4db8b8d47a0a4bfbc5ac03befe349a39b9e7226 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 11:29:24 +0100 Subject: [PATCH 0143/2437] Use .yaml instead of .yml as extension --- components/config/caching.rst | 2 +- components/config/definition.rst | 4 ++-- components/config/resources.rst | 10 +++++----- .../_imports-parameters-note.rst.inc | 12 ++++++------ components/dependency_injection/compilation.rst | 2 +- components/http_foundation/session_configuration.rst | 2 +- components/property_info.rst | 2 +- components/routing.rst | 8 ++++---- components/serializer.rst | 4 ++-- components/translation.rst | 2 +- components/translation/custom_formats.rst | 2 +- components/validator/resources.rst | 6 +++--- components/yaml.rst | 10 +++++----- 13 files changed, 33 insertions(+), 33 deletions(-) diff --git a/components/config/caching.rst b/components/config/caching.rst index 99cd4f6a2b1..7881306a4b8 100644 --- a/components/config/caching.rst +++ b/components/config/caching.rst @@ -32,7 +32,7 @@ should be regenerated:: $userMatcherCache = new ConfigCache($cachePath, true); if (!$userMatcherCache->isFresh()) { - // fill this with an array of 'users.yml' file paths + // fill this with an array of 'users.yaml' file paths $yamlUserFiles = ...; $resources = array(); diff --git a/components/config/definition.rst b/components/config/definition.rst index 43025d3178d..d3346a5f9fc 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -804,10 +804,10 @@ Otherwise the result is a clean array of configuration values:: use Acme\DatabaseConfiguration; $config1 = Yaml::parse( - file_get_contents(__DIR__.'/src/Matthias/config/config.yml') + file_get_contents(__DIR__.'/src/Matthias/config/config.yaml') ); $config2 = Yaml::parse( - file_get_contents(__DIR__.'/src/Matthias/config/config_extra.yml') + file_get_contents(__DIR__.'/src/Matthias/config/config_extra.yaml') ); $configs = array($config1, $config2); diff --git a/components/config/resources.rst b/components/config/resources.rst index de88b483b42..79681d1000e 100644 --- a/components/config/resources.rst +++ b/components/config/resources.rst @@ -22,7 +22,7 @@ files. This can be done with the :class:`Symfony\\Component\\Config\\FileLocator $configDirectories = array(__DIR__.'/app/config'); $locator = new FileLocator($configDirectories); - $yamlUserFiles = $locator->locate('users.yml', null, false); + $yamlUserFiles = $locator->locate('users.yaml', null, false); The locator receives a collection of locations where it should look for files. The first argument of ``locate()`` is the name of the file to look @@ -53,12 +53,12 @@ which allows for recursively importing other resources:: // maybe import some other resource: - // $this->import('extra_users.yml'); + // $this->import('extra_users.yaml'); } public function supports($resource, $type = null) { - return is_string($resource) && 'yml' === pathinfo( + return is_string($resource) && 'yaml' === pathinfo( $resource, PATHINFO_EXTENSION ); @@ -88,5 +88,5 @@ the resource:: $delegatingLoader = new DelegatingLoader($loaderResolver); // YamlUserLoader is used to load this resource because it supports - // files with the '.yml' extension - $delegatingLoader->load(__DIR__.'/users.yml'); + // files with the '.yaml' extension + $delegatingLoader->load(__DIR__.'/users.yaml'); diff --git a/components/dependency_injection/_imports-parameters-note.rst.inc b/components/dependency_injection/_imports-parameters-note.rst.inc index 3b479e70ba6..eb68a4dbdcc 100644 --- a/components/dependency_injection/_imports-parameters-note.rst.inc +++ b/components/dependency_injection/_imports-parameters-note.rst.inc @@ -8,13 +8,13 @@ .. code-block:: yaml - # app/config/config.yml + # config/services.yaml imports: - - { resource: '%kernel.project_dir%/somefile.yml' } + - { resource: '%kernel.project_dir%/somefile.yaml' } .. code-block:: xml - + - + .. code-block:: php - // app/config/config.php - $loader->import('%kernel.project_dir%/somefile.yml'); + // config/services.php + $loader->import('%kernel.project_dir%/somefile.yaml'); diff --git a/components/dependency_injection/compilation.rst b/components/dependency_injection/compilation.rst index d2b494ab4ca..38ca077f743 100644 --- a/components/dependency_injection/compilation.rst +++ b/components/dependency_injection/compilation.rst @@ -121,7 +121,7 @@ are loaded:: $container->registerExtension(new AcmeDemoExtension); $loader = new YamlFileLoader($container, new FileLocator(__DIR__)); - $loader->load('config.yml'); + $loader->load('config.yaml'); // ... $container->compile(); diff --git a/components/http_foundation/session_configuration.rst b/components/http_foundation/session_configuration.rst index ca5524adbe4..42edb3752c9 100644 --- a/components/http_foundation/session_configuration.rst +++ b/components/http_foundation/session_configuration.rst @@ -147,7 +147,7 @@ configuration: .. code-block:: yaml - # config.yml + # config/packages/framework.yaml framework: session: gc_probability: null diff --git a/components/property_info.rst b/components/property_info.rst index 8e642a03e31..40f6c667343 100644 --- a/components/property_info.rst +++ b/components/property_info.rst @@ -355,7 +355,7 @@ It can also provide return and scalar types for PHP 7+. .. code-block:: yaml - # app/config/config.yml + # config/packages/framework.yaml framework: property_info: enabled: true diff --git a/components/routing.rst b/components/routing.rst index 4afb1c663c5..089c688469b 100644 --- a/components/routing.rst +++ b/components/routing.rst @@ -246,7 +246,7 @@ If you're using the ``YamlFileLoader``, then route definitions look like this: .. code-block:: yaml - # routes.yml + # routes.yaml route1: path: /foo defaults: { _controller: 'MyController::fooAction' } @@ -256,7 +256,7 @@ If you're using the ``YamlFileLoader``, then route definitions look like this: defaults: { _controller: 'MyController::foobarAction' } To load this file, you can use the following code. This assumes that your -``routes.yml`` file is in the same directory as the below code:: +``routes.yaml`` file is in the same directory as the below code:: use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\YamlFileLoader; @@ -264,7 +264,7 @@ To load this file, you can use the following code. This assumes that your // look inside *this* directory $locator = new FileLocator(array(__DIR__)); $loader = new YamlFileLoader($locator); - $collection = $loader->load('routes.yml'); + $collection = $loader->load('routes.yaml'); Besides :class:`Symfony\\Component\\Routing\\Loader\\YamlFileLoader` there are two other loaders that work the same way: @@ -337,7 +337,7 @@ automatically in the background if you want to use it. A basic example of the $router = new Router( new YamlFileLoader($locator), - 'routes.yml', + 'routes.yaml', array('cache_dir' => __DIR__.'/cache'), $requestContext ); diff --git a/components/serializer.rst b/components/serializer.rst index 1377ff19bdf..765a0ecd28b 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -21,7 +21,7 @@ the middle. This way, Encoders will only deal with turning specific **formats** into **arrays** and vice versa. The same way, Normalizers will deal with turning specific **objects** into **arrays** and vice versa. -Serialization is a complex topic. This component may not cover all your use cases out of the box, +Serialization is a complex topic. This component may not cover all your use cases out of the box, but it can be useful for developing tools to serialize and deserialize your objects. Installation @@ -243,7 +243,7 @@ like the following:: // For XML // $classMetadataFactory = new ClassMetadataFactory(new XmlFileLoader('/path/to/your/definition.xml')); // For YAML - // $classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader('/path/to/your/definition.yml')); + // $classMetadataFactory = new ClassMetadataFactory(new YamlFileLoader('/path/to/your/definition.yaml')); .. _component-serializer-attributes-groups-annotations: diff --git a/components/translation.rst b/components/translation.rst index dfbf9fd6259..52e70f35008 100644 --- a/components/translation.rst +++ b/components/translation.rst @@ -128,7 +128,7 @@ file as the second argument, instead of an array:: // ... $translator->addLoader('yaml', new YamlFileLoader()); - $translator->addResource('yaml', 'path/to/messages.fr.yml', 'fr_FR'); + $translator->addResource('yaml', 'path/to/messages.fr.yaml', 'fr_FR'); The Translation Process ----------------------- diff --git a/components/translation/custom_formats.rst b/components/translation/custom_formats.rst index d5d9ddcd446..3f9997d502d 100644 --- a/components/translation/custom_formats.rst +++ b/components/translation/custom_formats.rst @@ -119,7 +119,7 @@ YAML file are dumped into a text file with the custom format:: use Symfony\Component\Translation\Loader\YamlFileLoader; $loader = new YamlFileLoader(); - $catalogue = $loader->load(__DIR__ . '/translations/messages.fr_FR.yml' , 'fr_FR'); + $catalogue = $loader->load(__DIR__ . '/translations/messages.fr_FR.yaml' , 'fr_FR'); $dumper = new MyFormatDumper(); $dumper->dump($catalogue, array('path' => __DIR__.'/dumps')); diff --git a/components/validator/resources.rst b/components/validator/resources.rst index 7ee7c286f08..c3c2677b99e 100644 --- a/components/validator/resources.rst +++ b/components/validator/resources.rst @@ -71,7 +71,7 @@ configure the locations of these files:: use Symfony\Component\Validator\Validation; $validator = Validation::createValidatorBuilder() - ->addYamlMapping('config/validation.yml') + ->addYamlMapping('config/validation.yaml') ->getValidator(); .. note:: @@ -173,13 +173,13 @@ Using a Custom MetadataFactory ------------------------------ All the loaders and the cache are passed to an instance of -:class:`Symfony\\Component\\Validator\\Mapping\\Factory\\LazyLoadingMetadataFactory`. +:class:`Symfony\\Component\\Validator\\Mapping\\Factory\\LazyLoadingMetadataFactory`. This class is responsible for creating a ``ClassMetadata`` instance from all the configured resources. You can also use a custom metadata factory implementation by creating a class which implements -:class:`Symfony\\Component\\Validator\\Mapping\\Factory\\MetadataFactoryInterface`. +:class:`Symfony\\Component\\Validator\\Mapping\\Factory\\MetadataFactoryInterface`. You can set this custom implementation using :method:`Symfony\\Component\\Validator\\ValidatorBuilder::setMetadataFactory`:: diff --git a/components/yaml.rst b/components/yaml.rst index dbb20fb0a30..af8e1a97833 100644 --- a/components/yaml.rst +++ b/components/yaml.rst @@ -128,7 +128,7 @@ contents of the given file path and converts them to a PHP value:: use Symfony\Component\Yaml\Yaml; - $value = Yaml::parseFile('/path/to/file.yml'); + $value = Yaml::parseFile('/path/to/file.yaml'); If an error occurs during parsing, the parser throws a ``ParseException`` exception. @@ -151,7 +151,7 @@ array to its YAML representation: $yaml = Yaml::dump($array); - file_put_contents('/path/to/file.yml', $yaml); + file_put_contents('/path/to/file.yaml', $yaml); If an error occurs during the dump, the parser throws a :class:`Symfony\\Component\\Yaml\\Exception\\DumpException` exception. @@ -356,20 +356,20 @@ Then, execute the script for validating contents: .. code-block:: terminal # validates a single file - $ php lint.php path/to/file.yml + $ php lint.php path/to/file.yaml # or all the files in a directory $ php lint.php path/to/directory # or contents passed to STDIN - $ cat path/to/file.yml | php lint.php + $ cat path/to/file.yaml | php lint.php The result is written to STDOUT and uses a plain text format by default. Add the ``--format`` option to get the output in JSON format: .. code-block:: terminal - $ php lint.php path/to/file.yml --format json + $ php lint.php path/to/file.yaml --format json .. tip:: From 8b48cc9a45c051550810988afeaf58ba97d504df Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 12:14:12 +0100 Subject: [PATCH 0144/2437] Remove bundle references --- components/form.rst | 18 +++++++++--------- components/http_kernel.rst | 36 +++++++++++++++++------------------- components/var_dumper.rst | 4 ++-- email/spool.rst | 2 ++ 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/components/form.rst b/components/form.rst index 1cc82b62997..ac31f2cc164 100644 --- a/components/form.rst +++ b/components/form.rst @@ -398,17 +398,17 @@ is created from the form factory. .. code-block:: php-symfony - // src/Acme/TaskBundle/Controller/DefaultController.php - namespace Acme\TaskBundle\Controller; + // src/Controller/TaskController.php + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\DateType; - class DefaultController extends Controller + class TaskController extends Controller { - public function newAction(Request $request) + public function new(Request $request) { // createFormBuilder is a shortcut to get the "form factory" // and then call "createBuilder()" on it @@ -418,7 +418,7 @@ is created from the form factory. ->add('dueDate', DateType::class) ->getForm(); - return $this->render('@AcmeTask/Default/new.html.twig', array( + return $this->render('task/new.html.twig', array( 'form' => $form->createView(), )); } @@ -604,16 +604,16 @@ method: .. code-block:: php-symfony - // src/Acme/TaskBundle/Controller/DefaultController.php - namespace Acme\TaskBundle\Controller; + // src/Controller/TaskController.php + namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\TextType; - class DefaultController extends Controller + class TaskController extends Controller { - public function newAction(Request $request) + public function new(Request $request) { $form = $this->createFormBuilder() ->add('task', TextType::class) diff --git a/components/http_kernel.rst b/components/http_kernel.rst index b72152ec13c..5dea91c8447 100644 --- a/components/http_kernel.rst +++ b/components/http_kernel.rst @@ -256,11 +256,11 @@ on the request's information. information is typically placed on the ``Request`` via the ``RouterListener``). This string is then transformed into a PHP callable by doing the following: - a) The ``AcmeDemoBundle:Default:index`` format of the ``_controller`` key - is changed to another string that contains the full class and method - name of the controller by following the convention used in Symfony - e.g. - ``Acme\DemoBundle\Controller\DefaultController::indexAction``. This transformation - is specific to the :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver` + a) If the ``_controller`` key doesn't follow the recommended PHP namespace + format (e.g. ``App\Controller\DefaultController::index``) its format is + transformed into it. For example, the legacy ``AppBundle:Default:index`` + format would be changed to ``Acme\AppBundle\Controller\DefaultController::indexAction``. + This transformation is specific to the :class:`Symfony\\Bundle\\FrameworkBundle\\Controller\\ControllerResolver` sub-class used by the Symfony Framework. b) A new instance of your controller class is instantiated with no @@ -300,11 +300,10 @@ on the event object that's passed to listeners on this event. the Symfony Framework, and many deal with collecting profiler data when the profiler is enabled. - One interesting listener comes from the `SensioFrameworkExtraBundle`_, - which is packaged with the Symfony Standard Edition. This listener's - `@ParamConverter`_ functionality allows you to pass a full object (e.g. a - ``Post`` object) to your controller instead of a scalar value (e.g. an - ``id`` parameter that was on your route). The listener - + One interesting listener comes from the `SensioFrameworkExtraBundle`_. This + listener's `@ParamConverter`_ functionality allows you to pass a full object + (e.g. a ``Post`` object) to your controller instead of a scalar value (e.g. + an ``id`` parameter that was on your route). The listener - ``ParamConverterListener`` - uses reflection to look at each of the arguments of the controller and tries to use different methods to convert those to objects, which are then stored in the ``attributes`` property of @@ -423,12 +422,11 @@ return a ``Response``. .. sidebar:: ``kernel.view`` in the Symfony Framework There is no default listener inside the Symfony Framework for the ``kernel.view`` - event. However, one core bundle - `SensioFrameworkExtraBundle`_ - *does* - add a listener to this event. If your controller returns an array, - and you place the `@Template`_ annotation above the controller, then this - listener renders a template, passes the array you returned from your - controller to that template, and creates a ``Response`` containing the - returned content from that template. + event. However, `SensioFrameworkExtraBundle`_ *does* add a listener to this + event. If your controller returns an array, and you place the `@Template`_ + annotation above the controller, then this listener renders a template, + passes the array you returned from your controller to that template, and + creates a ``Response`` containing the returned content from that template. Additionally, a popular community bundle `FOSRestBundle`_ implements a listener on this event which aims to give you a robust view layer @@ -514,9 +512,9 @@ as possible to the client (e.g. sending emails). .. sidebar:: ``kernel.terminate`` in the Symfony Framework - If you use the SwiftmailerBundle with Symfony and use ``memory`` spooling, - then the `EmailSenderListener`_ is activated, which actually delivers - any emails that you scheduled to send during the request. + If you use the :ref:`memory spooling ` option of the + default Symfony mailer, then the `EmailSenderListener`_ is activated, which + actually delivers any emails that you scheduled to send during the request. .. _component-http-kernel-kernel-exception: diff --git a/components/var_dumper.rst b/components/var_dumper.rst index 98b0a35b68d..c8673d08364 100644 --- a/components/var_dumper.rst +++ b/components/var_dumper.rst @@ -19,8 +19,8 @@ You can install the component in 2 different ways: .. note:: - If using it inside a Symfony application, make sure that the - DebugBundle is enabled in your ``app/AppKernel.php`` file. + If using it inside a Symfony application, make sure that the DebugBundle has + been installed (or run ``composer required debug`` to install it). .. _components-var-dumper-dump: diff --git a/email/spool.rst b/email/spool.rst index d8afa6ba88d..9c6ad04843e 100644 --- a/email/spool.rst +++ b/email/spool.rst @@ -15,6 +15,8 @@ it somewhere such as a file. Another process can then read from the spool and take care of sending the emails in the spool. Currently only spooling to file or memory is supported. +.. _email-spool-memory: + Spool Using Memory ------------------ From 0c0c07638bbfd66a2726a9999517e065bb86536d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 12:15:25 +0100 Subject: [PATCH 0145/2437] Remove app/ references --- components/config/resources.rst | 2 +- components/dependency_injection/workflow.rst | 2 +- components/phpunit_bridge.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/config/resources.rst b/components/config/resources.rst index 79681d1000e..b1ea7b2c269 100644 --- a/components/config/resources.rst +++ b/components/config/resources.rst @@ -19,7 +19,7 @@ files. This can be done with the :class:`Symfony\\Component\\Config\\FileLocator use Symfony\Component\Config\FileLocator; - $configDirectories = array(__DIR__.'/app/config'); + $configDirectories = array(__DIR__.'/config'); $locator = new FileLocator($configDirectories); $yamlUserFiles = $locator->locate('users.yaml', null, false); diff --git a/components/dependency_injection/workflow.rst b/components/dependency_injection/workflow.rst index 5ad8ae7c3d8..750420f4d47 100644 --- a/components/dependency_injection/workflow.rst +++ b/components/dependency_injection/workflow.rst @@ -34,7 +34,7 @@ for more details. Application-level Configuration ------------------------------- -Application level config is loaded from the ``app/config`` directory. Multiple +Application level config is loaded from the ``config`` directory. Multiple files are loaded which are then merged when the extensions are processed. This allows for different configuration for different environments e.g. dev, prod. diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 1a62e472b7f..a528ec56f1c 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -134,7 +134,7 @@ message, enclosed with ``/``. For example, with: - + From 5828b2f3ccfe9ff6e8365c68dde1b044d15a3e57 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 12:34:27 +0100 Subject: [PATCH 0146/2437] Remove a deleted article --- components/console/helpers/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/components/console/helpers/index.rst b/components/console/helpers/index.rst index 38a8c2a7939..87c62ca7629 100644 --- a/components/console/helpers/index.rst +++ b/components/console/helpers/index.rst @@ -7,7 +7,6 @@ The Console Helpers .. toctree:: :hidden: - dialoghelper formatterhelper processhelper progressbar From e44f62290b8917366e88faf86de2adb616877590 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 16:18:02 +0100 Subject: [PATCH 0147/2437] Updated the console/* articles to Symfony 4 --- _build/redirection_map | 1 + console/calling_commands.rst | 2 +- console/coloring.rst | 4 +-- console/commands_as_services.rst | 7 ++--- console/logging.rst | 15 ---------- console/request_context.rst | 48 +++++++++++++++++++------------- console/usage.rst | 31 +++++++-------------- console/verbosity.rst | 7 ----- 8 files changed, 45 insertions(+), 70 deletions(-) delete mode 100644 console/logging.rst diff --git a/_build/redirection_map b/_build/redirection_map index 146e731e460..a60b33f051f 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -346,6 +346,7 @@ /components/var_dumper/index /components/var_dumper /components/yaml/introduction /components/yaml /components/yaml/index /components/yaml +/console/logging /console /deployment/tools /deployment /install/bundles /setup/bundles /event_dispatcher/class_extension /event_dispatcher diff --git a/console/calling_commands.rst b/console/calling_commands.rst index 78759b70947..cfa3adf9966 100644 --- a/console/calling_commands.rst +++ b/console/calling_commands.rst @@ -6,7 +6,7 @@ user to remember the order of execution, you can call it directly yourself. This is also useful if you want to create a "meta" command that just runs a bunch of other commands (for instance, all commands that need to be run when the project's code has changed on the production servers: clearing the cache, -generating Doctrine2 proxies, dumping Assetic assets, ...). +generating Doctrine2 proxies, dumping web assets, ...). Calling a command from another one is straightforward:: diff --git a/console/coloring.rst b/console/coloring.rst index 0df7b4dd197..7594e439e9f 100644 --- a/console/coloring.rst +++ b/console/coloring.rst @@ -43,7 +43,7 @@ It is possible to define your own styles using the $style = new OutputFormatterStyle('red', 'yellow', array('bold', 'blink')); $output->getFormatter()->setStyle('fire', $style); - $output->writeln('foo'); + $output->writeln('foo'); Available foreground and background colors are: ``black``, ``red``, ``green``, ``yellow``, ``blue``, ``magenta``, ``cyan`` and ``white``. @@ -54,7 +54,7 @@ are swapped) and ``conceal`` (sets the foreground color to transparent, making the typed text invisible - although it can be selected and copied; this option is commonly used when asking the user to type sensitive information). -You can also set these colors and options directly inside the tagname:: +You can also set these colors and options directly inside the tag name:: // green text $output->writeln('foo'); diff --git a/console/commands_as_services.rst b/console/commands_as_services.rst index 217698bced8..d319b2172df 100644 --- a/console/commands_as_services.rst +++ b/console/commands_as_services.rst @@ -86,8 +86,8 @@ Or set the ``command`` attribute on the ``console.command`` tag in your service .. code-block:: yaml + # config/services.yaml services: - App\Command\SunshineCommand: tags: - { name: 'console.command', command: 'app:sunshine' } @@ -95,24 +95,23 @@ Or set the ``command`` attribute on the ``console.command`` tag in your service .. code-block:: xml + - - .. code-block:: php + // config/services.php use App\Command\SunshineCommand; - //... $container diff --git a/console/logging.rst b/console/logging.rst deleted file mode 100644 index 000165112b0..00000000000 --- a/console/logging.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. index:: - single: Console; Enabling logging - -How to Enable Logging in Console Commands -========================================= - -In Symfony versions prior to 3.3, the Console component didn't provide any -logging capabilities out of the box and you had to implement your own exception -listener for the console. - -Starting from Symfony 3.3, the Console component provides automatic error and -exception logging. - -You can of course also access and use the :doc:`logger ` service to -log messages. diff --git a/console/request_context.rst b/console/request_context.rst index 11125b58255..7f4cbd2540a 100644 --- a/console/request_context.rst +++ b/console/request_context.rst @@ -21,8 +21,8 @@ Configuring the Request Context Globally To configure the Request Context - which is used by the URL Generator - you can redefine the parameters it uses as default values to change the default host -(localhost) and scheme (http). You can also configure the base path if Symfony -is not running in the root directory. +(``localhost``) and scheme (``http``). You can also configure the base path if +Symfony is not running in the root directory. Note that this does not impact URLs generated via normal web requests, since those will override the defaults. @@ -31,7 +31,7 @@ will override the defaults. .. code-block:: yaml - # app/config/parameters.yml + # config/services.yaml parameters: router.request_context.host: example.org router.request_context.scheme: https @@ -39,7 +39,7 @@ will override the defaults. .. code-block:: xml - + @@ -54,7 +54,7 @@ will override the defaults. .. code-block:: php - // app/config/parameters.php + // config/services.php $container->setParameter('router.request_context.host', 'example.org'); $container->setParameter('router.request_context.scheme', 'https'); $container->setParameter('router.request_context.base_url', 'my/path'); @@ -62,21 +62,29 @@ will override the defaults. Configuring the Request Context per Command ------------------------------------------- -To change it only in one command you can simply fetch the Request Context -from the ``router`` service and override its settings:: +To change it only in one command you can fetch the Request Context from the +router service and override its settings:: - // src/Command/DemoCommand.php + // src/Command/DemoCommand.php + use Symfony\Component\Routing\RouterInterface; + // ... - // ... - class DemoCommand extends ContainerAwareCommand - { - protected function execute(InputInterface $input, OutputInterface $output) - { - $context = $this->getContainer()->get('router')->getContext(); - $context->setHost('example.com'); - $context->setScheme('https'); - $context->setBaseUrl('my/path'); + class DemoCommand extends ContainerAwareCommand + { + private $router; - // ... your code here - } - } + public function __construct(RouterInterface $router) + { + $this->router = $router; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $context = $this->router->getContext(); + $context->setHost('example.com'); + $context->setScheme('https'); + $context->setBaseUrl('my/path'); + + // ... your code here + } + } diff --git a/console/usage.rst b/console/usage.rst index 38b745b1276..3575737dd3b 100644 --- a/console/usage.rst +++ b/console/usage.rst @@ -8,24 +8,13 @@ The :doc:`/components/console/usage` page of the components documentation looks at the global console options. When you use the console as part of the full-stack framework, some additional global options are available as well. -By default, console commands run in the ``dev`` environment and you may want to -change this for some commands. For example, you may want to run some commands in -the ``prod`` environment for performance reasons. Also, the result of some -commands will be different depending on the environment. For example, the -``cache:clear`` command will clear the cache for the specified environment only. -To clear the ``prod`` cache you need to run: - -.. code-block:: terminal - - $ php bin/console cache:clear --no-warmup --env=prod - - # this is equivalent: - $ php bin/console cache:clear --no-warmup -e prod - -In addition to changing the environment, you can also choose to disable debug mode. -This can be useful where you want to run commands in the ``dev`` environment -but avoid the performance hit of collecting debug data: - -.. code-block:: terminal - - $ php bin/console list --no-debug +Console commands run in the environment defined in the ``APP_ENV`` variable of +the ``.env`` file, which is ``dev`` by default. The result of some commands will +be different depending on the environment (e.g. the ``cache:clear`` command +clears the cache for the given environment only). To run the command in other +environment, edit the value of ``APP_ENV``. + +In addition to changing the environment, you can also choose to disable debug +mode. This can be useful where you want to run commands in the ``dev`` +environment but avoid the performance hit of collecting debug data. To do that, +set the value of the ``APP_DEBUG`` env var to ``0`` in the same ``.env`` file. diff --git a/console/verbosity.rst b/console/verbosity.rst index 609d60bc003..7776f9a513f 100644 --- a/console/verbosity.rst +++ b/console/verbosity.rst @@ -63,13 +63,6 @@ verbosity levels:: // ... } -.. note:: - - These semantic methods are defined in the ``OutputInterface`` starting from - Symfony 3.0. In previous Symfony versions they are defined in the different - implementations of the interface (e.g. :class:`Symfony\\Component\\Console\\Output\\Output`) - in order to keep backward compatibility. - When the quiet level is used, all output is suppressed as the default :method:`Symfony\\Component\\Console\\Output\\Output::write` method returns without actually printing. From 37c4c06351805e84a9dcb2d26e46cdc5e1aaf724 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 16:25:25 +0100 Subject: [PATCH 0148/2437] Deprecate the LockHandler utility --- components/filesystem.rst | 9 --- components/filesystem/lock_handler.rst | 89 +------------------------- 2 files changed, 2 insertions(+), 96 deletions(-) diff --git a/components/filesystem.rst b/components/filesystem.rst index 0cc1c20669d..e825df024f2 100644 --- a/components/filesystem.rst +++ b/components/filesystem.rst @@ -314,14 +314,5 @@ Whenever something wrong happens, an exception implementing An :class:`Symfony\\Component\\Filesystem\\Exception\\IOException` is thrown if directory creation fails. -Learn More ----------- - -.. toctree:: - :maxdepth: 1 - :glob: - - filesystem/* - .. _`Packagist`: https://packagist.org/packages/symfony/filesystem .. _`umask`: https://en.wikipedia.org/wiki/Umask diff --git a/components/filesystem/lock_handler.rst b/components/filesystem/lock_handler.rst index 3c2e7ce3b77..5950e98226f 100644 --- a/components/filesystem/lock_handler.rst +++ b/components/filesystem/lock_handler.rst @@ -1,92 +1,7 @@ LockHandler =========== -What is a Lock? ---------------- - -File locking is a mechanism that restricts access to a computer file by allowing -only one user or process access at any specific time. This mechanism was -introduced a few decades ago for mainframes, but continues being useful for -modern applications. - -Symfony provides a LockHelper to help you use locks in your project. - -Usage ------ - .. caution:: - The lock handler only works if you're using just one server. If you have - several hosts, you must not use this helper. - -A lock can be used, for example, to allow only one instance of a command to run. - -.. code-block:: php - - use Symfony\Component\Filesystem\LockHandler; - - $lockHandler = new LockHandler('hello.lock'); - if (!$lockHandler->lock()) { - // the resource "hello" is already locked by another process - - return 0; - } - -The first argument of the constructor is a string that it will use as part of -the name of the file used to create the lock on the local filesystem. A best -practice for Symfony commands is to use the command name, such as ``acme:my-command``. -``LockHandler`` sanitizes the contents of the string before creating -the file, so you can pass any value for this argument. - -.. tip:: - - The ``.lock`` extension is optional, but it's a common practice to include - it. This will make it easier to find lock files on the filesystem. Moreover, - to avoid name collisions, ``LockHandler`` also appends a hash to the name of - the lock file. - -By default, the lock will be created in the system's temporary directory, but -you can optionally select the directory where locks are created by passing it as -the second argument of the constructor. - -.. tip:: - - Another way to configure the directory where the locks are created is to - define a special environment variable, because PHP will use that value to - override the default temporary directory. On Unix-based systems, define the - ``TMPDIR`` variable. On Windows systems, define any of these variables: - ``TMP``, ``TEMP`` or ``USERPROFILE`` (they are checked in this order). This - technique is useful for example when deploying a third-party Symfony - application whose code can't be modified. - -The :method:`Symfony\\Component\\Filesystem\\LockHandler::lock` method tries to -acquire the lock. If the lock is acquired, the method returns ``true``, -``false`` otherwise. If the ``lock()`` method is called several times on the same -instance it will always return ``true`` if the lock was acquired on the first -call. - -You can pass an optional blocking argument as the first argument to the -``lock()`` method, which defaults to ``false``. If this is set to ``true``, your -PHP code will wait indefinitely until the lock is released by another process. - -.. caution:: - - Be aware of the fact that the resource lock is automatically released as soon - as PHP applies the garbage-collection process to the ``LockHandler`` object. - This means that if you refactor the first example shown in this article as - follows:: - - use Symfony\Component\Filesystem\LockHandler; - - if (!(new LockHandler('hello.lock'))->lock()) { - // the resource "hello" is already locked by another process - - return 0; - } - - Now the code won't work as expected because PHP's garbage collection mechanism - removes the reference to the ``LockHandler`` object and thus, the lock is released - just after it's been created. - - Another alternative way to release the lock explicitly when needed is to use the - :method:`Symfony\\Component\\Filesystem\\LockHandler::release` method. + The ``LockHandler`` utility is deprecated since Symfony 3.4. Use the new + Symfony Lock component instead. From 88e0f1d3d8954a394755d2aa87199453e424b931 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 16:27:34 +0100 Subject: [PATCH 0149/2437] Don't mention the deprecated LockHandler utility --- console/lockable_trait.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/console/lockable_trait.rst b/console/lockable_trait.rst index 18b64e57373..ce9cac0bbd8 100644 --- a/console/lockable_trait.rst +++ b/console/lockable_trait.rst @@ -2,9 +2,8 @@ Prevent Multiple Executions of a Console Command ================================================ A simple but effective way to prevent multiple executions of the same command in -a single server is to use **file locks**. The Filesystem component provides a -:doc:`LockHandler ` class that eases the -creation and release of these locks. +a single server is to use **file locks**. The Lock component eases the creation +and release of these locks. In addition, the Console component provides a PHP trait called ``LockableTrait`` that adds two convenient methods to lock and release commands:: From 4af878fda362da97b079fa7506c81b1cf8a36d70 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 16:43:17 +0100 Subject: [PATCH 0150/2437] Define a deprecated page as orphan to avoid RST issues --- components/filesystem/lock_handler.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/filesystem/lock_handler.rst b/components/filesystem/lock_handler.rst index 5950e98226f..45ea7cda95c 100644 --- a/components/filesystem/lock_handler.rst +++ b/components/filesystem/lock_handler.rst @@ -1,3 +1,5 @@ +:orphan: + LockHandler =========== From fcb4ac0c5749850fb6c0f8572d5eb1131a458a7b Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 16:50:26 +0100 Subject: [PATCH 0151/2437] Update the main console article too --- console.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console.rst b/console.rst index dfa559991f8..3ec442a8e1c 100644 --- a/console.rst +++ b/console.rst @@ -163,11 +163,11 @@ Getting Services from the Service Container To actually create a new user, the command has to access to some :doc:`services `. Since your command is already registered as a service, you can use normal dependency injection. Imagine you have a -``AppBundle\Service\UserManager`` service that you want to access:: +``App\Service\UserManager`` service that you want to access:: // ... use Symfony\Component\Console\Command\Command; - use AppBundle\Service\UserManager; + use App\Service\UserManager; class CreateUserCommand extends Command { From 65d6754d9aa12e7b56b3611276ce8ea4c40c0239 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Sat, 25 Nov 2017 20:35:19 +0100 Subject: [PATCH 0152/2437] Updated service_container/* articles to Symfony 4 --- service_container.rst | 80 ++++++++++----------- service_container/3.3-di-changes.rst | 40 +++++------ service_container/alias_private.rst | 19 +++-- service_container/autowiring.rst | 19 +++-- service_container/compiler_passes.rst | 87 +++++++++++++++++++---- service_container/configurators.rst | 6 +- service_container/expression_language.rst | 3 + service_container/factories.rst | 11 +-- service_container/import.rst | 24 +++---- service_container/injection_types.rst | 11 ++- service_container/lazy_services.rst | 3 + service_container/parameters.rst | 16 ++++- service_container/parent_services.rst | 6 ++ service_container/service_decoration.rst | 12 ++++ service_container/service_locators.rst | 6 +- service_container/synthetic_services.rst | 4 +- service_container/tags.rst | 6 +- 17 files changed, 226 insertions(+), 127 deletions(-) diff --git a/service_container.rst b/service_container.rst index 12e0705ae32..11ea370ee29 100644 --- a/service_container.rst +++ b/service_container.rst @@ -10,15 +10,10 @@ send emails while another object might help you save things to the database. Almost *everything* that your app "does" is actually done by one of these objects. And each time you install a new bundle, you get access to even more! -In Symfony, these useful objects are called **services** and each service lives inside -a very special object called the **service container**. If you have the service container, -then you can fetch a service by using that service's id:: - - $logger = $container->get('logger'); - $entityManager = $container->get('doctrine.orm.entity_manager'); - -The container allows you to centralize the way objects are constructed. It makes -your life easier, promotes a strong architecture and is super fast! +In Symfony, these useful objects are called **services** and each service lives +inside a very special object called the **service container**. The container +allows you to centralize the way objects are constructed. It makes your life +easier, promotes a strong architecture and is super fast! Fetching and using Services --------------------------- @@ -36,7 +31,7 @@ service's class or interface name. Want to :doc:`log ` something? No p /** * @Route("/products") */ - public function listAction(LoggerInterface $logger) + public function list(LoggerInterface $logger) { $logger->info('Look! I just used a service'); @@ -83,7 +78,7 @@ You can also use the unique "Service ID" to access a service directly:: /** * @Route("/products") */ - public function listAction() + public function list() { $logger = $this->container->get('logger'); $logger->info('Look! I just used a service'); @@ -146,7 +141,7 @@ inside your controller:: use App\Service\MessageGenerator; - public function newAction(MessageGenerator $messageGenerator) + public function new(MessageGenerator $messageGenerator) { // thanks to the type-hint, the container will instantiate a // new MessageGenerator and pass it to you! @@ -167,9 +162,7 @@ each time you ask for it. .. sidebar:: Automatic Service Loading in services.yaml - The documentation assumes you're using - `Symfony Standard Edition (version 3.3) services.yaml`_ configuration. The most - important part is this: + The documentation assumes you're using the following service configuration: .. configuration-block:: @@ -185,10 +178,10 @@ each time you ask for it. # makes classes in src/ available to be used as services App\: - resource: '../../src/*' + resource: '../src/*' # you can exclude directories or files # but if a service is unused, it's removed anyway - exclude: '../../src/{Entity,Repository}' + exclude: '../src/{Entity,Repository}' .. code-block:: xml @@ -204,7 +197,7 @@ each time you ask for it. - + @@ -223,7 +216,7 @@ each time you ask for it. ; // $this is a reference to the current loader - $this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}'); + $this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}'); .. tip:: @@ -237,15 +230,16 @@ each time you ask for it. If you'd prefer to manually wire your service, that's totally possible: see :ref:`services-explicitly-configure-wire-services`. -You can also fetch a service directly from the container via its "id", which will -be its class name in this case:: +If the :ref:`service is public `, you can also fetch it +directly from the container via its "id". However, this practice is discouraged +and you should instead inject services via constructors:: use App\Service\MessageGenerator; // accessing services like this only works if you extend Controller class ProductController extends Controller { - public function newAction() + public function new() { // only works if your service is public $messageGenerator = $this->get(MessageGenerator::class); @@ -256,8 +250,6 @@ be its class name in this case:: } } -However, this only works if you make your service :ref:`public `. - .. _services-constructor-injection: Injecting Services/Config into a Service @@ -368,7 +360,7 @@ you can use the service immediately:: use App\Updates\SiteUpdateManager; - public function newAction(SiteUpdateManager $siteUpdateManager) + public function new(SiteUpdateManager $siteUpdateManager) { // ... @@ -438,8 +430,8 @@ pass here. No problem! In your configuration, you can explicitly set this argume # same as before App\: - resource: '../../src/*' - exclude: '../../src/{Entity,Repository}' + resource: '../src/*' + exclude: '../src/{Entity,Repository}' # explicitly configure the service App\Updates\SiteUpdateManager: @@ -459,7 +451,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume - + @@ -483,7 +475,7 @@ pass here. No problem! In your configuration, you can explicitly set this argume ->setPublic(false) ; - $this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}'); + $this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}'); // Explicitly configure the service $container->getDefinition(SiteUpdateManager::class) @@ -553,9 +545,9 @@ and reference it with the ``%parameter_name%`` syntax: // ... ->setArgument('$adminEmail', '%admin_email%'); -Actually, once you define a parameter, it can be referenced via the ``%parameter_name%`` -syntax in *any* other service configuration file - like ``config.yml``. Many parameters -are defined in a :ref:`parameters.yml file `. +Actually, once you define a parameter, it can be referenced via the +``%parameter_name%`` syntax in *any* other configuration file. Many parameters +are defined in the ``config/services.yaml`` file. You can then fetch the parameter in the service:: @@ -573,11 +565,11 @@ You can then fetch the parameter in the service:: You can also fetch parameters directly from the container:: - public function newAction() + public function new() { // ... - // this ONLY works if you extend Controller + // this ONLY works if you extend the base Controller $adminEmail = $this->container->getParameter('admin_email'); // or a shorter way! @@ -741,7 +733,7 @@ as a service, and :doc:`tag ` it with ``twig.extension` ->addTag('twig.extension'); But, with ``autoconfigure: true``, you don't need the tag. In fact, if you're using -the :ref:`Symfony Standard Edition services.yaml config `, +the :ref:`default services.yaml config `, you don't need to do *anything*: the service will be automatically loaded. Then, ``autoconfigure`` will add the ``twig.extension`` tag *for* you, because your class implements ``Twig_ExtensionInterface``. And thanks to ``autowire``, you can even add @@ -789,7 +781,7 @@ from the container:: use App\Service\MessageGenerator; - public function newAction(MessageGenerator $messageGenerator) + public function new(MessageGenerator $messageGenerator) { // type-hinting it as an argument DOES work @@ -797,7 +789,7 @@ from the container:: $this->container->get(MessageGenerator::class); } -Usually, this is ok: there are better ways to access a service. But, if you *do* +Usually, this is OK: there are better ways to access a service. But, if you *do* need to make your service public, just override this setting: .. configuration-block:: @@ -848,13 +840,13 @@ key. For example, the default Symfony configuration contains this: # the namespace prefix for classes (must end in \) App\: # create services for all the classes found in this directory... - resource: '../../src/*' + resource: '../src/*' # ...except for the classes located in these directories - exclude: '../../src/{Entity,Repository}' + exclude: '../src/{Entity,Repository}' # these were imported above, but we want to add some extra config App\Controller\: - resource: '../../src/Controller' + resource: '../src/Controller' # apply some configuration to these services public: true tags: ['controller.service_arguments'] @@ -871,9 +863,9 @@ key. For example, the default Symfony configuration contains this: - + - + @@ -893,7 +885,7 @@ key. For example, the default Symfony configuration contains this: ->setPublic(false) ; - $this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}'); + $this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}'); // Changes default config $definition @@ -902,7 +894,7 @@ key. For example, the default Symfony configuration contains this: ; // $this is a reference to the current loader - $this->registerClasses($definition, 'App\\Controller\\', '../../src/Controller/*'); + $this->registerClasses($definition, 'App\\Controller\\', '../src/Controller/*'); .. tip:: diff --git a/service_container/3.3-di-changes.rst b/service_container/3.3-di-changes.rst index ba4445ad42c..2cc1afec728 100644 --- a/service_container/3.3-di-changes.rst +++ b/service_container/3.3-di-changes.rst @@ -49,15 +49,15 @@ Symfony Standard Edition: # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name App\: - resource: '../../src/*' + resource: '../src/*' # you can exclude directories or files # but if a service is unused, it's removed anyway - exclude: '../../src/{Entity,Repository}' + exclude: '../src/{Entity,Repository}' # controllers are imported separately to make sure they're public # and have a tag that allows actions to type-hint services App\Controller\: - resource: '../../src/Controller' + resource: '../src/Controller' tags: ['controller.service_arguments'] # add more services, or override services that need manual wiring @@ -77,9 +77,9 @@ Symfony Standard Edition: - + - + @@ -101,7 +101,7 @@ Symfony Standard Edition: ->setPublic(false) ; - $this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}'); + $this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}'); // Changes default config $definition @@ -109,7 +109,7 @@ Symfony Standard Edition: ; // $this is a reference to the current loader - $this->registerClasses($definition, 'App\\Controller\\', '../../src/Controller/*'); + $this->registerClasses($definition, 'App\\Controller\\', '../src/Controller/*'); // add more services, or override services that need manual wiring @@ -139,10 +139,10 @@ thanks to the following config: # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name App\: - resource: '../../src/*' + resource: '../src/*' # you can exclude directories or files # but if a service is unused, it's removed anyway - exclude: '../../src/{Entity,Repository}' + exclude: '../src/{Entity,Repository}' .. code-block:: xml @@ -156,7 +156,7 @@ thanks to the following config: - + @@ -174,7 +174,7 @@ thanks to the following config: ->setPublic(false) ; - $this->registerClasses($definition, 'App\\', '../../src/*', '../../src/{Entity,Repository}'); + $this->registerClasses($definition, 'App\\', '../src/*', '../src/{Entity,Repository}'); This means that every class in ``src/`` is *available* to be used as a service. And thanks to the ``_defaults`` section at the top of the file, all of @@ -345,7 +345,7 @@ The third big change is that, in a new Symfony 3.3 project, your controllers are # controllers are imported separately to make sure they're public # and have a tag that allows actions to type-hint services App\Controller\: - resource: '../../src/Controller' + resource: '../src/Controller' tags: ['controller.service_arguments'] .. code-block:: xml @@ -360,7 +360,7 @@ The third big change is that, in a new Symfony 3.3 project, your controllers are - + @@ -372,7 +372,7 @@ The third big change is that, in a new Symfony 3.3 project, your controllers are // ... - $this->registerClasses($definition, 'App\\Controller\\', '../../src/Controller/*'); + $this->registerClasses($definition, 'App\\Controller\\', '../src/Controller/*'); But, you might not even notice this. First, your controllers *can* still extend the same base ``Controller`` class or a new :ref:`AbstractController `. @@ -720,11 +720,11 @@ You're now ready to automatically register all services in ``src/`` # ... + App\: - + resource: '../../src/*' - + exclude: '../../src/{Entity,Repository}' + + resource: '../src/*' + + exclude: '../src/{Entity,Repository}' + + App\Controller\: - + resource: '../../src/Controller' + + resource: '../src/Controller' + tags: ['controller.service_arguments'] # ... @@ -809,11 +809,11 @@ can be autowired. The final configuration looks like this: public: false App\: - resource: '../../src/*' - exclude: '../../src/{Entity,Repository}' + resource: '../src/*' + exclude: '../src/{Entity,Repository}' App\Controller\: - resource: '../../src/Controller' + resource: '../src/Controller' tags: ['controller.service_arguments'] App\Service\GitHubNotifier: diff --git a/service_container/alias_private.rst b/service_container/alias_private.rst index b6bd077fa30..b57099960f9 100644 --- a/service_container/alias_private.rst +++ b/service_container/alias_private.rst @@ -32,6 +32,7 @@ You can also control the ``public`` option on a service-by-service basis: .. code-block:: yaml + # config/services.yaml services: # ... @@ -40,6 +41,7 @@ You can also control the ``public`` option on a service-by-service basis: .. code-block:: xml + register(Foo::class) @@ -80,11 +83,6 @@ to access it directly from your code. However, if a service has been marked as private, you can still alias it (see below) to access this service (via the alias). -.. note:: - - Services are by default public, but it's considered a good practice to mark - as many services private as possible. - .. _services-alias: Aliasing @@ -98,6 +96,7 @@ services. .. code-block:: yaml + # config/services.yaml services: # ... App\Mail\PhpMailer: @@ -109,6 +108,7 @@ services. .. code-block:: xml + register(PhpMailer::class) @@ -142,6 +143,7 @@ This means that when using the container directly, you can access the .. code-block:: yaml + # config/services.yaml services: # ... app.mailer: '@App\Mail\PhpMailer' @@ -156,11 +158,13 @@ or you decided not to maintain it anymore), you can deprecate its definition: .. code-block:: yaml - App\Service\OldService: - deprecated: The "%service_id%" service is deprecated since 2.8 and will be removed in 3.0. + # config/services.yaml + App\Service\OldService: + deprecated: The "%service_id%" service is deprecated since 2.8 and will be removed in 3.0. .. code-block:: xml + `. Suppose that for some reason, the id of the service was instead ``app.rot13.transformer``. In this case, any arguments type-hinted with the class name (``App\Util\Rot13Transformer``) -can no longer be autowired (actually, it :ref:`will work now, but not in Symfony 4.0 `). +can no longer be autowired. No problem! To fix this, you can *create* a service whose id matches the class by adding a service alias: @@ -212,6 +215,7 @@ adding a service alias: .. code-block:: yaml + # config/services.yaml services: # ... @@ -227,6 +231,7 @@ adding a service alias: .. code-block:: xml + `). +argument can no longer be autowired. To fix that, add an :ref:`alias `: @@ -310,6 +315,7 @@ To fix that, add an :ref:`alias `: .. code-block:: yaml + # config/services.yaml services: # ... @@ -321,6 +327,7 @@ To fix that, add an :ref:`alias `: .. code-block:: xml + `: .. code-block:: php + // config/services.php use App\Util\Rot13Transformer; use App\Util\TransformerInterface; @@ -375,6 +383,7 @@ that alias: .. code-block:: yaml + # config/services.yaml services: # ... @@ -396,6 +405,7 @@ that alias: .. code-block:: xml + `, -you need to register them in the ``build()`` method of the bundle class (this -is not needed when implementing the ``process()`` method in the extension):: +Compiler passes are registered in the ``build()`` method of the application kernel:: - // src/AppBundle.php - namespace AppBundle; + // src/Kernel.php + namespace App; + + use App\DependencyInjection\Compiler\CustomPass; + use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; + use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\HttpKernel\Kernel as BaseKernel; + + class Kernel extends BaseKernel implements CompilerPassInterface + { + use MicroKernelTrait; + + // ... + + protected function build(ContainerBuilder $container): void + { + $container->addCompilerPass(new CustomPass()); + } + } + +One of the most common use-cases of compiler passes is to work with :doc:`tagged +services `. In those cases, instead of creating a +compiler pass, you can make the kernel implement +:class:`Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface` +and process the services inside the ``process()`` method:: + + // src/Kernel.php + namespace App; + + use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; + use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; + use Symfony\Component\DependencyInjection\ContainerBuilder; + use Symfony\Component\HttpKernel\Kernel as BaseKernel; + + class Kernel extends BaseKernel implements CompilerPassInterface + { + use MicroKernelTrait; + + // ... + + public function process(ContainerBuilder $container) + { + // in this method you can manipulate the service container: + // for example, changing some container service: + $container->getDefinition('app.some_private_service')->setPublic(true); + + // or processing tagged services: + foreach ($container->findTaggedServiceIds('some_tag') as $id => $tags) { + // ... + } + } + } + +Working with Compiler Passes in Bundles +--------------------------------------- + +`Bundles `_ can define compiler passes in the ``build()`` method of +the main bundle class (this is not needed when implementing the ``process()`` +method in the extension):: + + // src/MyBundle/MyBundle.php + namespace App\MyBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use App\DependencyInjection\Compiler\CustomPass; - class AppBundle extends Bundle + class MyBundle extends Bundle { public function build(ContainerBuilder $container) { @@ -31,10 +90,8 @@ is not needed when implementing the ``process()`` method in the extension):: } } -One of the most common use-cases of compiler passes is to work with tagged services -(read more about tags in ":doc:`/service_container/tags`"). If you are using -custom tags in a bundle then by convention, tag names consist of the name of -the bundle (lowercase, underscores as separators), followed by a dot, and -finally the "real" name. For example, if you want to introduce some sort of -"transport" tag in your AcmeMailerBundle, you should call it -``acme_mailer.transport``. +If you are using custom service tags in a bundle then by convention, tag names +consist of the name of the bundle (lowercase, underscores as separators), +followed by a dot, and finally the "real" name. For example, if you want to +introduce some sort of "transport" tag in your AcmeMailerBundle, you should call +it ``acme_mailer.transport``. diff --git a/service_container/configurators.rst b/service_container/configurators.rst index 20ceaeed18c..7f2817e0a56 100644 --- a/service_container/configurators.rst +++ b/service_container/configurators.rst @@ -131,7 +131,7 @@ all the classes are already loaded as services. All you need to do is specify th # Registers all 4 classes as services, including App\Mail\EmailConfigurator App\: - resource: '../../src/*' + resource: '../src/*' # ... # override the services to set the configurator @@ -151,7 +151,7 @@ all the classes are already loaded as services. All you need to do is specify th http://symfony.com/schema/dic/services/services-1.0.xsd"> - + @@ -176,7 +176,7 @@ all the classes are already loaded as services. All you need to do is specify th $definition->setAutowired(true); - $this->registerClasses($definition, 'App\\', '../../src/*'); + $this->registerClasses($definition, 'App\\', '../src/*'); $container->getDefinition(NewsletterManager::class) ->setConfigurator(array(new Reference(EmailConfigurator::class), 'configure')); diff --git a/service_container/expression_language.rst b/service_container/expression_language.rst index c6878e413e9..cbab6c2ffde 100644 --- a/service_container/expression_language.rst +++ b/service_container/expression_language.rst @@ -78,12 +78,14 @@ via a ``container`` variable. Here's another example: .. code-block:: yaml + # config/services.yaml services: App\Mailer: arguments: ["@=container.hasParameter('some_param') ? parameter('some_param') : 'default_value'"] .. code-block:: xml + - - - + `. Internally, each bundle defines its services in files like you've seen so far. However, these files aren't imported using the ``import`` directive. Instead, bundles @@ -123,10 +121,6 @@ use a *dependency injection extension* to load the files automatically. As soon as you enable a bundle, its extension is called, which is able to load service configuration files. -In fact, each configuration block in ``config.yml`` - e.g. ``framework`` or ``twig``- -is passed to the extension for that bundle - e.g. ``FrameworkBundle`` or ``TwigBundle`` - +In fact, each configuration file in ``config/packages/`` is passed to the +extension of its related bundle - e.g. ``FrameworkBundle`` or ``TwigBundle`` - and used to configure those services further. - -If you want to use dependency injection extensions in your own shared -bundles and provide user friendly configuration, take a look at the -:doc:`/bundles/extension` article. diff --git a/service_container/injection_types.rst b/service_container/injection_types.rst index e5c7fe78dbf..60478f66a5f 100644 --- a/service_container/injection_types.rst +++ b/service_container/injection_types.rst @@ -41,7 +41,8 @@ service container configuration: .. code-block:: yaml - services: + # config/services.yaml + services: # ... App\Mail\NewsletterManager: @@ -49,6 +50,7 @@ service container configuration: .. code-block:: xml + register(AppExtension::class) diff --git a/service_container/parameters.rst b/service_container/parameters.rst index 224684e84b9..046076a5fe5 100644 --- a/service_container/parameters.rst +++ b/service_container/parameters.rst @@ -17,11 +17,13 @@ Use the ``parameters`` section of a config file to set parameters: .. code-block:: yaml + # config/services.yaml parameters: mailer.transport: sendmail .. code-block:: xml + setParameter('mailer.transport', 'sendmail'); You can refer to parameters elsewhere in any config file by surrounding them @@ -50,6 +53,7 @@ and hidden with the service definition: .. code-block:: yaml + # config/services.yaml parameters: mailer.transport: sendmail @@ -59,6 +63,7 @@ and hidden with the service definition: .. code-block:: xml +