Astuce #6 - Personnalisez la Génération SQL de Propel

This tip is also available in English.      

L'écriture d'un schéma Propel est un formidable moyen de décrire une base de données. On peut déclarer la structure de base des tables avec les colonnes, les clés étrangères et même les index. Ce schéma supporte également quelques fonctionnalités plus avancées comme la déclaration 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>
 

Ou en YAML:

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

Mais de temps en temps, vous avez besoin d'exécuter des requêtes SQL juste après que Propel ai créé les tables. Voyons comment faire cela de façon automatique à chaque appel de la tâche propel-insert-sql (ou propel:insert-sql en symfony 1.1).

La tâche propel-build-sql exécute les requêtes SQL qui vont supprimer puis re-créer les tables dans votre base de données. Ces requêtes SQL ont été générées préalablement par la tâche propel-build-sql (propel:build-sql en symfony 1.1). Les fichiers SQL utilisés par cette tâche sont stockés dans le répertoire data/sql. Propel crée un fichier par schéma. Si vous avez installé des plugins comme sfGuardPlugin, vous aurez plusieurs fichiers :

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

Si vous regardez attentivement ce répertoire, vous allez également y trouver un fichier sqldb.map:

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

La tâche propel-insert-sql exécute en fait tous les fichiers contenus dans ce fichier. Du coup, si vous souhaitez exécuter des requêtes SQL après que Propel ait créé les tables, vous avez juste à ajouter des fichiers à la fin de ce fichier :

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

Dans le fichier data/sql/post-table-creation.sql, vous pouvez mettre toutes les requêtes SQL que vous souhaitez. Le deuxième argument de chaque ligne (ici propel), est le nom de la base de données, tel que défini dans le fichier databases.yml:

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

Discussion

#1 | rihad | 2007-12-10 16:46
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.
#2 | hadrien | 2007-12-10 21:01
@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 ?
#3 | rihad | 2007-12-11 08:50
@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.
#4 | hadrien | 2007-12-11 13:17
@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.
#5 | Fabian | 2007-12-11 17:00
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
Les commentaires sur cette astuce sont fermés.
© 2007 Fabien Potencier  |  Powered by  Symfony Framework  |  Valid XHTML 1.0 Transitional