April 19, 2014
by Jason Roman





Categories:
Protips

Tags:
PHP  Symfony  YAML


Set Bundle Configuration Defaults with YAML in Symfony

Configure your bundle default values in YAML instead of PHP, just like how you override them in your applications.

When I was first learning Symfony2's Dependency Injection component I found it daunting and a little confusing. I still feel like portions of it are clunky and unnecessarily complicated, but it has improved and does the job.

As you start creating bundles outside of your application, you'll inevitably start having configurable parameters that the user can override in their application. More information on how to do this can be found in the Symfony Config documentation. Let's use this to configure an example bundle.

Our example bundle is going to contain a hash generator used for creating short URLs. (e.g. jayroman.com/sXr4dN2). Our bundle will create hashes that are 7 characters long with our own defined alphabet. For flexibility, we want to allow users to override these values in their application. Using Symfony's example documentation, our DependencyInjection/Configuration.php file might look something like this:

// path/to/mybundle/DependencyInjection/Configuration.php
...

$rootNode = $treeBuilder->root('short_url');

$rootNode->children()
->arrayNode('hash_generator')
->addDefaultsIfNotSet()
->children()
->integerNode('length')
->cannotBeEmpty()
->min(0)
->defaultValue(7)
->end()
->scalarNode('alphabet')
->cannotBeEmpty()
->defaultValue('bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ1234567890')
->end()
->end()
->end()
->end();
As you can see, our hash_generator node has two parameters: length which defaults to 7 characters, and a custom alphabet which contains all lower/uppercase letters and the numbers 0-9, minus vowels (including 'y') to prevent hashes containing swear words. Let's say a user wants to use our hash generator, but instead wants 10-character hashes and the full alphabet minus uppercase letters. They would override these parameters in their application's config.yml file like so:
# path/to/myapp/app/config/config.yml
short_url:
hash_generator:
length: 10
alphabet: abcdefghijklmnopqrstuvwxyz0123456789
This all seems simple enough, but I don't like hard-coding the default values directly in PHP. Wouldn't it make more sense to define these defaults in a YAML file just like you do in your application?

Thankfully, you can, and it's very simple! We are going to create a config.yml file in our bundle's Resources folder, load that in our Configuration, and set the defaults from the parsed file. Let's first create our config.yml file in the bundle:
# /path/to/mybundle/Resources/config/config.yml
hash_generator:
length: 7
alphabet: bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ1234567890
Notice I left off the 'short_url' prefix as it is unnecessary - we are already in the bundle. Now let's update the Configuration class to parse the YAML file and set the defaults from there:
// path/to/mybundle/DependencyInjection/Configuration.php
use Symfony\Component\Yaml\Yaml;

...

// load bundle defaults that can be overwritten by the application
$yaml = Yaml::parse(file_get_contents(__DIR__.'/../Resources/config/config.yml'));

$rootNode->children()
->arrayNode('hash_generator')
->addDefaultsIfNotSet()
->children()
->integerNode('length')
->cannotBeEmpty()
->min(0)
->defaultValue($yaml['hash_generator']['length'])
->end()
->scalarNode('alphabet')
->cannotBeEmpty()
->defaultValue($yaml['hash_generator']['alphabet'])
->end()
->end()
->end()
->end();
The YAML gets parsed into an array which is then used to pass the appropriate values to defaultValue() for each node.

There you have it! You can now use the Configuration class strictly for the node definitions, while setting your default values in the bundle's config.yml file, more closely mirroring your application.

See my follow up post to learn how to automatically set these configuration values as container parameters.