From 62650bbdc7949798550f644531ddab4b8d8526ea Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Fri, 2 Apr 2021 09:52:16 -0400 Subject: [PATCH] [Form] Add support for sorting fields --- src/Symfony/Component/Form/CHANGELOG.md | 1 + .../Form/Extension/Core/Type/BaseType.php | 5 ++++ src/Symfony/Component/Form/Form.php | 27 +++++++++++++++++++ .../Extension/Core/Type/FormTypeTest.php | 23 ++++++++++++++++ .../Descriptor/resolved_form_type_1.json | 1 + .../Descriptor/resolved_form_type_1.txt | 1 + .../Descriptor/resolved_form_type_2.json | 1 + .../Descriptor/resolved_form_type_2.txt | 1 + 8 files changed, 60 insertions(+) diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 2ab805eb990b1..9a8dae4739d53 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -15,6 +15,7 @@ CHANGELOG * Added a `choice_translation_parameters` option to `ChoiceType` * Add `UuidType` and `UlidType` * Dependency on `symfony/intl` was removed. Install `symfony/intl` if you are using `LocaleType`, `CountryType`, `CurrencyType`, `LanguageType` or `TimezoneType`. + * Add `priority` option to `BaseType` and sorting view fields 5.2.0 ----- diff --git a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php index 3b5a3a01b5601..4ac58bd2acd05 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php @@ -107,6 +107,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) 'translation_domain' => $translationDomain, 'label_translation_parameters' => $labelTranslationParameters, 'attr_translation_parameters' => $attrTranslationParameters, + 'priority' => $options['priority'], // Using the block name here speeds up performance in collection // forms, where each entry has the same full block name. // Including the type is important too, because if rows of a @@ -135,11 +136,15 @@ public function configureOptions(OptionsResolver $resolver) 'attr' => [], 'translation_domain' => null, 'auto_initialize' => true, + 'priority' => 0, ]); $resolver->setAllowedTypes('block_prefix', ['null', 'string']); $resolver->setAllowedTypes('attr', 'array'); $resolver->setAllowedTypes('row_attr', 'array'); $resolver->setAllowedTypes('label_html', 'bool'); + $resolver->setAllowedTypes('priority', 'int'); + + $resolver->setInfo('priority', 'The form rendering priority (higher priorities will be rendered first)'); } } diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index e22415c95efdb..1901524562c6a 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -1044,11 +1044,38 @@ public function createView(FormView $parent = null) $view->children[$name] = $child->createView($view); } + $this->sort($view->children); + $type->finishView($view, $this, $options); return $view; } + /** + * Sorts view fields based on their priority value. + */ + private function sort(array &$children): void + { + $c = []; + $i = 0; + $needsSorting = false; + foreach ($children as $name => $child) { + $c[$name] = ['p' => $child->vars['priority'] ?? 0, 'i' => $i++]; + + if (0 !== $c[$name]['p']) { + $needsSorting = true; + } + } + + if (!$needsSorting) { + return; + } + + uksort($children, static function ($a, $b) use ($c): int { + return [$c[$b]['p'], $c[$a]['i']] <=> [$c[$a]['p'], $c[$b]['i']]; + }); + } + /** * Normalizes the underlying data if a model transformer is set. * diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index ffbcfbaa64f15..3701b653f855e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -836,6 +836,29 @@ public function testFormAttrAsStringWithNoId() $this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']); $this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']); } + + public function testSortingViewChildrenBasedOnPriorityOption() + { + $view = $this->factory->createNamedBuilder('parent', self::TESTED_TYPE) + ->add('child1', null, ['priority' => -1]) + ->add('child2') + ->add('child3', null, ['priority' => -1]) + ->add('child4') + ->add('child5', null, ['priority' => 1]) + ->add('child6') + ->getForm() + ->createView(); + + $expected = [ + 'child5', + 'child2', + 'child4', + 'child6', + 'child1', + 'child3', + ]; + $this->assertSame($expected, array_keys($view->children)); + } } class Money diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json index 2b51a6e40b131..c9f453c8d6cc6 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json @@ -57,6 +57,7 @@ "mapped", "method", "post_max_size_message", + "priority", "property_path", "required", "row_attr", diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt index 42e858528e565..c4c4e901804af 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt @@ -34,6 +34,7 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice") mapped method post_max_size_message + priority property_path required row_attr diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json index 5bb64c00fd5ab..225ec9ae08600 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json @@ -35,6 +35,7 @@ "mapped", "method", "post_max_size_message", + "priority", "property_path", "required", "row_attr", diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt index 30ba52c92a3a5..40506a1f67a1d 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt @@ -37,6 +37,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form") mapped method post_max_size_message + priority property_path required row_attr