Saturday, July 04, 2009

10 Doctrine gotchas

Here is a list of tips for Doctrine usage in php projects, ranging from hydration to magic method. They are valid for the 1.x versions.
I am currently working on generation of Zend_Form instances based on Doctrine objects, that use model metadata to create form elements of the right type. Doctrine is very powerful, but while developing Otk_Form_Doctrine, I had some gotchas that I'd like to share with other php developers that use this orm.
  1. findAll() and findOne*() does not hydrate the object. If you obtain a collection or a record with one of these methods, a subsequent access to a relation would raise a new query to the database. Hydration should be your repositories concern, and you have to decide what relation hydrate by default.
  2. you can generate table classes, with proper options set in Doctrine facade calls. "generateTableClasses" is the option needed, see the documentation for examples.
  3. fixture keys are unique throughout the whole set of files imported. This means that if you have a bunch of yaml files where you write fixtures, you have to make sure that the keys of the various records are all different, so don't use 1, 2, ... as keys, but meaningful names instead.
  4. unlink() is not permanent until saved. From version 1.1 of Doctrine, until you call save() on a record, unlinked relationship would not be reflected to the database. A more consistent behaviour than the previous 1.0 version one, where unlink() will automatically save changes when called. For a deep model introspection, it is better to have a single point of saving as we have now.
  5. Doctrine validation is turned off by default, so every save() might not saving all the data, resulting in truncated text fields...
  6. ...but if you turn it on, remember that a form value of "" on a integer field will result in a non valid record and save() will throw an exception().
  7. Doctrine many-to-many relations are bidirectional. So even if you don't define a side of a m-n relationship, it will be present in the record and will be listed by methods like toArray() when hydrated.
  8. The methods getRelations() and getColumns() of Doctrine_Table can give you a lot of introspection of the model from the script point of view. In my case, I was able to generate form elements and subforms according to the business object structure, for instance a dojo DateTextBox with a sexy calendar to represent a timestamp model column.
  9. __toString() is very useful in a Doctrine_Record subclass, putting together the identity fields of the object to represent it for various purposes like dumping or putting it in a list.
  10. __call() is also very handy in a decorator for a Doctrine_Record or Doctrine_Table object, used for proxying to the underlying instance methods.

Hope this tips help you to follow the Doctrine... :)

No comments: