Seven months ago I started working with Doctrine (vs. Propel) and missed some of the benefits Doctrine provides,  due to lack of experience working with it. Over time I finally picked up on some of the benefits of doctrine and one of these benefits relates to the differences between sfWidgetFormDoctrineChoice and sfWidgetFormChoice (and their associated validators). This article is intended to demonstrate these differences.

sfWidgetFormDoctrineChoice

The main benefit of using this widget vs sfWidgetFormChoice, is that you can specify an object from your model and Doctrine will automagically know how to retreive the data. You can also specify other options to fully configure your choice options.  For example:

// lib/doctrine/form/BookForm.class.php
public function configure()
{
// This will create a single select drop downbox using data stored in Category model. It will also add an empty select option as the first option and sort the categories
// by name, asc
$this->widgetSchema['category_list']    = new sfWidgetFormDoctrineChoice(array('model' => 'Category', 'multiple' => false, 'add_empty' => true, 'order_by' => array('name', 'asc')));

// Or maybe you want a multiple select option, no problem.

// Notice the multiple option is set to true and the add_empty option has been removed, useful for admin double lists
$this->widgetSchema['category_list']    = new sfWidgetFormDoctrineChoice(array('model' => 'Category', 'multiple' => true, 'order_by' => array('name', 'asc')));
}

There are other options you can pass to sfWidgetFormDoctrineChoice which can be found via Symfony’s api documentation.

If you are a propel user, don’t fret, propel follows the same logic but uses sfWidgetFormPropelChoice.

Ok so we got sfWidgetFormDoctrineChoice setup, but what about an accompanying validator? Again, no problem, check out the following example:

// Notice that sfValidatorDoctrineChoice takes the same two arguments that we had in sfWidgetFormDoctrineChoice; model and multiple
// The only difference is the 'column' option which allows us to tell doctrine which column from the Category model will be used for validating
// submitted values
$this->validatorSchema['category_list']     = new sfValidatorDoctrineChoice(array('model' => 'Category', 'column' => 'id', 'multiple' => true));

Also, just like sfWidgetFormDoctrineChoice, there are other options  you can use when instantiating a new sfValidatorDoctrineChoice object; refer to the for all the options: api documentation.

So far I’ve only discussed sfWidgetFormDoctrineChoice, but what about sfWidgetFormChoice, when should we use it? I’ve found the best scenarios for using sfWidgetFormChoice occur when you have a list of options that are not supplied by a model object. For example, say you wanted to maintain a list of static options for book types; ‘format’ (i.e. paperback, hardcover).

Because there are only a handful of options which won’t change much over time, its better to make ‘format’ options class constants rather than create a table, add them to schema, and rebuild the model.

To display these options as a select list you would use sfWidgetFormChoice b/c there is no model which will automagically provide the needed data for your select list.

Lets see it in action:

// An example of using class constants to set values

// lib/model/doctrine/BookFormat.class.php
const FORMAT_TYPE_PAPERBACK = 1;
const FORMAT_TYPE_HARDCOVER = 2;

public static $formatTypes = array(
    self::FORMAT_TYPE_PAPERBACK => 'paperback',
    self::FORMAT_TYPE_HARDCOVER => 'hardcover'
);

// lib/form/doctrine/BookForm.class.php

$formatTypes = BookFormat::$formatTypes;

// I want to add an empty element so user is aware they must select something
$formatTypes = array('' => '') + $formatTypes

// Now pass to sfWidgetFormChoice
$this->widgetSchema['book_formats'] = new sfWidgetFormChoice(array('choices' => $formatTypes));

// Notice we calling array_keys so when form validates it will validate against 1,2,3 vs the string (paperback, hardcover)
$this->validatorSchema['book_formats'] = new sfValidatorChoice(array('choices' => array_keys($formatTypes), 'required' => false));

One thing to remember with the sfWidgetFormChoice example, you still must have a column in your object model to house the submitted value, otherwise the submitted value will be redirected to /dev/null.

Hopefully this article clearly demonstrated the differences between sfWidgetFormDoctrineChoice and sfWidgetFormChoice and when to use which. Thanks for reading and HTH.