So, you want to give Doctrine a try with symfony 1.1 eh? First we will need to setup a new symfony 1.1 project and install the sfDoctrinePlugin for 1.1. Execute the following commands below and continue reading:

$ mkdir symfony1.1Doctrine
$ cd symfony1.1Doctrine
$ /path/to/symfony generate:project symfony1.1Doctrine
$ svn co plugins/sfDoctrinePlugin
$ php symfony cc

Now, type the following command to list all the new commands that sfDoctrinePlugin provides. You will notice that it gives you all the same commands as sfPropelPlugin and lots more!

$ php symfony list doctrine
Available tasks for the "doctrine" namespace:
  :build-all                   Generates Doctrine model, SQL and initializes the database (doctrine-build-all)
  :build-all-load              Generates Doctrine model, SQL, initializes database, and load data (doctrine-build-all-load)
  :build-all-reload            Generates Doctrine model, SQL, initializes database, and load data (doctrine-build-all-reload)
  :build-all-reload-test-all   Generates Doctrine model, SQL, initializes database, load data and run all test suites (doctrine-build-all-reload-test-all)
  :build-db                    Creates database for current model (doctrine-build-db)
  :build-forms                 Creates form classes for the current model (doctrine-build-forms)
  :build-model                 Creates classes for the current model (doctrine-build-model)
  :build-schema                Creates a schema.xml from an existing database (doctrine-build-schema)
  :build-sql                   Creates SQL for the current model (doctrine-build-sql)
  :data-dump                   Dumps data to the fixtures directory (doctrine-dump-data)
  :data-load                   Loads data from fixtures directory (doctrine-load-data)
  :dql                         Execute a DQL query and view the results (doctrine-dql)
  :drop-db                     Drops database for current model (doctrine-drop-db)
  :generate-crud               Generates a Doctrine CRUD module (doctrine-generate-crud)
  :generate-migration          Generate migration class (doctrine-generate-migration)
  :generate-migrations-db      Generate migration classes from existing database connections (doctrine-generate-migrations-db, doctrine-gen-migrations-from-db)
  :generate-migrations-models  Generate migration classes from an existing set of models (doctrine-generate-migrations-models, doctrine-gen-migrations-from-models)
  :init-admin                  Initializes a Doctrine admin module (doctrine-init-admin)
  :insert-sql                  Inserts SQL for current model (doctrine-insert-sql)
  :migrate                     Migrates database to current/specified version (doctrine-migrate)
  :rebuild-db                  Creates database for current model (doctrine-rebuild-db)

First, sfDoctrinePlugin currently requires that at least one application be setup, so lets just instantiate a frontend application now.

$ php symfony generate:app frontend

Now lets setup our database configuration in config/databases.yml. Open the file in your favorite editor and place the YAML below inside. For this test we are simply using a SQLite database. Doctrine is able to create the SQLite database at the config/doctrine.db path for you which we will do once we setup our schema and some data fixtures.

    class:    sfDoctrineDatabase
      dsn:    sqlite:///< ?php echo dirname(__FILE__); ?>/doctrine.db

Now that we have our database configured, lets define our YAML schema files in config/doctrine/schema.yml. In this example we are setting up a simple BlogPost model which hasMany Tags.

      fields: [title]
    title: string(255)
    body: clob
    author: string(255)
      class: Tag
      refClass: BlogPostTag
      foreignAlias: BlogPosts
      type: integer
      primary: true
      type: integer
      primary: true
  actAs: [Timestampable]
    name: string(255)

Now that we have our Doctrine schema defined, lets create some test data fixtures in data/fixtures/data.yml. Open the file in your favorite editor and paste the below YAML in to the file.

    title:  symfony + Doctrine
    body:   symfony and Doctrine are great!
    author: Jonathan H. Wage
    Tags:   [symfony, doctrine, php]
    name: symfony
    name: doctrine
    name: php

Ok, now for the fun stuff. We have our schema, and we have some data fixtures, so lets run one single Doctrine command and create your database, generate your models, create tables and load the data fixtures.

$ php symfony doctrine-build-all-reload frontend
>> doctrine  Are you sure you wish to drop your databases? (y/n)
>> doctrine  Successfully dropped database f...1.1Doctrine/config/doctrine.db"
>> doctrine  Successfully created database f...1.1Doctrine/config/doctrine.db"
>> doctrine  Generated models successfully
>> doctrine  Created tables successfully
>> doctrine  Data was successfully loaded

