Here is a short tutorial about my discovery of the new YAML parsing library that comes with symfony 1.1. As you may know, YAML files are a place symfony developpers spend time writing configuration, it is very important they have a good tool to manipulate data and debug files. Giving trainings on symfony 1.0 is a part of my job and when I see people starting the configuration files, I can notice the YAML system in the first version of symfony has two major problems:

  • The error messages do not help developers finding their mistakes in a YAML file.

  • Converting PHP data into a YAML structure can produce messy outputs.

Lets play with YAML!

The first good new is you do not have to use symfony to take advantage of this new library. As I needed it for a non symfony project (that's sad, I know), the only thing I had to do was to include the sfYaml.class.php file in my script.

// Include the symfony YAML library
include_once('/path/to/sf1.1/lib/yaml/sfYaml.class.php');
 
// Load the YAML file
$array = sfYaml::load('test.yml');
 
// Check what we have got
print_r($array);
 

Well, that is all we need to test parsing and creating YAML files! Let's create a test.yml file:

root:
  level1:
    sublevel11: value11
    sublevel12: value12
  level2:
     sublevel21: value21
    sublevel22: value22
 

Error messages

Some of you acquainted with YAML syntax might have noticed the indentation error I have on the sublevel21 line. Let's run our test.php file. It will explode on the screen showing the following error:

Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Unable to parse file "test.yml": Indentation problem at line 6 ( sublevel22: value22)' in /path/to/sf1.1/lib/yaml/sfYaml.class.php:70
Stack trace:
#0 /var/www/sites/test/-(7): sfYaml::load('test.yml')
#1 {main}
thrown in /path/to/sf1.1/lib/yaml/sfYaml.class.php on line 70'

Most of us have a difficult time when beginning with YAML because of its uncompromising syntax. The library used in symfony 1.0 was of course working well but it has crypting error messages that let you spend hours looking for the tab character lost alone at the end of your file. You can see here the message is clear: Indentation problem at line 6. In case of the presence of tabs in our file, we would have Unable to parse file "test.yml": A YAML file cannot contain tabs as indentation line .... The second good thing is this error is propagated with an exception so it is catchable.

With such information, we can fix our mistake quickly. The php script then obediently outputs the following:

Array
(
    [root] => Array
        (
            [level1] => Array
                (
                    [sublevel11] => value11
                    [sublevel12] => value12
                )

            [level2] => Array
                (
                    [sublevel21] => value21
                    [sublevel22] => value22
                )

        )

)

That was as easy as that.

Dumping YAML

Let's now try to modify the array and generate the according YAML structure:

// Add an extra level to our array
$array['root']['level3'] = array('sublevel31' => 'value31', 'sublevel32' => 'value32');
 
// print the YAML out on the screen
echo sfYaml::dump($array);
 

This will produce the following output:

root:
  level1: { sublevel11: value11, sublevel12: value12 }
  level2: { sublevel21: value21, sublevel22: value22 }
  level3: { sublevel31: value31, sublevel32: value32 }

This isn't really what we expected. Well, in fact, sfYaml::dump() can take an extra inline argument. When the inline depth is reached, the rest of the structure is dumped as YAML associative array. We just have to specify an inline level of 3:

echo sfYaml::dump($array, 3);
 

This will give us:

root:
  level1:
    sublevel11: value11
    sublevel12: value12
  level2:
    sublevel21: value21
    sublevel22: value22
  level3:
    sublevel31: value31
    sublevel32: value32

This is particularly convenient when dumping YAML schema from a database with propel:build-schema. With symfony 1.0 we were used to obtain something dirty like:

propel:
  prd_alert:
    _attributes:
      idMethod: native
    id:
      type: INTEGER
      required: true
      autoIncrement: true
      primaryKey: true
    dummy:
      type: INTEGER
    begin_at:
      type: TIMESTAMP

Now enjoy the output using the new library:

propel:
  _attributes:
    package: lib.model
  admin:
    id: { type: INTEGER, required: true, primaryKey: true }
    login: { type: VARCHAR, size: '255', required: true }
    created_at: { type: TIMESTAMP }
    _indexes: { admin_login_idx: [login] }

You can use the sfYaml library with your non symfony applications exactly the way we did here. This tool is also bundled with symfony 1.1 so you can use it directly out of the box in your actions or your tasks.

I have been using symfony 1.0 and I had great pleasure discovering it and working with it. Now, I am using symfony 1.1 and discovering features like this one, I found the same pleasure again.