In the process of application development, developers are often faced with the problem of database population. A few specific solutions exist for some database systems, but none can be used on top of the object-relational mapping. Thanks to YAML and the sfPropelData
object, symfony can automatically transfer data from a text source to a database. Although writing a text file source for data may seem like more work than entering the records by hand using a CRUD interface, it will save you time in the long run. You will find this feature very useful for automatically storing and populating the test data for your application.
16.3.1. Fixture File Syntax
Symfony can read data files that follow a very simple YAML syntax, provided that they are located under the data/fixtures/
directory. Fixture files are organized by class, each class section being introduced by the class name as a header. For each class, records labeled with a unique string are defined by a set of fieldname: value
pairs. Listing 16-12 shows an example of a data file for database population.
Listing 16-12 - Sample Fixture File, in data/fixtures/import_data.yml
Article: ## Insert records in the blog_article table
first_post: ## First record label
title: My first memories
content: |
For a long time I used to go to bed early. Sometimes, when I had put
out my candle, my eyes would close so quickly that I had not even time
to say "I'm going to sleep".
second_post: ## Second record label
title: Things got worse
content: |
Sometimes he hoped that she would die, painlessly, in some accident,
she who was out of doors in the streets, crossing busy thoroughfares,
from morning to night.
Symfony translates the column keys into setter methods by using a camelCase converter (setTitle()
, setContent()
). This means that you can define a password
key even if the actual table doesn't have a password
field — just define a setPassword()
method in the User
object, and you can populate other columns based on the password (for instance, a hashed version of the password).
The primary key column doesn't need to be defined. Since it is an auto-increment field, the database layer knows how to determine it.
The created_at
columns don't need to be set either, because symfony knows that fields named that way must be set to the current system time when created.
16.3.2. Launching the Import
The propel-load-data
task imports data from a YAML file to a database. The connection settings come from the databases.yml
file, and therefore need an application name to run. Optionally, you can specify an environment name (dev
by default).
> symfony propel-load-data frontend
This command reads all the YAML fixture files from the data/fixtures/
directory and inserts the records into the database. By default, it replaces the existing database content, but if the last argument call is append
, the command will not erase the current data.
> symfony propel-load-data frontend append
You can specify another fixture file or directory in the call. In this case, add a path relative to the project directory.
> symfony propel-load-data frontend data/myfixtures/myfile.yml
16.3.3. Using Linked Tables
You now know how to add records to a single table, but how do you add records with foreign keys to another table? Since the primary key is not included in the fixtures data, you need an alternative way to relate records to one another.
Let's return to the example in Chapter 8, where a blog_article table is linked to a blog_comment
table, as shown in Figure 16-8.
This is where the labels given to the records become really useful. To add a Comment
field to the first_post
article, you simply need to append the lines shown in Listing 16-13 to the import_data.yml
data file.
Listing 16-13 - Adding a Record to a Related Table, in data/fixtures/import_data.yml
Comment:
first_comment:
article_id: first_post
author: Anonymous
content: Your prose is too verbose. Write shorter sentences.
The propel-load-data
task will recognize the label that you gave to an article previously in import_data.yml
, and grab the primary key of the corresponding Article
record to set the article_id
field. You don't even see the IDs of the records; you just link them by their labels--it couldn't be simpler.
The only constraint for linked records is that the objects called in a foreign key must be defined earlier in the file; that is, as you would do if you defined them one by one. The data files are parsed from the top to the bottom, and the order in which the records are written is important.
One data file can contain declarations of several classes. But if you need to insert a lot of data for many different tables, your fixture file might get too long to be easily manipulated.
The propel-load-data
task parses all the files it finds in the fixtures/
directory, so nothing prevents you from splitting a YAML fixture file into smaller pieces. The important thing to keep in mind is that foreign keys impose a processing order for the tables. To make sure that they are parsed in the correct order, prefix the files with an ordinal number.
100_article_import_data.yml 200_comment_import_data.yml 300_rating_import_data.yml