Each configuration file has a handler. The job of configuration handlers is to manage the configuration cascade, and to do the translation between the configuration files and the optimized PHP code executable at runtime.
19.4.1. Default Configuration Handlers
The default handler configuration is stored in $sf_symfony_data_dir/config/config_handlers.yml
. This file links the handlers to the configuration files according to a file path. Listing 19-7 shows an extract of this file.
Listing 19-7 - Extract of $sf_symfony_data_dir/config/config_handlers.yml
config/settings.yml:
class: sfDefineEnvironmentConfigHandler
param:
prefix: sf_
config/app.yml:
class: sfDefineEnvironmentConfigHandler
param:
prefix: app_
config/filters.yml:
class: sfFilterConfigHandler
modules/*/config/module.yml:
class: sfDefineEnvironmentConfigHandler
param:
prefix: mod_
module: yes
For each configuration file (config_handlers.yml
identifies each file by a file path with wildcards), the handler class is specified under the class
key.
The settings of configuration files handled by sfDefineEnvironmentConfigHandler
can be made available directly in the code via the sfConfig
class, and the param key contains a prefix value.
You can add or modify the handlers used to process each configuration file--for instance, to use INI or XML files instead of YAML files.
Note The configuration handler for the config_handlers.yml
file is sfRootConfigHandler
and, obviously, it cannot be changed.
If you ever need to modify the way the configuration is parsed, create an empty config_handlers.yml
file in your application's config/
folder and override the class
lines with the classes you wrote.
19.4.2. Adding Your Own Handler
Using a handler to deal with a configuration file provides two important benefits:
- The configuration file is transformed into executable PHP code, and this code is stored in the cache. This means that the configuration is parsed only once in production, and the performance is optimal.
- The configuration file can be defined at different levels (project and application) and the final parameter values will result from a cascade. So you can define parameters at a project level and override them on a per-application basis.
If you feel like writing your own configuration handler, follow the example of the structure used by the framework in the $sf_symfony_lib_dir/config/
directory.
Let's suppose that your application contains a myMapAPI
class, which provides an interface to a third-party web service delivering maps. This class needs to be initialized with a URL and a user name, as shown in Listing 19-8.
Listing 19-8 - Example of Initialization of the myMapAPI
Class
$mapApi = new myMapAPI();
$mapApi->setUrl($url);
$mapApi->setUser($user);
You may want to store these two parameters in a custom configuration file called map.yml
, located in the application config/
directory. This configuration file might contain the following:
api:
url: map.api.example.com
user: foobar
In order to transform these settings into code equivalent to Listing 19-8, you must build a configuration handler. Each configuration handler must extend sfConfigHandler
and provide an execute()
method, which expects an array of file paths to configuration files as a parameter, and must return data to be written in a cache file. Handlers for YAML files should extend the sfYamlConfigHandler
class, which provides additional facilities for YAML parsing. For the map.yml
file, a typical configuration handler could be written as shown in Listing 19-9.
Listing 19-9 - A Custom Configuration Handler, in myapp/lib/myMapConfigHandler.class.php
<?php
class myMapConfigHandler extends sfYamlConfigHandler
{
public function execute($configFiles)
{
$this->initialize();
// Parse the yaml
$config = $this->parseYamls($configFiles);
$data = "<?php\n";
$data. = "\$mapApi = new myMapAPI();\n";
if (isset($config['api']['url'])
{
$data. = sprintf("\$mapApi->setUrl('%s');\n", $config['api']['url']);
}
if (isset($config['api']['user'])
{
$data. = sprintf("\$mapApi->setUser('%s');\n", $config['api']['user']);
}
return $data;
}
}
The $configFiles
array that symfony passes to the execute()
method will contain a path to all the map.yml
files found in the config/
folders. The parseYamls()
method will handle the configuration cascade.
In order to associate this new handler with the map.yml
file, you must create a config_handlers.yml
configuration file with the following content:
config/map.yml:
class: myMapConfigHandler
Note The class
must either be autoloaded (that's the case here) or defined in the file whose path is written in a file
parameter under the param
key.
When you need the code based on the map.yml
file and generated by the myMapConfigHandler
handler in your application, call the following line:
include(sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_config_dir_name').'/map.yml'));
When calling the checkConfig()
method, symfony looks for existing map.yml
files in the configuration directories and processes them with the handler specified in the config_handlers.yml
file, if a map.yml.php
does not already exist in the cache or if the map.yml
file is more recent than the cache.
Tip If you want to handle environments in a YAML configuration file, the handler can extend the sfDefineEnvironmentConfigHandler
class instead of sfYamlConfigHandler
. After calling the parseYaml()
method to retrieve configuration, you should call the mergeEnvironment()
method. You can do it all in one line by calling $config = $this->mergeEnvironment($this->parseYamls ($configFiles));
.