Skip to content

[RFR] Added "How to Organize Configuration Files" cookbook #3885

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Aug 16, 2014
Next Next commit
Firest draft of the "How to Organize Configuration Files" cookbook
  • Loading branch information
javiereguiluz committed May 28, 2014
commit 0520bf1617b38a93d35d3a61f56c670b33dbff87
258 changes: 258 additions & 0 deletions cookbook/configuration/configuration_organization.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
.. index::
single: Configuration, Environments
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to refer people to this article in the "Environments" index, do we?


How to Organize Configuration Files
===================================

The default Symfony2 Standard Edition defines three
:doc:`execution environments </cookbook/configuration/environments>` called
``dev``, ``prod``, and ``test``. An environment simply represents a way to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the comma before and

execute the same codebase with different configuration.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] with different configurations.


In order to select the configuration file to load for each environment, Symfony
executes the ``registerContainerConfiguration()`` method of the ``AppKernel``
class::

// app/AppKernel.php
class AppKernel extends Kernel
{
// ...

public function registerContainerConfiguration(LoaderInterface $loader)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either a use statement for the LoaderInterface or // ... should be added to the top of the file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same applies to the Kernel class.

{
$loader->load(__DIR__.'/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
├─ src/
├─ vendor/
└─ web/

This default structure was choosen for its simplicity — one file per environment.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chosen

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.

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
├─ src/
├─ vendor/
└─ web/

To make it work, change the code of the ``registerContainerConfiguration()``
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"To make this work," sounds better for continuity perhaps?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also does the method needs to follow some formatting guidelines for method naming?

method::

// app/AppKernel.php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the notes about use statements at the code block above.

class AppKernel extends Kernel
{
// ...

public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/'.$this->getEnvironment().'/config.yml');
}
}

Then, make sure that each ``config.yml`` file loads the rest of the configuration
files, including the common files:

.. code-block:: yaml

# app/config/dev/config.yml
imports:
- { resource: '../config.yml' }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be ../common/config.yml, shouldn't it? (same below)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should also include XML and PHP

- { resource: 'parameters.yml' }
- { resource: 'security.yml' }

# ...

# app/config/prod/config.yml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer to put this in 3 different code blocks

imports:
- { resource: '../config.yml' }
- { resource: 'parameters.yml' }
- { resource: 'security.yml' }

# ...


# app/config/common/config.yml
imports:
- { resource: 'parameters.yml' }
- { resource: 'security.yml' }

# ...


Semantic Configuration Files
----------------------------

A different organization strategy may be needed for complex applications with
large configuration files. You could for instance create one file per bundle
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For instance, you could create one file per bundle [...]

and several files to define all the application services:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the the in front of application services, since it is not a particular designation but rather a general designation


.. code-block:: text

<your-project>/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could just be / rather than as maybe it is understood already

├─ app/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could also remove the /'s since anything that lacks extension is a folder? although some executables lack extension

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think including the slash makes things easier to understand

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 For keeping the slash for readability reasons.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 as well. Not all files have an extension (app/console for instance, even if it does not appear in this tree)

│ └─ 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
├─ src/
├─ vendor/
└─ web/

Again, change the code of the ``registerContainerConfiguration()`` method to
make Symfony aware of the new file organization::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add some information that the environment config files imports the correct bundle configurations


// app/AppKernel.php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same notes about the use statements.

class AppKernel extends Kernel
{
// ...

public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/environments/'.$this->getEnvironment().'.yml');
}
}

Advanced Tecniques
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Techniques

------------------

Symfony loads configuration files using the ``Config component </components/config>``,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be /components/config/introduction I guess.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and should be :doc:Config component </components/config/introduction>``

which provides some advanced features.

Mix and Match Configuration Formats
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Configuration files can import files defined with any other built-in configuration
format (``.yml``, ``.xml``, ``.php``, ``.ini``):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a little warning about the ini loader ( #3431 )

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also not sure we should add the dot in front of each option here


.. code-block:: yaml

# app/config/config.yml
imports:
- { resource: 'parameters.yml' }
- { resource: 'services.xml' }
- { resource: 'security.yml' }
- { resource: 'legacy.php' }

# ...

If you use any other configuration format, you have to define your own loader
class extending it from ``Symfony\Component\DependencyInjection\Loader\FileLoader``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's use the :class: role here

When the configuration values are dynamic, you can use the PHP configuration
file to execute your own logic. In addition, you can define your own services
to load configuration from databases and web services.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe suggest here extending or implementing a particular interface or using the ClosureLoader.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] to load configurations [...]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] databases or web servers.


Directory Loading
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does directory loading really works out of the box ? I don't see anything about it in the codebase. Are you using a thrid-party bundle for that ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stof you are right. Thanks for noticing this. I was confused by the resource loading of the Config component and the fact that this correctly works for loading routes defined as annotations in one or more controllers inside a bundle.

I've just removed this section.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest you open a feature request on Symfony for this. It looks useful (in case you don't need to strictly control the order of loading)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@javiereguiluz, I did a PR about Directory Loading, if you want to take a look: symfony/symfony#11059

~~~~~~~~~~~~~~~~~

Splitting configuration into lots of smaller files can rapidly become cumbersome
when importing those files from the main configuration file. Avoid these problems
by loading an entire directory:

.. code-block:: yaml

# app/config/config.yml
imports:
- { resource: 'bundles/' }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

- { resource: 'services/' }

# ...

The Config component will look for recursively in the ``bundles/`` and ``services/``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] will recursively look in the [...]

directories and it will load any supported file format (``.yml``, ``.xml``,
``.php``, ``.ini``).

Global Configuration Files
~~~~~~~~~~~~~~~~~~~~~~~~~~

Some system administrators may prefer to store sensitive parameteres in global
configuration files under the ``/etc`` directory. Imagine that the database
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer something like "[...] files outside the project directory."

credentials for your website are stored in the ``/etc/sites/mysite.com/parameters.yml``.
Loading this file is as simple as indicating the full file path when importing
it from any other configuration file:

.. code-block:: yaml

# app/config/config.yml
imports:
- { resource: 'parameters.yml' }
- { resource: '/etc/sites/mysite.com/parameters.yml' }

# ...

Most of the time, local developers won't have the same files that exist in the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[...] 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:

.. code-block:: yaml

# app/config/config.yml
imports:
- { resource: 'parameters.yml' }
- { resource: '/etc/sites/mysite.com/parameters.yml', ignore_errors: true }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be documented for other formats as well (using a configuration-block), given that it is the only place in the doc talking about it AFAIK (btw, thanks for making me discover this setting)


# ...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit strange end of an article. You may want to add something like

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:`dir_structure`".

1 change: 1 addition & 0 deletions cookbook/configuration/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Configuration
pdo_session_storage
apache_router
web_server_configuration
configuration_organization