November 28, 2012

Symfony - Day 5 - Setting up Propel

In my previous post I indicated that I would be working with Propel. Although Propel is one of the two recommended ORMs for Symfony, it does not come with the standard Symfony install so it needs to be manually configured. Propel includes a guide here that walks you through the installation. Since I'm using composer it's easy to obtain the new Propel vendor bundle by adding the line from Propel's guide in composer.json, deleting composer.lock and running the composer install again.

Now we need to configure Propel, create our models and build our database.

Configuring Propel
The Symfony documentation does a pretty good job of walking through this process. However, I noticed that it used "mysql" for the database driver, which produced an error. I had to change this to "pdo_mysql". Here is what my parameters file looks like:

#app/config/parameters.yml
-----
parameters:
    database_driver:   pdo_mysql
    database_host:     localhost
    database_port:     ~
    database_name:     symfony2
    database_user:     root
    database_password: ~


propel:
  dbal:
    driver:           %database_driver%
    user:             %database_user%
    password:     %database_password%
    dsn:              %database_driver%:host=%database_host%;
dbname=%database_name%;charset=UTF8
    options:          {}
    attributes:       {}

-----

Creating the Database
Now that propel knows about the database, it can create it for us:

php app/console propel:database:create

Creating the Models
In order to work with our database, we want to use objects that map to our database. This allows the code to continue working regardless of the database driver. These objects are called models. You could spend a lot of time building these models to talk to each table, but Propel can do this for us if we tell it how are tables are (or will be) structured. Propel can also create our tables for us (more on that in a minute).

To define out table structure we need to create schema.xml in Resources/config under our CompanyBundle. Using the Symfony example we create our file:


<?xml version="1.0" encoding="UTF-8"?>
<database name="default" namespace="Company\DemoBundle\Model" defaultIdMethod="native">
    <table name="product">
        <column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
        <column name="name" type="varchar" primaryString="true" size="100" />
        <column name="price" type="decimal"/>
        <column name="description" type="longvarchar" />
    </table>
</database>

To build our model, we simply need to run one command:

php app/console propel:model:build

Great. Now if we had tables and data we could perform operations. But I haven't created tables yet. Propel can do this for us as well:

php app/console propel:sql:build
php app/console propel:sql:insert --force

This creates our tables and commits that changes. Now we can being using our models.

Additional Modifications
In the Symfony tutorial, they use the price column to store decimal values like "19.99". However, with the xml file above 19.99 will be saved as 20 because I haven't specified a scale for the decimal and the default is 0. I update the column element in the XML to this:

<column name="price" type="decimal" size="10" scale="2"/>

I'll need to update my tables. Since I haven't added any data I can simple drop the database and rebuild it using the three commands before:

php app/console propel:model:build

php app/console propel:sql:build
php app/console propel:sql:insert --force

Note: I tried adding just the "scale" attribute to the XML element, but it didn't have any affect until I added the "size" attribute.