Configuration explained
Overview
To be simple and easy to use, symfony employs a default configuration that should answer the most common needs of standard applications without modification. However, it is possible to customize almost everything about how the framework and your application interact with the help of a set of simple and powerful configuration files. With these files, you will also be able to add specific parameters for your applications.
Introduction
The great advantage of web application frameworks is that they give developers full control over many aspects of a web application using configuration files - not hard-to-read code. No need to look for a specific class to change the logging behavior or to transform the way the URLs appear: just write some configuration, and you're done.
However, this approach has two serious drawbacks:
- developers end up writing endless hard-to-type XML files
- in a PHP architecture, every request takes much longer to process
Symfony uses configuration files only for what they are best at doing. As a matter of fact, the ambition of the configuration system in symfony is to be:
- powerful: almost every aspect that can be managed using configuration files is managed using configuration files
- simple: many aspects of configuration are not shown in a normal application, since they rarely need to be changed
- easy: configuration files are easy to read, to modify and to create by the final user (the application developer)
- customizable: the default configuration language is YAML, but it can be INI or XML or whatever the preference of the developer is
- fast: the configuration files are never processed by the application but by the configuration system, which compiles them into a fast-processing chunk of code for the PHP server
This is not just wishful thinking, since the PHP implementation of the configuration system actually allows it.
Why YAML ?
Symfony uses by default the YAML format instead of more traditional INI or XML formats. This decision is based on the great advantages of YAML. Below are some of the pros taken from the YAML website:
- YAML documents are very readable by humans.
- YAML interacts well with scripting languages.
- YAML uses host languages' native data structures.
- YAML has a consistent information model.
- YAML enables stream-based processing.
- YAML is expressive and extensible.
- YAML is easy to implement.
Contrary to INI, it supports hierarchy. Contrary to XML, it doesn't use a complicated syntax with lots of <, > and closing tags. The only disadvantage of YAML is that it is not widely known by developers, for now, as compared to the other formats. However, it is so simple to learn that it would be a pity to miss out on its features just for a lack of fame. As of now, if you are not familiar with the YAML syntax, you should get started right away.
For those who are attached to other configuration file formats, be reassured: symfony supports any type of configuration file, since they are processed by special handler that can be easily adapted (see the Configuration handlers section at the end of this chapter).
YAML syntax and symfony conventions
There are a few conventions that need to be kept in mind when writing YAML files:
Never use tabs, use spaces instead. The YAML parsers won't be able to understand files with tabs, so indent your lines with spaces (a double blank is the symfony convention for indentation)
# Never use tabs
all:
-> mail:
-> -> webmaster: webmaster@mysite.com
# Use blanks instead
all:
mail:
webmaster: webmaster@mysite.com
To define an array as a value, enclose the elements in square brackets or use the expanded syntax with dashes:
# shorthand syntax for arrays
all:
params: [value1, value2]
# expanded syntax for arrays
all:
params:
- value1
- value2
If your parameters are strings starting or ending with spaces, enclose the value in single quotes. If a string parameter contains special characters, also enclose the value in single quotes:
# strings starting or finishing with spaces are to be enclosed in single quotes
all:
param1: This is a normal string
param2: ' This is a special string '
param3: 'That''s all folks!'
To give a boolean value, use either on, 1 or true for a positive value and off, 0 or false for a negative one.
# Boolean values
true_values:
- on
- 1
- true
false_values:
- off
- 0
- false
The YAML website has an extensive description of the YAML syntax.
Environments
As a reminder, symfony provides three default environments : production (prod), test (test) and development (dev); you can add as many custom environments as you wish.
The different environments share the same php code (apart from the front web controller), but can have completely different configuration files. Consequently, each environment can connect to a different database.
In the development environment, the logging and debugging settings are all set to on, since maintenance is more important than performance. On the contrary, the production environment has settings optimized for performance by default, so the production configuration turns many features off.
The case of the test environment is a little special. This environment is used when you execute some code from your project on the command line, and that would mostly happen for unit testing. Consequently, the test environment is close to the production configuration, but it is not accessed through a web browser. It simulates the use of cookies and other HTTP specific components.
To add a new environment, you don't need to create a directory or to use the symfony command. Simply duplicate the production front controller (myproject/web/index.php) to a file called, say, index_myenv.php, and change the SF_ENVIRONMENT definition to myenv in this file. That's it, you have your new environment. As you will see, this environment inherits all the default configuration plus the settings that are common to all environments.
Configuration levels
There are several configuration levels in symfony:
- granularity levels
- The default configuration located in the framework
- The global configuration for the whole project (in
myproject/config/)
- The local configuration for an application of the project (in
myproject/apps/myapp/config/)
- The local configuration restricted to a module (in
myproject/apps/myapp/modules/mymodule/config)
- environment levels
- specific to one environment
- for all environments
Of all the properties that can be customized, many are environment-dependent. So many YAML configuration files are divided by environment, plus a tail section for all environments. Typical symfony configuration files result looking like:
# production environment settings
prod:
...
# development environment settings
dev:
...
# test environment settings
test:
...
# custom environment settings
myenv:
...
# setting for all environments
all:
...
In addition, the framework itself defines default values in files that are not located in the project tree structure, but in the $data_dir/symfony/config/ directory of your symfony installation. These settings are inherited by all applications:
# default settings:
default:
...
Part of these default definitions are repeated in the project/app/module configuration files as comments (prefixed with #), so that you know that some parameters are defined by default and that they can be modified:
all:
# default_module: default
# default_action: index
#
# error_404_module: default
# error_404_action: error404
#
# login_module: default
# login_action: login
This means that a property can be defined several times, and the actual value results from a definition cascade with the following priority:
- module
- application
- project
- specific environment
- all environments
- default
Not all configuration files are environment-dependent.
Structure
To improve readability of the configuration files, symfony puts the parameter definitions in categories. Here is an example app.yml:
all:
.general:
tax: 19.6
pager:
max_per_page: 5
mail:
webmaster: webmaster@mysite.com
commercial: commerce@mysite.com
The .general, pager and mail lines are category headers. Headers starting with . are only for readability and information, whereas the others define a name space. A name space allows you to use the same key name for several parameters, provided that they don't share the same name space. This is especially useful when you need to access the values with constants.
Access configuration from code
All the configuration files are eventually transformed into PHP, but some of the parameters need to be accessible from your code. In this case, they are available through a special sfConfig class. It is a registry for configuration parameters, with simple getter and setter class methods, accessible from every part of the code:
sfConfig::set('param_name', $value); // to define a config
parameter = sfConfig::get('param_name', $default_value); // to retrieve a config parameter
So symfony configuration parameters have all the advantages of PHP constants, but without the disadvantages, since the value can be changed.
For instance, if you need to access the values defined in the previous example from your PHP code, write:
sfConfig::get('app_tax');
sfConfig::get('app_pager_max_per_page');
sfConfig::get('app_mail_webmaster');
sfConfig::get('app_mail_commercial');
The name is the concatenation of:
- a prefix related to the configuration file name (
sf_ for
settings.yml, app_ for app.yml, mod_ for module.yml)
- the name space (if it is defined), in lower case
- the name of the key in lower case
The environment is not included, since your PHP code will only have access to the values defined for the environment it's executed in.
How to add a custom setting?
There are two ways of adding custom settings to your code:
- Add new lines to the usual configuration files
myproject/apps/myapp/config/app.yml for application wide settings
myproject/apps/myapp/modules/mymodule/config/module.yml for module wide settings (this files doesn't exist by default)
- Create a new configuration file, together with a new config handler
For instance, if you need to add the credit card operators accepted in you site, you can write in the application app.yml:
all:
creditcards:
fake: off
visa: on
americanexpress: on
dev:
creditcards:
fake: on
To know if the fake credit cards are accepted in the current environment, get the value of:
sfConfig::get('app_creditcards_fake');
But maybe you need to add an array, an associative array or a lot of new parameters. In this case it is better to create a new configuration file, together with the corresponding configuration handler.
Note: For project-wide custom settings, you can still take advantage of the config/config.php file to call directly the sfConfig::set() method or load your own YAML file with sfYaml::load($file). Beware that autoloading is not active when the config.php is executed, so you need to manually include the class files that you want to use.
Scriptable configuration
It may happen that your configuration relies on external parameters (such as a database, or another configuration file). For these particular cases, the symfony configuration files are parsed as a PHP file before being passed to the YAML parser. It means that you can write:
all:
translation:
format: <?php echo sfConfig::get('sf_i18n') == true ? 'xliff' : 'none' ?>
That's right: you can put PHP code in YAML files!
Beware though that the configuration is parsed very early in the life of a request, so you will have no symfony built-in methods or functions to help you. If you want one configuration file to rely on another, you have to make sure that the file you rely on is parsed before (look in the symfony source to find in which order the configuration files are parsed). The app.yml is one of the last files parsed, so you may rely on others in it.
Be also aware that in the production environment, the configuration is cached, so the configuration files are parsed (and executed) only once after the cache is cleared.
Note: If what you need is to repeat a setting defined in another configuration file, use the constants trick. Previsously defined settings are available as constants in YAML file - just uppercase the name and enclose it between % signs. For instance, here is how you can reuse a setting from settings.yml in a view.yml:
all:
javascripts: [%SF_PROTOTYPE_WEB_DIR%/js/prototype]
And if you are allergic to YAML, or if you prefer to avoid writing both a configuration file and a configuration handler to finally get an associative array in PHP, you can bypass YAML parsing completely and return a PHP array in any YAML file. It means that you can write the logging.yml as follows:
<?php
return array(
'default' => array(
'active' => true,
'level' => 'debug'
)
);
...instead of the classic
default:
active: on
level: debug
Configuration handlers
The configuration files, whatever their format, are processed by some special classes called handlers that transform them into fast-processing PHP code. To promote interactivity in the development environment, the handlers parse the configuration at each request so that you can see immediately a change in a YAML file. But of course, in the production environment, the processing occurs once during the first request, and then the processed PHP code is stored in the cache. The performance is guaranteed since every request in production will just execute some well-optimized PHP code.
For instance, if your app.yml contains:
all:
mail:
webmaster: webmaster@mysite.com
Then the file config_app.yml.php, located in the cache folder of your project, will contain:
<?php
sfConfig::add(array(
'app_mail_webmaster' => 'webmaster@mysite.com',
));
?>
This is a major advantage over many PHP frameworks, where configuration files are compiled at every request even in production. Unlike Java, PHP doesn't share an execution context between requests. For other PHP frameworks, keeping the flexibility of XML configuration files requires a major performance hit to process all the configuration at every request. This is not the case in symfony. Thanks to the cache system, the overhead caused by configuration is very low.
The other main advantage of using configuration handlers is that it allows you to use formats other than YAML. The configuration handlers just transform configuration files into optimized PHP code. If you have a parser for another language - and PHP has native support of XML and INI files - it is very easy to write a custom handler that will read your own configuration file format.
Wrap up
To sum up, just remember the syntax of YAML configuration files:
environment:
.header1:
key1: value1
key2: value2
namespace1:
key3: value3
key4: value4
# comment
But now, enough of these general considerations, let's dig into the real configuration files and all their marvelous possibilities.
|