A symfony tip: Customize Propel Generated SQL

Fabien Potencier

December 08, 2007

The Propel schema is a great way to describe your database schema. You can declare basic stuff like columns, foreign keys, and indexes. The schema also supports some more advanced features like onDelete:

<table name="comment">
  ...
  <column name="article_id" type="integer" required="true" />
  <foreign-key foreignTable="article" onDelete="cascade">
    <reference local="article_id" foreign="id"/>
  </foreign-key>
  ...
</table>
 

In YAML:

comment:
  ...
  article_id: { type: integer, foreignTable: article, foreignReference: id, onDelete: cascade }
  ...
 

But sometimes, you need a way to execute SQL statements after the schema has been created by Propel. Let's see how to do this automatically every time you launch the propel-insert-sql task (propel:insert-sql in symfony 1.1).

The propel-build-sql task executes SQL statements that drop and create tables in your database. These SQL statements have been generated previously by the propel-build-sql task (propel:build-sql in symfony 1.1). The SQL files used by the task are stored under the data/sql directory. Propel generates one file per schema. So, if you have installed some plugins like sfGuardPlugin, you will have several files:

  • lib.model.schema.sql
  • plugins.sfGuardPlugin.lib.model.schema.sql

If you have a closer look, you will also find a sqldb.map file in this directory:

# Sqlfile -> Database map
lib.model.schema.sql=propel
plugins.sfGuardPlugin.lib.model.schema.sql=propel
 

propel-insert-sql task executes files referenced in sqldb.map. So, if you want some SQL statements to be executed after Propel has created the tables, you can just add a file at the bottom of this file:

# Sqlfile -> Database map
lib.model.schema.sql=propel
plugins.sfGuardPlugin.lib.model.schema.sql=propel
post-table-creation.sql=propel
 

In the data/sql/post-table-creation.sql file, you can put any SQL. The second argument of each line (propel here), is the name of the database, as defined in your databases.yml:

all:
  propel: # name of the Propel database
    class:  sfPropelDatabase
    param:
      dsn:  mysql://root:@localhost/aidedecamp
 

Discussion

gravatar rihad  — December 10, 2007 16:46   #1
Propel? You've got to be kidding. It's all made of misfeatures. Impossible to write complex apps. A Symfony developer with 6 months of experience speaking.
gravatar hadrien  — December 10, 2007 21:01   #2
@rihad : how many month did you spent coding such "complex apps" with propel ? what fantastic ORM do u use to build your "complex apps" ? finally, what makes you so sure about propel misfeatures : your own experience or philosophical debates about pros ans cons of propel, doctrine and foo bar persistence api ?
gravatar rihad  — December 11, 2007 08:50   #3
@hadrien: 6 months, as I said, and now I'm forced to stick to Propel. I haven't tried Doctrine, but it looks promising. Propel is okay for demonstration "hello-world" apps, I guess. From my own experience Propel misfeatures are:
- when editing a model, on form submit, it forces you to "hydrate" the object from db, modify it, and save it back. I had to override its saving behavior, taking special care to modify !isNotNull() columns appropriately (so that columns declared as taking NULL can take that value on update).
- You often want only some of the columns from the table, but model forces you to fetch them all. lazyLoad="true" is a misfeature, because each such ->getFoo() will incur a separate database hit.
- The addAscendingOrderByColumn() is a misfeature. What if I want to use Postgres' ORDER BY ... NULLS FIRST? Resorting to plain SQL is not a solution, I wouldn't be using ORM in the first place, would I?
- Propel just doesn't feel right.
gravatar hadrien  — December 11, 2007 13:17   #4
@rihad : i agree propel is not the ideal orm many of us would dream of... but in my own experience, it saved me a lot of coding time and it alowed me to quickly build functional demo-apps for my customers. then, when functionnalities were aproved by the users, i could concentrate on optimising some critical database access... sometimes using plain sql, sometimes by overriding propel default behaviour, but, hey, it works prety well ! this being said, i eagerly wait for a stable release of doctrine to figure out its benefits over propel.
gravatar Fabian  — December 11, 2007 17:00   #5
rihad. You say that you might not want certain columns. I cannot find out how that fits to Object Relational Mapping. You get objects, not columns. partial objects would compromise integrity.
Special DB functionality is no in scope of propel. but I agree that the function itself to order by a column is somehow not straightforward.
Have you looked at Propel 1.3? it eliminates many issues

.: Fabian