add preferred_query option to ModelType

This enables the ModelChoiceList to use 'preferred_choices' of the parent ChoiceType.
This commit is contained in:
Toni Uebernickel 2012-12-21 12:16:37 +01:00
parent 031a09dc00
commit 6855cffb1d
3 changed files with 86 additions and 14 deletions

View File

@ -11,8 +11,10 @@
namespace Symfony\Bridge\Propel1\Form\ChoiceList;
use \ModelCriteria;
use \BaseObject;
use \Persistent;
use Symfony\Component\Form\Exception\FormException;
use Symfony\Component\Form\Exception\StringCastException;
use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
@ -21,6 +23,7 @@ use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
* Widely inspirated by the EntityChoiceList.
*
* @author William Durand <william.durand1@gmail.com>
* @author Toni Uebernickel <tuebernickel@gmail.com>
*/
class ModelChoiceList extends ObjectChoiceList
{
@ -31,28 +34,44 @@ class ModelChoiceList extends ObjectChoiceList
*
* @var array
*/
private $identifier = array();
protected $identifier = array();
/**
* Query
* The query to retrieve the choices of this list.
*
* @var ModelCriteria
*/
private $query = null;
protected $query;
/**
* The query to retrieve the preferred choices for this list.
*
* @var ModelCriteria
*/
protected $preferredQuery;
/**
* Whether the model objects have already been loaded.
*
* @var Boolean
*/
private $loaded = false;
protected $loaded = false;
/**
* @param string $class
* @param string $labelPath
* @param array $choices
* @param \ModelCriteria $queryObject
* @param string $groupPath
* Constructor.
*
* @see Symfony\Bridge\Propel1\Form\Type\ModelType How to use the preferred choices.
*
* @param string $class The FQCN of the model class to be loaded.
* @param string $labelPath A property path pointing to the property used for the choice labels.
* @param array $choices An optional array to use, rather than fetching the models.
* @param ModelCriteria $queryObject The query to use retrieving model data from database.
* @param string $groupPath A property path pointing to the property used to group the choices.
* @param array|ModelCriteria $preferred The preferred items of this choice.
* Either an array if $choices is given,
* or a ModelCriteria to be merged with the $queryObject.
*/
public function __construct($class, $labelPath = null, $choices = null, $queryObject = null, $groupPath = null)
public function __construct($class, $labelPath = null, $choices = null, $queryObject = null, $groupPath = null, $preferred = array())
{
$this->class = $class;
@ -63,13 +82,18 @@ class ModelChoiceList extends ObjectChoiceList
$this->query = $queryObject ?: $query;
$this->loaded = is_array($choices) || $choices instanceof \Traversable;
if ($preferred instanceof ModelCriteria) {
$this->preferredQuery = $preferred->mergeWith($this->query);
}
if (!$this->loaded) {
// Make sure the constraints of the parent constructor are
// fulfilled
$choices = array();
$preferred = array();
}
parent::__construct($choices, $labelPath, array(), $groupPath);
parent::__construct($choices, $labelPath, $preferred, $groupPath);
}
/**
@ -316,11 +340,11 @@ class ModelChoiceList extends ObjectChoiceList
private function load()
{
$models = (array) $this->query->find();
$preferred = (array) $this->preferredQuery->find();
try {
// The second parameter $labels is ignored by ObjectChoiceList
// The third parameter $preferredChoices is currently not supported
parent::initialize($models, array(), array());
parent::initialize($models, array(), $preferred);
} catch (StringCastException $e) {
throw new StringCastException(str_replace('argument $labelPath', 'option "property"', $e->getMessage()), null, $e);
}

View File

@ -22,6 +22,29 @@ use Symfony\Component\OptionsResolver\OptionsResolverInterface;
* ModelType class.
*
* @author William Durand <william.durand1@gmail.com>
* @author Toni Uebernickel <tuebernickel@gmail.com>
*
* Example using the preferred_query option.
*
* <code>
* public function buildForm(FormBuilderInterface $builder, array $options)
* {
* $builder
* ->add('product', 'model', array(
* 'class' => 'Model\Product',
* 'query' => ProductQuery::create()
* ->filterIsActive(true)
* ->useI18nQuery($options['locale'])
* ->orderByName()
* ->endUse()
* ,
* 'preferred_query' => ProductQuery::create()
* ->filterByIsTopProduct(true)
* ,
* ))
* ;
* }
* </code>
*/
class ModelType extends AbstractType
{
@ -40,7 +63,8 @@ class ModelType extends AbstractType
$options['property'],
$options['choices'],
$options['query'],
$options['group_by']
$options['group_by'],
$options['preferred_query']
);
};
@ -55,6 +79,7 @@ class ModelType extends AbstractType
'choice_list' => $choiceList,
'group_by' => null,
'by_reference' => false,
'preferred_query' => null,
));
}

View File

@ -70,6 +70,29 @@ class ModelChoiceListTest extends Propel1TestCase
$this->assertSame(array(1 => $item1, 2 => $item2), $choiceList->getChoices());
}
public function testFlattenedPreferredChoices()
{
$item1 = new Item(1, 'Foo');
$item2 = new Item(2, 'Bar');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array(
$item1,
$item2,
),
null,
null,
array(
$item1
)
);
$this->assertSame(array(1 => $item1, 2 => $item2), $choiceList->getChoices());
$this->assertEquals(array(1 => new ChoiceView($item1, '1', 'Foo')), $choiceList->getPreferredViews());
}
public function testNestedChoices()
{
$item1 = new Item(1, 'Foo');