From 0684c4a850b476b7c90c735448cb437c0a034605 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 22 Nov 2017 14:47:38 +0100 Subject: [PATCH 1/2] 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 6aabd10cb78de226a60b3c66788ada4bd086b966 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 23 Nov 2017 08:47:05 +0100 Subject: [PATCH 2/2] Removed links to specific files (they are not easy to maintain) --- configuration/front_controllers_and_kernel.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/configuration/front_controllers_and_kernel.rst b/configuration/front_controllers_and_kernel.rst index df57fa40cf1..f50e8875cca 100644 --- a/configuration/front_controllers_and_kernel.rst +++ b/configuration/front_controllers_and_kernel.rst @@ -27,7 +27,7 @@ The Front Controller 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 Skeleton, this role is taken by the `index.php`_ file in the +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. @@ -60,7 +60,7 @@ that is located in the ``public/`` directory. achieved by configuring the web server, as shown in :doc:`/setup/web_server_configuration`. -Technically, the `bin/console`_ script used when running Symfony on the command +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. @@ -143,5 +143,4 @@ this method differently if you need a more sophisticated way of loading your configuration. .. _front controller: https://en.wikipedia.org/wiki/Front_Controller_pattern -.. _bin/console: https://github.com/symfony/symfony-standard/blob/master/bin/console .. _decorate: https://en.wikipedia.org/wiki/Decorator_pattern