Now your doctrine.db SQLite database is created, all the tables for your schema were created, and the data fixtures were populated in to the tables. Now lets do a little playing around with the data to see how we can use the Doctrine Query Language to retrieve data.

$ php symfony doctrine:dql frontend "FROM BlogPost p, p.Tags t"
>> doctrine  executing: "FROM BlogPost p, p.Tags t" ()
>> doctrine  - 
>> doctrine    id: 1
>> doctrine    title: symfony + Doctrine
>> doctrine    body: symfony and Doctrine are great!
>> doctrine    author: Jonathan H. Wage
>> doctrine    slug: symfony-doctrine
>> doctrine    created_at: 2008-06-16 12:28:57
>> doctrine    updated_at: 2008-06-16 12:28:57
>> doctrine    Tags: 
>> doctrine      - 
>> doctrine        id: 1
>> doctrine        name: symfony
>> doctrine        created_at: 2008-06-16 12:28:57
>> doctrine        updated_at: 2008-06-16 12:28:57
>> doctrine      - 
>> doctrine        id: 2
>> doctrine        name: doctrine
>> doctrine        created_at: 2008-06-16 12:28:57
>> doctrine        updated_at: 2008-06-16 12:28:57
>> doctrine      - 
>> doctrine        id: 3
>> doctrine        name: php
>> doctrine        created_at: 2008-06-16 12:28:57
>> doctrine        updated_at: 2008-06-16 12:28:57

Now, lets do a little explaning of the data that was returned. As you can see the models have a created_at, updated_at and slug column which were not defined in the schema files. These columns are added by the behaviors attached to the schema information under the actAs setting. The created_at and updated_at column are automatically set onInsert and onUpdate, and the slug column is a url friendly string that is created from the value of the name column. Doctrine has a few behaviors that are included in core such as Sluggable and Timestampable, but the behavior system is built to allow anyone to easily write behaviors for their models to re-use over and over.

Now we have our data model all setup and populated with some test fixtures so lets generate an admin generator to manage the blog posts and tags.

$ php symfony doctrine:init-admin frontend blog_posts BlogPost
$ php symfony doctrine:init-admin frontend tags Tag

>Note >The admin generator templates for sfDoctrinePlugin have not yet been fully updated for symfony 1.1 as they still require the compat_10 option to be turned on in apps/frontend/config/settings.yml. They will be 100% updated before the official release of symfony 1.1 stable.

Now go open up your web browser and check out the frontend application and the blog_posts and tags modules. It should be located at a url like the following:

$ http://localhost/symfony1.1Doctrine/web/frontend_dev.php/blog_posts
$ http://localhost/symfony1.1Doctrine/web/frontend_dev.php/tags

blog posts

Now, with a little configuration of the blog post admin generator, we can control the associated blog post tags by checking checkboxes when editing a blog post. Open apps/frontend/modules/blog_posts/config/generator.yml and replace the contents with the YAML from below.

  class:              sfDoctrineAdminGenerator
    model_class:      BlogPost
    theme:            default
      display:        [=title, author]
        _edit:        -
        _delete:      -
      display:        [author, title, body, Tags]
          type:       input_tag
          type:       input_tag
          type:       textarea_tag
          params:     size=50x10
          type:       doctrine_admin_check_list
          params:     through_class=BlogPostTag

Now refresh the blog post list and you will see it is cleaned up a little bit. Edit a blog post by clicking the edit icon or the title and you can see below you can check the tags associated to the blog post.

edit blog posts

All of the features you get in Propel work 99% the same way with Doctrine, so it should be fairly easy to get the hang of if you are coming from propel. sfDoctrinePlugin implements all the same functionality as sfPropelPlugin as well as several additional features which sfPropelPlugin is not capable of. Below you can find some more information on the major features that Doctrine supports:

  • Behaviors - Easily create reusable behaviors for your Doctrine models.
  • Migrations - Deploy database schema changes to your production environment through a programmatic interface.
  • Doctrine Query Language - Build your database queries through a fluent OO interface
  • Validators - Turn on column validators for both database and code level validation.
  • Hierarchical Data - Turn your models in to nested sets easily with the flip of a switch.
  • Caching - Tune performance by caching your DQL query parsing and the result sets of queries.

If this short tutorial sparked your interest in Doctrine you can check out some other Doctrine resources below to learn more about Doctrine: