8000 [Form] Improved FormType::getDefaultOptions() to see default options … · symfony/symfony@88ef52d · GitHub
[go: up one dir, main page]

Skip to content

Commit 88ef52d

Browse files
committed
[Form] Improved FormType::getDefaultOptions() to see default options defined in parent types
In turn, FormType::getParent() does not see default options anymore.
1 parent b9facfc commit 88ef52d

File tree

9 files changed

+62
-19
lines changed

9 files changed

+62
-19
lines changed

CHANGELOG-2.1.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
202202
* added options "add_method" and "remove_method" to collection and choice type
203203
* forms now don't create an empty object anymore if they are completely
204204
empty and not required. The empty value for such forms is null.
205+
* FormType::getDefaultOptions() now sees default options defined by parent types
206+
* [BC BREAK] FormType::getParent() does not see default options anymore
205207

206208
### HttpFoundation
207209

UPGRADE-2.1.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,22 @@ UPGRADE FROM 2.0 to 2.1
229229
return false;
230230
}
231231
}
232+
233+
* The options passed to `getParent` of the form types don't contain default
234+
options anymore
235+
236+
You should check with `isset` if options exist before checking their value.
237+
238+
Before:
239+
240+
public function getParent()
241+
{
242+
return 'single_text' === $options['widget'] ? 'text' : 'choice';
243+
}
244+
245+
After:
246+
247+
public function getParent()
248+
{
249+
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'text' : 'choice';
250+
}

src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ public function getDefaultOptions(array $options)
5050
'property' => null,
5151
'query_builder' => null,
5252
'loader' => null,
53-
'choices' => null,
5453
'group_by' => null,
5554
);
5655

src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public function getDefaultOptions(array $options)
149149
'multiple' => false,
150150
'expanded' => false,
151151
'choice_list' => null,
152-
'choices' => array(),
152+
'choices' => null,
153153
'preferred_choices' => array(),
154154
'value_strategy' => ChoiceList::GENERATE,
155155
'index_strategy' => ChoiceList::GENERATE,
@@ -166,7 +166,7 @@ public function getDefaultOptions(array $options)
166166
*/
167167
public function getParent(array $options)
168168
{
169-
return $options['expanded'] ? 'form' : 'field';
169+
return isset($options['expanded']) && $options['expanded'] ? 'form' : 'field';
170170
}
171171

172172
/**

src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ public function getAllowedOptionValues(array $options)
200200
*/
201201
public function getParent(array $options)
202202
{
203-
return 'single_text' === $options['widget'] ? 'field' : 'form';
203+
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
204204
}
205205

206206
/**

src/Symfony/Component/Form/Extension/Core/Type/DateType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public function getAllowedOptionValues(array $options)
211211
*/
212212
public function getParent(array $options)
213213
{
214-
return 'single_text' === $options['widget'] ? 'field' : 'form';
214+
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
215215
}
216216

217217
/**

src/Symfony/Component/Form/Extension/Core/Type/TimeType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public function getAllowedOptionValues(array $options)
184184
*/
185185
public function getParent(array $options)
186186
{
187-
return 'single_text' === $options['widget'] ? 'field' : 'form';
187+
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'field' : 'form';
188188
}
189189

190190
/**

src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function getDefaultOptions(array $options)
3131
'value_strategy' => ChoiceList::COPY_CHOICE,
3232
);
3333

34-
if (!isset($options['choice_list']) && !isset($options['choices'])) {
34+
if (empty($options['choice_list']) && empty($options['choices'])) {
3535
$defaultOptions['choices'] = self::getTimezones();
3636
}
3737

src/Symfony/Component/Form/FormFactory.php

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -213,16 +213,20 @@ public function createBuilder($type, $data = null, array $options = array(), For
213213
*/
214214
public function createNamedBuilder($type, $name, $data = null, array $options = array(), FormBuilder $parent = null)
215215
{
216-
$builder = null;
217-
$types = array();
218-
$knownOptions = array();
219-
$passedOptions = array_keys($options);
220-
$optionValues = array();
221-
222216
if (!array_key_exists('data', $options)) {
223217
$options['data'] = $data;
224218
}
225219

220+
$builder = null;
221+
$types = array();
222+
$defaultOptions = array();
223+
$optionValues = array();
224+
$passedOptions = $options;
225+
226+
// Bottom-up determination of the type hierarchy
227+
// Start with the actual type and look for the parent type
228+
// The complete hierarchy is saved in $types, the first entry being
229+
// the root and the last entry being the leaf (the concrete type)
226230
while (null !== $type) {
227231
if ($type instanceof FormTypeInterface) {
228232
if ($type->getName() == $type->getParent($options)) {
@@ -236,28 +240,47 @@ public function createNamedBuilder($type, $name, $data = null, array $options =
236240
throw new UnexpectedTypeException($type, 'string or Symfony\Component\Form\FormTypeInterface');
237241
}
238242

239-
$defaultOptions = $type->getDefaultOptions($options);
243+
array_unshift($types, $type);
244+
245+
// getParent() cannot see default options set by this type nor
246+
// default options set by parent types
247+
// As a result, the options always have to be checked for
248+
// existence with isset() before using them in this method.
249+
$type = $type->getParent($options);
250+
}
251+
252+
// Top-down determination of the options and default options
253+
foreach ($types as $type) {
254+
// Merge the default options of all types to an array of default
255+
// options. Default options of children override default options
256+
// of parents.
257+
// Default options of ancestors are already visible in the $options
258+
// array passed to the following methods.
259+
$defaultOptions = array_replace($defaultOptions, $type->getDefaultOptions($options));
240260
$optionValues = array_merge_recursive($optionValues, $type->getAllowedOptionValues($options));
241261

242262
foreach ($type->getExtensions() as $typeExtension) {
243263
$defaultOptions = array_replace($defaultOptions, $typeExtension->getDefaultOptions($options));
244264
$optionValues = array_merge_recursive($optionValues, $typeExtension->getAllowedOptionValues($options));
245265
}
246266

247-
$options = array_replace($defaultOptions, $options);
248-
$knownOptions = array_merge($knownOptions, array_keys($defaultOptions));
249-
array_unshift($types, $type);
250-
$type = $type->getParent($options);
267+
// In each turn, the options are replaced by the combination of
268+
// the currently known default options and the passed options.
269+
// It is important to merge with $passedOptions and not with
270+
// $options, otherwise default options of parents would override
271+
// default options of child types.
272+
$options = array_replace($defaultOptions, $passedOptions);
251273
}
252274

253275
$type = end($types);
276+
$knownOptions = array_keys($defaultOptions);
254277
$diff = array_diff(self::$requiredOptions, $knownOptions);
255278

256279
if (count($diff) > 0) {
257280
throw new TypeDefinitionException(sprintf('Type "%s" should support the option(s) "%s"', $type->getName(), implode('", "', $diff)));
258281
}
259282

260-
$diff = array_diff($passedOptions, $knownOptions);
283+
$diff = array_diff(array_keys($passedOptions), $knownOptions);
261284

262285
if (count($diff) > 1) {
263286
throw new CreationException(sprintf('The options "%s" do not exist. Known options are: "%s"', implode('", "', $diff), implode('", "', $knownOptions)));

0 commit comments

Comments
 (0)
0