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
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 (
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.
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
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
Comment: first_comment: article_id: first_post author: Anonymous content: Your prose is too verbose. Write shorter sentences.
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.
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