[Form] Improved FormType::getDefaultOptions() to see default options defined in parent types

In turn, FormType::getParent() does not see default options anymore.
This commit is contained in:
Bernhard Schussek 2012-02-07 10:51:21 +01:00
parent b9facfc5ae
commit 88ef52d272
9 changed files with 62 additions and 19 deletions

View File

@ -202,6 +202,8 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
* added options "add_method" and "remove_method" to collection and choice type * added options "add_method" and "remove_method" to collection and choice type
* forms now don't create an empty object anymore if they are completely * forms now don't create an empty object anymore if they are completely
empty and not required. The empty value for such forms is null. empty and not required. The empty value for such forms is null.
* FormType::getDefaultOptions() now sees default options defined by parent types
* [BC BREAK] FormType::getParent() does not see default options anymore
### HttpFoundation ### HttpFoundation

View File

@ -229,3 +229,22 @@ UPGRADE FROM 2.0 to 2.1
return false; return false;
} }
} }
* The options passed to `getParent` of the form types don't contain default
options anymore
You should check with `isset` if options exist before checking their value.
Before:
public function getParent()
{
return 'single_text' === $options['widget'] ? 'text' : 'choice';
}
After:
public function getParent()
{
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'text' : 'choice';
}

View File

@ -50,7 +50,6 @@ abstract class DoctrineType extends AbstractType
'property' => null, 'property' => null,
'query_builder' => null, 'query_builder' => null,
'loader' => null, 'loader' => null,
'choices' => null,
'group_by' => null, 'group_by' => null,
); );

View File

@ -149,7 +149,7 @@ class ChoiceType extends AbstractType
'multiple' => false, 'multiple' => false,
'expanded' => false, 'expanded' => false,
'choice_list' => null, 'choice_list' => null,
'choices' => array(), 'choices' => null,
'preferred_choices' => array(), 'preferred_choices' => array(),
'value_strategy' => ChoiceList::GENERATE, 'value_strategy' => ChoiceList::GENERATE,
'index_strategy' => ChoiceList::GENERATE, 'index_strategy' => ChoiceList::GENERATE,
@ -166,7 +166,7 @@ class ChoiceType extends AbstractType
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return $options['expanded'] ? 'form' : 'field'; return isset($options['expanded']) && $options['expanded'] ? 'form' : 'field';
} }
/** /**

View File

@ -200,7 +200,7 @@ class DateTimeType extends AbstractType
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return 'single_text' === $options['widget'] ? 'field' : 'form'; return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
} }
/** /**

View File

@ -211,7 +211,7 @@ class DateType extends AbstractType
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return 'single_text' === $options['widget'] ? 'field' : 'form'; return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
} }
/** /**

View File

@ -184,7 +184,7 @@ class TimeType extends AbstractType
*/ */
public function getParent(array $options) public function getParent(array $options)
{ {
return 'single_text' === $options['widget'] ? 'field' : 'form'; return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
} }
/** /**

View File

@ -31,7 +31,7 @@ class TimezoneType extends AbstractType
'value_strategy' => ChoiceList::COPY_CHOICE, 'value_strategy' => ChoiceList::COPY_CHOICE,
); );
if (!isset($options['choice_list']) && !isset($options['choices'])) { if (empty($options['choice_list']) && empty($options['choices'])) {
$defaultOptions['choices'] = self::getTimezones(); $defaultOptions['choices'] = self::getTimezones();
} }

View File

@ -213,16 +213,20 @@ class FormFactory implements FormFactoryInterface
*/ */
public function createNamedBuilder($type, $name, $data = null, array $options = array(), FormBuilder $parent = null) public function createNamedBuilder($type, $name, $data = null, array $options = array(), FormBuilder $parent = null)
{ {
$builder = null;
$types = array();
$knownOptions = array();
$passedOptions = array_keys($options);
$optionValues = array();
if (!array_key_exists('data', $options)) { if (!array_key_exists('data', $options)) {
$options['data'] = $data; $options['data'] = $data;
} }
$builder = null;
$types = array();
$defaultOptions = array();
$optionValues = array();
$passedOptions = $options;
// Bottom-up determination of the type hierarchy
// Start with the actual type and look for the parent type
// The complete hierarchy is saved in $types, the first entry being
// the root and the last entry being the leaf (the concrete type)
while (null !== $type) { while (null !== $type) {
if ($type instanceof FormTypeInterface) { if ($type instanceof FormTypeInterface) {
if ($type->getName() == $type->getParent($options)) { if ($type->getName() == $type->getParent($options)) {
@ -236,7 +240,23 @@ class FormFactory implements FormFactoryInterface
throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface'); throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
} }
$defaultOptions = $type->getDefaultOptions($options); array_unshift($types, $type);
// getParent() cannot see default options set by this type nor
// default options set by parent types
// As a result, the options always have to be checked for
// existence with isset() before using them in this method.
$type = $type->getParent($options);
}
// Top-down determination of the options and default options
foreach ($types as $type) {
// Merge the default options of all types to an array of default
// options. Default options of children override default options
// of parents.
// Default options of ancestors are already visible in the $options
// array passed to the following methods.
$defaultOptions = array_replace($defaultOptions, $type->getDefaultOptions($options));
$optionValues = array_merge_recursive($optionValues, $type->getAllowedOptionValues($options)); $optionValues = array_merge_recursive($optionValues, $type->getAllowedOptionValues($options));
foreach ($type->getExtensions() as $typeExtension) { foreach ($type->getExtensions() as $typeExtension) {
@ -244,20 +264,23 @@ class FormFactory implements FormFactoryInterface
$optionValues = array_merge_recursive($optionValues, $typeExtension->getAllowedOptionValues($options)); $optionValues = array_merge_recursive($optionValues, $typeExtension->getAllowedOptionValues($options));
} }
$options = array_replace($defaultOptions, $options); // In each turn, the options are replaced by the combination of
$knownOptions = array_merge($knownOptions, array_keys($defaultOptions)); // the currently known default options and the passed options.
array_unshift($types, $type); // It is important to merge with $passedOptions and not with
$type = $type->getParent($options); // $options, otherwise default options of parents would override
// default options of child types.
$options = array_replace($defaultOptions, $passedOptions);
} }
$type = end($types); $type = end($types);
$knownOptions = array_keys($defaultOptions);
$diff = array_diff(self::$requiredOptions, $knownOptions); $diff = array_diff(self::$requiredOptions, $knownOptions);
if (count($diff) > 0) { if (count($diff) > 0) {
throw new TypeDefinitionException(sprintf('Type "%s" should support the option(s) "%s"', $type->getName(), implode('", "', $diff))); throw new TypeDefinitionException(sprintf('Type "%s" should support the option(s) "%s"', $type->getName(), implode('", "', $diff)));
} }
$diff = array_diff($passedOptions, $knownOptions); $diff = array_diff(array_keys($passedOptions), $knownOptions);
if (count($diff) > 1) { if (count($diff) > 1) {
throw new CreationException(sprintf('The options "%s" do not exist. Known options are: "%s"', implode('", "', $diff), implode('", "', $knownOptions))); throw new CreationException(sprintf('The options "%s" do not exist. Known options are: "%s"', implode('", "', $diff), implode('", "', $knownOptions)));