From 11e570018064702808bf1d98e86431bf80d651e1 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 24 Apr 2024 12:12:14 +0200 Subject: [PATCH 01/11] deprecate the use of option arrays to configure validation constraints --- .../FormValidatorFunctionalTest.php | 72 ++++++++----------- .../Constraints/FormValidatorTest.php | 12 ++-- .../Type/FormTypeValidatorExtensionTest.php | 10 +-- .../Validator/ValidatorTypeGuesserTest.php | 14 ++-- 4 files changed, 47 insertions(+), 61 deletions(-) diff --git a/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php b/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php index 14595e8cf..9841ac9fc 100644 --- a/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php +++ b/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php @@ -88,7 +88,7 @@ public function testFieldConstraintsInvalidateFormIfFieldIsSubmitted() public function testNonCompositeConstraintValidatedOnce() { $form = $this->formFactory->create(TextType::class, null, [ - 'constraints' => [new NotBlank(['groups' => ['foo', 'bar']])], + 'constraints' => [new NotBlank(groups: ['foo', 'bar'])], 'validation_groups' => ['foo', 'bar'], ]); $form->submit(''); @@ -105,12 +105,8 @@ public function testCompositeConstraintValidatedInEachGroup() $form = $this->formFactory->create(FormType::class, null, [ 'constraints' => [ new Collection([ - 'field1' => new NotBlank([ - 'groups' => ['field1'], - ]), - 'field2' => new NotBlank([ - 'groups' => ['field2'], - ]), + 'field1' => new NotBlank(groups: ['field1']), + 'field2' => new NotBlank(groups: ['field2']), ]), ], 'validation_groups' => ['field1', 'field2'], @@ -136,12 +132,8 @@ public function testCompositeConstraintValidatedInSequence() $form = $this->formFactory->create(FormType::class, null, [ 'constraints' => [ new Collection([ - 'field1' => new NotBlank([ - 'groups' => ['field1'], - ]), - 'field2' => new NotBlank([ - 'groups' => ['field2'], - ]), + 'field1' => new NotBlank(groups: ['field1']), + 'field2' => new NotBlank(groups: ['field2']), ]), ], 'validation_groups' => new GroupSequence(['field1', 'field2']), @@ -167,10 +159,10 @@ public function testFieldsValidateInSequence() 'validation_groups' => new GroupSequence(['group1', 'group2']), ]) ->add('foo', TextType::class, [ - 'constraints' => [new Length(['min' => 10, 'groups' => ['group1']])], + 'constraints' => [new Length(min: 10, groups: ['group1'])], ]) ->add('bar', TextType::class, [ - 'constraints' => [new NotBlank(['groups' => ['group2']])], + 'constraints' => [new NotBlank(groups: ['group2'])], ]) ; @@ -188,13 +180,13 @@ public function testFieldsValidateInSequenceWithNestedGroupsArray() 'validation_groups' => new GroupSequence([['group1', 'group2'], 'group3']), ]) ->add('foo', TextType::class, [ - 'constraints' => [new Length(['min' => 10, 'groups' => ['group1']])], + 'constraints' => [new Length(min: 10, groups: ['group1'])], ]) ->add('bar', TextType::class, [ - 'constraints' => [new Length(['min' => 10, 'groups' => ['group2']])], + 'constraints' => [new Length(min: 10, groups: ['group2'])], ]) ->add('baz', TextType::class, [ - 'constraints' => [new NotBlank(['groups' => ['group3']])], + 'constraints' => [new NotBlank(groups: ['group3'])], ]) ; @@ -214,13 +206,11 @@ public function testConstraintsInDifferentGroupsOnSingleField() ]) ->add('foo', TextType::class, [ 'constraints' => [ - new NotBlank([ - 'groups' => ['group1'], - ]), - new Length([ - 'groups' => ['group2'], - 'max' => 3, - ]), + new NotBlank(groups: ['group1']), + new Length( + groups: ['group2'], + max: 3, + ), ], ]); $form->submit([ @@ -242,13 +232,11 @@ public function testConstraintsInDifferentGroupsOnSingleFieldWithAdditionalField ->add('bar') ->add('foo', TextType::class, [ 'constraints' => [ - new NotBlank([ - 'groups' => ['group1'], - ]), - new Length([ - 'groups' => ['group2'], - 'max' => 3, - ]), + new NotBlank(groups: ['group1']), + new Length( + groups: ['group2'], + max: 3, + ), ], ]); $form->submit([ @@ -268,11 +256,11 @@ public function testCascadeValidationToChildFormsUsingPropertyPaths() 'validation_groups' => ['group1', 'group2'], ]) ->add('field1', null, [ - 'constraints' => [new NotBlank(['groups' => 'group1'])], + 'constraints' => [new NotBlank(groups: ['group1'])], 'property_path' => '[foo]', ]) ->add('field2', null, [ - 'constraints' => [new NotBlank(['groups' => 'group2'])], + 'constraints' => [new NotBlank(groups: ['group2'])], 'property_path' => '[bar]', ]) ; @@ -359,11 +347,11 @@ public function testCascadeValidationToChildFormsUsingPropertyPathsValidatedInSe 'validation_groups' => new GroupSequence(['group1', 'group2']), ]) ->add('field1', null, [ - 'constraints' => [new NotBlank(['groups' => 'group1'])], + 'constraints' => [new NotBlank(groups: ['group1'])], 'property_path' => '[foo]', ]) ->add('field2', null, [ - 'constraints' => [new NotBlank(['groups' => 'group2'])], + 'constraints' => [new NotBlank(groups: ['group2'])], 'property_path' => '[bar]', ]) ; @@ -384,9 +372,7 @@ public function testContextIsPopulatedWithFormBeingValidated() { $form = $this->formFactory->create(FormType::class) ->add('field1', null, [ - 'constraints' => [new Expression([ - 'expression' => '!this.getParent().get("field2").getData()', - ])], + 'constraints' => [new Expression(expression: '!this.getParent().get("field2").getData()')], ]) ->add('field2') ; @@ -407,10 +393,10 @@ public function testContextIsPopulatedWithFormBeingValidatedUsingGroupSequence() 'validation_groups' => new GroupSequence(['group1']), ]) ->add('field1', null, [ - 'constraints' => [new Expression([ - 'expression' => '!this.getParent().get("field2").getData()', - 'groups' => ['group1'], - ])], + 'constraints' => [new Expression( + expression: '!this.getParent().get("field2").getData()', + groups: ['group1'], + )], ]) ->add('field2') ; diff --git a/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/Tests/Extension/Validator/Constraints/FormValidatorTest.php index 86b53ac3a..b438c0d8f 100644 --- a/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -70,9 +70,9 @@ public function testValidate() public function testValidateConstraints() { $object = new \stdClass(); - $constraint1 = new NotNull(['groups' => ['group1', 'group2']]); - $constraint2 = new NotBlank(['groups' => 'group2']); - $constraint3 = new Length(['groups' => 'group2', 'min' => 3]); + $constraint1 = new NotNull(groups: ['group1', 'group2']); + $constraint2 = new NotBlank(groups: ['group2']); + $constraint3 = new Length(groups: ['group2'], min: 3); $options = [ 'validation_groups' => ['group1', 'group2'], @@ -156,8 +156,8 @@ public function testMissingConstraintIndex() public function testValidateConstraintsOptionEvenIfNoValidConstraint() { $object = new \stdClass(); - $constraint1 = new NotNull(['groups' => ['group1', 'group2']]); - $constraint2 = new NotBlank(['groups' => 'group2']); + $constraint1 = new NotNull(groups: ['group1', 'group2']); + $constraint2 = new NotBlank(groups: ['group2']); $parent = $this->getBuilder('parent', null) ->setCompound(true) @@ -684,7 +684,7 @@ public function getValidationGroups(FormInterface $form) public function testCauseForNotAllowedExtraFieldsIsTheFormConstraint() { $form = $this - ->getBuilder('form', null, ['constraints' => [new NotBlank(['groups' => ['foo']])]]) + ->getBuilder('form', null, ['constraints' => [new NotBlank(groups: ['foo'])]]) ->setCompound(true) ->setDataMapper(new DataMapper()) ->getForm(); diff --git a/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php b/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php index a1d1a3840..2dec87b5c 100644 --- a/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php +++ b/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php @@ -84,8 +84,8 @@ public function testGroupSequenceWithConstraintsOption() ->create(FormTypeTest::TESTED_TYPE, null, ['validation_groups' => new GroupSequence(['First', 'Second'])]) ->add('field', TextTypeTest::TESTED_TYPE, [ 'constraints' => [ - new Length(['min' => 10, 'groups' => ['First']]), - new NotBlank(['groups' => ['Second']]), + new Length(min: 10, groups: ['First']), + new NotBlank(groups: ['Second']), ], ]) ; @@ -102,7 +102,7 @@ public function testManyFieldsGroupSequenceWithConstraintsOption() { $formMetadata = new ClassMetadata(Form::class); $authorMetadata = (new ClassMetadata(Author::class)) - ->addPropertyConstraint('firstName', new NotBlank(['groups' => 'Second'])) + ->addPropertyConstraint('firstName', new NotBlank(groups: ['Second'])) ; $metadataFactory = $this->createMock(MetadataFactoryInterface::class); $metadataFactory->expects($this->any()) @@ -131,12 +131,12 @@ public function testManyFieldsGroupSequenceWithConstraintsOption() ->add('firstName', TextTypeTest::TESTED_TYPE) ->add('lastName', TextTypeTest::TESTED_TYPE, [ 'constraints' => [ - new Length(['min' => 10, 'groups' => ['First']]), + new Length(min: 10, groups: ['First']), ], ]) ->add('australian', TextTypeTest::TESTED_TYPE, [ 'constraints' => [ - new NotBlank(['groups' => ['Second']]), + new NotBlank(groups: ['Second']), ], ]) ; diff --git a/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index c561cd76f..1d0e0f872 100644 --- a/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -96,8 +96,8 @@ public static function guessRequiredProvider() [new NotNull(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)], [new NotBlank(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)], [new IsTrue(), new ValueGuess(true, Guess::HIGH_CONFIDENCE)], - [new Length(['min' => 10, 'max' => 10]), new ValueGuess(false, Guess::LOW_CONFIDENCE)], - [new Range(['min' => 1, 'max' => 20]), new ValueGuess(false, Guess::LOW_CONFIDENCE)], + [new Length(min: 10, max: 10), new ValueGuess(false, Guess::LOW_CONFIDENCE)], + [new Range(min: 1, max: 20), new ValueGuess(false, Guess::LOW_CONFIDENCE)], ]; } @@ -122,7 +122,7 @@ public function testGuessRequiredReturnsFalseForUnmappedProperties() public function testGuessMaxLengthForConstraintWithMaxValue() { - $constraint = new Length(['max' => '2']); + $constraint = new Length(max: '2'); $result = $this->guesser->guessMaxLengthForConstraint($constraint); $this->assertInstanceOf(ValueGuess::class, $result); @@ -132,7 +132,7 @@ public function testGuessMaxLengthForConstraintWithMaxValue() public function testGuessMaxLengthForConstraintWithMinValue() { - $constraint = new Length(['min' => '2']); + $constraint = new Length(min: '2'); $result = $this->guesser->guessMaxLengthForConstraint($constraint); $this->assertNull($result); @@ -141,7 +141,7 @@ public function testGuessMaxLengthForConstraintWithMinValue() public function testGuessMimeTypesForConstraintWithMimeTypesValue() { $mimeTypes = ['image/png', 'image/jpeg']; - $constraint = new File(['mimeTypes' => $mimeTypes]); + $constraint = new File(mimeTypes: $mimeTypes); $typeGuess = $this->guesser->guessTypeForConstraint($constraint); $this->assertInstanceOf(TypeGuess::class, $typeGuess); $this->assertArrayHasKey('attr', $typeGuess->getOptions()); @@ -159,7 +159,7 @@ public function testGuessMimeTypesForConstraintWithoutMimeTypesValue() public function testGuessMimeTypesForConstraintWithMimeTypesStringValue() { - $constraint = new File(['mimeTypes' => 'image/*']); + $constraint = new File(mimeTypes: 'image/*'); $typeGuess = $this->guesser->guessTypeForConstraint($constraint); $this->assertInstanceOf(TypeGuess::class, $typeGuess); $this->assertArrayHasKey('attr', $typeGuess->getOptions()); @@ -169,7 +169,7 @@ public function testGuessMimeTypesForConstraintWithMimeTypesStringValue() public function testGuessMimeTypesForConstraintWithMimeTypesEmptyStringValue() { - $constraint = new File(['mimeTypes' => '']); + $constraint = new File(mimeTypes: ''); $typeGuess = $this->guesser->guessTypeForConstraint($constraint); $this->assertInstanceOf(TypeGuess::class, $typeGuess); $this->assertArrayNotHasKey('attr', $typeGuess->getOptions()); From 8547d55409bea7f6f2a866b2f178222ae1e2450a Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Thu, 27 Feb 2025 02:08:09 -0500 Subject: [PATCH 02/11] Add support for displaying nested options in DebugCommand --- CHANGELOG.md | 5 ++++ Console/Descriptor/Descriptor.php | 1 + Console/Descriptor/JsonDescriptor.php | 18 ++++++++++++++- Console/Descriptor/TextDescriptor.php | 7 ++++++ Tests/Command/DebugCommandTest.php | 2 ++ .../Descriptor/AbstractDescriptorTestCase.php | 9 ++++++++ .../default_option_with_normalizer.json | 3 ++- .../default_option_with_normalizer.txt | 2 ++ .../Descriptor/deprecated_option.json | 3 ++- .../Fixtures/Descriptor/deprecated_option.txt | 4 +++- Tests/Fixtures/Descriptor/nested_option.json | 23 +++++++++++++++++++ Tests/Fixtures/Descriptor/nested_option.txt | 21 +++++++++++++++++ ...erridden_option_with_default_closures.json | 3 ++- ...verridden_option_with_default_closures.txt | 4 +++- .../required_option_with_allowed_values.json | 3 ++- .../required_option_with_allowed_values.txt | 3 ++- composer.json | 2 +- 17 files changed, 104 insertions(+), 9 deletions(-) create mode 100644 Tests/Fixtures/Descriptor/nested_option.json create mode 100644 Tests/Fixtures/Descriptor/nested_option.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b1fabfd1..45af09033 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.3 +--- + + * Add support for displaying nested options in DebugCommand + 7.2 --- diff --git a/Console/Descriptor/Descriptor.php b/Console/Descriptor/Descriptor.php index c910acdf4..91778f819 100644 --- a/Console/Descriptor/Descriptor.php +++ b/Console/Descriptor/Descriptor.php @@ -118,6 +118,7 @@ protected function getOptionDefinition(OptionsResolver $optionsResolver, string 'allowedValues' => 'getAllowedValues', 'normalizers' => 'getNormalizers', 'deprecation' => 'getDeprecation', + 'nestedOptions' => 'getNestedOptions', ]; foreach ($map as $key => $method) { diff --git a/Console/Descriptor/JsonDescriptor.php b/Console/Descriptor/JsonDescriptor.php index 1f5c7bfa5..1eca762b7 100644 --- a/Console/Descriptor/JsonDescriptor.php +++ b/Console/Descriptor/JsonDescriptor.php @@ -62,6 +62,12 @@ protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedF } protected function describeOption(OptionsResolver $optionsResolver, array $options): void + { + $data = $this->getOptionDescription($optionsResolver, $options); + $this->writeData($data, $options); + } + + private function getOptionDescription(OptionsResolver $optionsResolver, array $options): array { $definition = $this->getOptionDefinition($optionsResolver, $options['option']); @@ -90,7 +96,17 @@ protected function describeOption(OptionsResolver $optionsResolver, array $optio } $data['has_normalizer'] = isset($definition['normalizers']); - $this->writeData($data, $options); + if ($data['has_nested_options'] = isset($definition['nestedOptions'])) { + $nestedResolver = new OptionsResolver(); + foreach ($definition['nestedOptions'] as $nestedOption) { + $nestedOption($nestedResolver, $optionsResolver); + } + foreach ($nestedResolver->getDefinedOptions() as $option) { + $data['nested_options'][$option] = $this->getOptionDescription($nestedResolver, ['option' => $option]); + } + } + + return $data; } private function writeData(array $data, array $options): void diff --git a/Console/Descriptor/TextDescriptor.php b/Console/Descriptor/TextDescriptor.php index 630b87253..e12b34262 100644 --- a/Console/Descriptor/TextDescriptor.php +++ b/Console/Descriptor/TextDescriptor.php @@ -118,12 +118,19 @@ protected function describeOption(OptionsResolver $optionsResolver, array $optio 'Allowed types' => 'allowedTypes', 'Allowed values' => 'allowedValues', 'Normalizers' => 'normalizers', + 'Nested Options' => 'nestedOptions', ]; $rows = []; foreach ($map as $label => $name) { $value = \array_key_exists($name, $definition) ? $dump($definition[$name]) : '-'; if ('default' === $name && isset($definition['lazy'])) { $value = "Value: $value\n\nClosure(s): ".$dump($definition['lazy']); + } elseif ('nestedOptions' === $name && isset($definition['nestedOptions'])) { + $nestedResolver = new OptionsResolver(); + foreach ($definition['nestedOptions'] as $nestedOption) { + $nestedOption($nestedResolver, $optionsResolver); + } + $value = $dump($nestedResolver->getDefinedOptions()); } $rows[] = ["$label", $value]; diff --git a/Tests/Command/DebugCommandTest.php b/Tests/Command/DebugCommandTest.php index 4537099c2..cac92addb 100644 --- a/Tests/Command/DebugCommandTest.php +++ b/Tests/Command/DebugCommandTest.php @@ -179,6 +179,8 @@ class:%s } %s ] %s ---------------- -----------%s + Nested Options - %s + ---------------- -----------%s TXT , $tester->getDisplay(true)); diff --git a/Tests/Console/Descriptor/AbstractDescriptorTestCase.php b/Tests/Console/Descriptor/AbstractDescriptorTestCase.php index 8a99c205c..456b433ee 100644 --- a/Tests/Console/Descriptor/AbstractDescriptorTestCase.php +++ b/Tests/Console/Descriptor/AbstractDescriptorTestCase.php @@ -130,6 +130,11 @@ public static function getDescribeOptionTestData() $options['option'] = 'bar'; $options['show_deprecated'] = true; yield [$resolvedType->getOptionsResolver(), $options, 'deprecated_option']; + + $resolvedType = new ResolvedFormType(new FooType(), [], $parent); + $options['type'] = $resolvedType->getInnerType(); + $options['option'] = 'baz'; + yield [$resolvedType->getOptionsResolver(), $options, 'nested_option']; } abstract protected function getDescriptor(); @@ -172,5 +177,9 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('foo', 'string'); $resolver->setAllowedValues('foo', ['bar', 'baz']); $resolver->setNormalizer('foo', fn (Options $options, $value) => (string) $value); + $resolver->setOptions('baz', function (OptionsResolver $baz) { + $baz->setRequired('foo'); + $baz->setDefaults(['foo' => true, 'bar' => true]); + }); } } diff --git a/Tests/Fixtures/Descriptor/default_option_with_normalizer.json b/Tests/Fixtures/Descriptor/default_option_with_normalizer.json index 0ac903a95..25b7c4525 100644 --- a/Tests/Fixtures/Descriptor/default_option_with_normalizer.json +++ b/Tests/Fixtures/Descriptor/default_option_with_normalizer.json @@ -7,5 +7,6 @@ "bool", "string" ], - "has_normalizer": true + "has_normalizer": true, + "has_nested_options": false } diff --git a/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt b/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt index 0f6f1f40e..cd41f47a8 100644 --- a/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt +++ b/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt @@ -25,4 +25,6 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (choice_translation_domain } %s ] %s ---------------- -----------%s + Nested Options - %s + ---------------- -----------%s diff --git a/Tests/Fixtures/Descriptor/deprecated_option.json b/Tests/Fixtures/Descriptor/deprecated_option.json index b3b0cf3ec..5c88933f9 100644 --- a/Tests/Fixtures/Descriptor/deprecated_option.json +++ b/Tests/Fixtures/Descriptor/deprecated_option.json @@ -2,5 +2,6 @@ "deprecated": true, "deprecation_message": "The option \"bar\" is deprecated.", "required": false, - "has_normalizer": false + "has_normalizer": false, + "has_nested_options": false } diff --git a/Tests/Fixtures/Descriptor/deprecated_option.txt b/Tests/Fixtures/Descriptor/deprecated_option.txt index 31ef796f9..f5da39c70 100644 --- a/Tests/Fixtures/Descriptor/deprecated_option.txt +++ b/Tests/Fixtures/Descriptor/deprecated_option.txt @@ -21,4 +21,6 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (bar) Allowed values - --------------------- ----------------------------------- Normalizers - - --------------------- ----------------------------------- + --------------------- ----------------------------------- + Nested Options - + --------------------- ----------------------------------- diff --git a/Tests/Fixtures/Descriptor/nested_option.json b/Tests/Fixtures/Descriptor/nested_option.json new file mode 100644 index 000000000..a6fa2a93a --- /dev/null +++ b/Tests/Fixtures/Descriptor/nested_option.json @@ -0,0 +1,23 @@ +{ + "required": false, + "default": [], + "is_lazy": false, + "has_normalizer": false, + "has_nested_options": true, + "nested_options": { + "foo": { + "required": true, + "default": true, + "is_lazy": false, + "has_normalizer": false, + "has_nested_options": false + }, + "bar": { + "required": false, + "default": true, + "is_lazy": false, + "has_normalizer": false, + "has_nested_options": false + } + } +} diff --git a/Tests/Fixtures/Descriptor/nested_option.txt b/Tests/Fixtures/Descriptor/nested_option.txt new file mode 100644 index 000000000..0f698abfc --- /dev/null +++ b/Tests/Fixtures/Descriptor/nested_option.txt @@ -0,0 +1,21 @@ +Symfony\Component\Form\Tests\Console\Descriptor\FooType (baz) +============================================================= + + ---------------- ---------- + Info - + ---------------- ---------- + Required false + ---------------- ---------- + Default [] + ---------------- ---------- + Allowed types - + ---------------- ---------- + Allowed values - + ---------------- ---------- + Normalizers - + ---------------- ---------- + Nested Options [ + "foo", + "bar" + ] + ---------------- ---------- diff --git a/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.json b/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.json index c41e377ac..bc79122e1 100644 --- a/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.json +++ b/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.json @@ -2,5 +2,6 @@ "required": false, "default": null, "is_lazy": true, - "has_normalizer": false + "has_normalizer": false, + "has_nested_options": false } diff --git a/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt b/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt index cedca25a6..8bf9cb8c8 100644 --- a/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt +++ b/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt @@ -23,6 +23,8 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (empty_data) ---------------- ----------------------%s Allowed values - %s ---------------- ----------------------%s - Normalizers - %s + Normalizers - %s + ---------------- ----------------------%s + Nested Options - %s ---------------- ----------------------%s diff --git a/Tests/Fixtures/Descriptor/required_option_with_allowed_values.json b/Tests/Fixtures/Descriptor/required_option_with_allowed_values.json index 126933c6b..5aad5becb 100644 --- a/Tests/Fixtures/Descriptor/required_option_with_allowed_values.json +++ b/Tests/Fixtures/Descriptor/required_option_with_allowed_values.json @@ -7,5 +7,6 @@ "bar", "baz" ], - "has_normalizer": true + "has_normalizer": true, + "has_nested_options": false } diff --git a/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt b/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt index fd2f8f3f1..a8371243b 100644 --- a/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt +++ b/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt @@ -27,4 +27,5 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (foo) } %s ] %s ---------------- -----------%s - + Nested Options - %s + ---------------- -----------%s diff --git a/composer.json b/composer.json index 40c021d91..f4403ba74 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/event-dispatcher": "^6.4|^7.0", - "symfony/options-resolver": "^6.4|^7.0", + "symfony/options-resolver": "^7.3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "^1.21", "symfony/polyfill-mbstring": "~1.0", From 9ec2f0b9c4467b61da71e821ee9a9ad97c7d1997 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 2 Mar 2025 16:03:52 +0100 Subject: [PATCH 03/11] replace assertEmpty() with stricter assertions --- Tests/Extension/Core/Type/ChoiceTypeTest.php | 14 +++++++------- Tests/Extension/Core/Type/ColorTypeTest.php | 4 +++- .../EventListener/CsrfValidationListenerTest.php | 7 +++++-- Tests/FormBuilderTest.php | 4 ++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Tests/Extension/Core/Type/ChoiceTypeTest.php b/Tests/Extension/Core/Type/ChoiceTypeTest.php index 28810bbc7..977a8707c 100644 --- a/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -878,7 +878,7 @@ public function testSubmitSingleExpandedRequired() $this->assertSame('b', $form->getData()); $this->assertSame('b', $form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame([], $form->getExtraData()); $this->assertTrue($form->isSynchronized()); $this->assertFalse($form[0]->getData()); @@ -906,7 +906,7 @@ public function testSubmitSingleExpandedRequiredInvalidChoice() $this->assertNull($form->getData()); $this->assertSame('foobar', $form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame([], $form->getExtraData()); $this->assertFalse($form->isSynchronized()); $this->assertFalse($form[0]->getData()); @@ -934,7 +934,7 @@ public function testSubmitSingleExpandedNonRequired() $this->assertSame('b', $form->getData()); $this->assertSame('b', $form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame([], $form->getExtraData()); $this->assertTrue($form->isSynchronized()); $this->assertFalse($form['placeholder']->getData()); @@ -964,7 +964,7 @@ public function testSubmitSingleExpandedNonRequiredInvalidChoice() $this->assertNull($form->getData()); $this->assertSame('foobar', $form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame([], $form->getExtraData()); $this->assertFalse($form->isSynchronized()); $this->assertFalse($form[0]->getData()); @@ -1348,7 +1348,7 @@ public function testSubmitMultipleExpanded() $this->assertSame(['a', 'c'], $form->getData()); $this->assertSame(['a', 'c'], $form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame([], $form->getExtraData()); $this->assertTrue($form->isSynchronized()); $this->assertTrue($form[0]->getData()); @@ -1375,7 +1375,7 @@ public function testSubmitMultipleExpandedInvalidScalarChoice() $this->assertNull($form->getData()); $this->assertSame('foobar', $form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame([], $form->getExtraData()); $this->assertFalse($form->isSynchronized()); $this->assertFalse($form[0]->getData()); @@ -1402,7 +1402,7 @@ public function testSubmitMultipleExpandedInvalidArrayChoice() $this->assertSame(['a'], $form->getData()); $this->assertSame(['a'], $form->getViewData()); - $this->assertEmpty($form->getExtraData()); + $this->assertSame([], $form->getExtraData()); $this->assertFalse($form->isValid()); $this->assertTrue($form[0]->getData()); diff --git a/Tests/Extension/Core/Type/ColorTypeTest.php b/Tests/Extension/Core/Type/ColorTypeTest.php index 52382cea2..5cfab193e 100644 --- a/Tests/Extension/Core/Type/ColorTypeTest.php +++ b/Tests/Extension/Core/Type/ColorTypeTest.php @@ -13,6 +13,7 @@ use Symfony\Component\Form\Extension\Core\Type\ColorType; use Symfony\Component\Form\FormError; +use Symfony\Component\Form\FormErrorIterator; final class ColorTypeTest extends BaseTypeTestCase { @@ -30,7 +31,8 @@ public function testValidationShouldPass(bool $html5, ?string $submittedValue) $form->submit($submittedValue); - $this->assertEmpty($form->getErrors()); + $this->assertInstanceOf(FormErrorIterator::class, $form->getErrors()); + $this->assertCount(0, $form->getErrors()); } public static function validationShouldPassProvider(): array diff --git a/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php b/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php index 6a6a8be9c..6cd4d8d93 100644 --- a/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php +++ b/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper; use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormErrorIterator; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormFactoryBuilder; use Symfony\Component\Form\FormFactoryInterface; @@ -65,7 +66,8 @@ public function testArrayCsrfToken() $validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Invalid.'); $validation->preSubmit($event); - $this->assertNotEmpty($this->form->getErrors()); + $this->assertInstanceOf(FormErrorIterator::class, $this->form->getErrors()); + $this->assertGreaterThan(0, count($this->form->getErrors())); } public function testMaxPostSizeExceeded() @@ -74,7 +76,8 @@ public function testMaxPostSizeExceeded() $validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Error message', null, null, new ServerParamsPostMaxSizeExceeded()); $validation->preSubmit($event); - $this->assertEmpty($this->form->getErrors()); + $this->assertInstanceOf(FormErrorIterator::class, $this->form->getErrors()); + $this->assertCount(0, $this->form->getErrors()); } } diff --git a/Tests/FormBuilderTest.php b/Tests/FormBuilderTest.php index 023cf77d6..9234d8775 100644 --- a/Tests/FormBuilderTest.php +++ b/Tests/FormBuilderTest.php @@ -173,8 +173,8 @@ public function testGetFormConfigErasesReferences() $children = $reflClass->getProperty('children'); $unresolvedChildren = $reflClass->getProperty('unresolvedChildren'); - $this->assertEmpty($children->getValue($config)); - $this->assertEmpty($unresolvedChildren->getValue($config)); + $this->assertSame([], $children->getValue($config)); + $this->assertSame([], $unresolvedChildren->getValue($config)); } public function testGetButtonBuilderBeforeExplicitlyResolvingAllChildren() From 7874f71565f2164d871eb617696e22f08bde67b1 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sat, 8 Mar 2025 00:16:33 +0100 Subject: [PATCH 04/11] chore: PHP CS Fixer fixes --- .../Extension/Csrf/EventListener/CsrfValidationListenerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php b/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php index 6cd4d8d93..48cbf743e 100644 --- a/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php +++ b/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php @@ -67,7 +67,7 @@ public function testArrayCsrfToken() $validation->preSubmit($event); $this->assertInstanceOf(FormErrorIterator::class, $this->form->getErrors()); - $this->assertGreaterThan(0, count($this->form->getErrors())); + $this->assertGreaterThan(0, \count($this->form->getErrors())); } public function testMaxPostSizeExceeded() From 21afef190cb8cd49b9b89191ab6d6de82a80c3e5 Mon Sep 17 00:00:00 2001 From: Steven Renaux Date: Mon, 17 Mar 2025 13:34:01 +0100 Subject: [PATCH 05/11] Allow string input --- CHANGELOG.md | 1 + .../MoneyToLocalizedStringTransformer.php | 2 +- Extension/Core/Type/MoneyType.php | 7 ++- Tests/Extension/Core/Type/MoneyTypeTest.php | 51 +++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45af09033..00d3b2fc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add support for displaying nested options in DebugCommand + * Add support for strings as data for the `MoneyType` 7.2 --- diff --git a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php index b03f8da44..e9c9cb9e5 100644 --- a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php @@ -70,7 +70,7 @@ public function reverseTransform(mixed $value): int|float|null if (null !== $value) { $value = (string) ($value * $this->divisor); - if ('float' === $this->input) { + if ('integer' !== $this->input) { return (float) $value; } diff --git a/Extension/Core/Type/MoneyType.php b/Extension/Core/Type/MoneyType.php index 2657b03af..38dbfc038 100644 --- a/Extension/Core/Type/MoneyType.php +++ b/Extension/Core/Type/MoneyType.php @@ -14,6 +14,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\MoneyToLocalizedStringTransformer; +use Symfony\Component\Form\Extension\Core\DataTransformer\StringToFloatTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; @@ -38,6 +39,10 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $options['input'], )) ; + + if ('string' === $options['input']) { + $builder->addModelTransformer(new StringToFloatTransformer($options['scale'])); + } } public function buildView(FormView $view, FormInterface $form, array $options): void @@ -77,7 +82,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('html5', 'bool'); - $resolver->setAllowedValues('input', ['float', 'integer']); + $resolver->setAllowedValues('input', ['float', 'integer', 'string']); $resolver->setNormalizer('grouping', static function (Options $options, $value) { if ($value && $options['html5']) { diff --git a/Tests/Extension/Core/Type/MoneyTypeTest.php b/Tests/Extension/Core/Type/MoneyTypeTest.php index f9112ffca..aa0d6c249 100644 --- a/Tests/Extension/Core/Type/MoneyTypeTest.php +++ b/Tests/Extension/Core/Type/MoneyTypeTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Intl\Util\IntlTestHelper; @@ -146,4 +147,54 @@ public function testIntegerInputWithoutDivisor() $this->assertSame(1234567, $form->getData()); } + + public function testDefaultFormattingWithScaleAndStringInput() + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 2, 'input' => 'string']); + $form->setData('12345.67890'); + + $this->assertSame('12345.68', $form->createView()->vars['value']); + } + + public function testStringInputWithFloatData() + { + $this->expectException(TransformationFailedException::class); + $this->expectExceptionMessage('Expected a numeric string.'); + + $this->factory->create(static::TESTED_TYPE, 12345.6789, [ + 'input' => 'string', + 'scale' => 2, + ]); + } + + public function testStringInputWithIntData() + { + $this->expectException(TransformationFailedException::class); + $this->expectExceptionMessage('Expected a numeric string.'); + + $this->factory->create(static::TESTED_TYPE, 12345, [ + 'input' => 'string', + 'scale' => 2, + ]); + } + + public function testSubmitStringInputWithDefaultScale() + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'string']); + $form->submit('1.234'); + + $this->assertSame('1.23', $form->getData()); + $this->assertSame(1.23, $form->getNormData()); + $this->assertSame('1.23', $form->getViewData()); + } + + public function testSubmitStringInputWithScale() + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'string', 'scale' => 3]); + $form->submit('1.234'); + + $this->assertSame('1.234', $form->getData()); + $this->assertSame(1.234, $form->getNormData()); + $this->assertSame('1.234', $form->getViewData()); + } } From 1b99528e2b60dbb4b630652f48bc7b1e364981bd Mon Sep 17 00:00:00 2001 From: Matthias Schmidt Date: Fri, 1 Aug 2025 05:42:01 +0200 Subject: [PATCH 06/11] [Form] Fix interface name in Guess documentation --- Guess/Guess.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Guess/Guess.php b/Guess/Guess.php index fc19ed9ce..d8394f363 100644 --- a/Guess/Guess.php +++ b/Guess/Guess.php @@ -14,7 +14,7 @@ use Symfony\Component\Form\Exception\InvalidArgumentException; /** - * Base class for guesses made by TypeGuesserInterface implementation. + * Base class for guesses made by FormTypeGuesserInterface implementation. * * Each instance contains a confidence value about the correctness of the guess. * Thus an instance with confidence HIGH_CONFIDENCE is more likely to be From 48c966216fc56418914c81c47c459de3eb9ddc95 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 4 Aug 2025 17:09:28 +0200 Subject: [PATCH 07/11] Fix inline var annotations --- Extension/Validator/ValidatorExtension.php | 2 +- ResolvedFormType.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Extension/Validator/ValidatorExtension.php b/Extension/Validator/ValidatorExtension.php index 51ba5258e..bfad8074f 100644 --- a/Extension/Validator/ValidatorExtension.php +++ b/Extension/Validator/ValidatorExtension.php @@ -36,6 +36,7 @@ public function __construct(ValidatorInterface $validator, bool $legacyErrorMess { $this->legacyErrorMessages = $legacyErrorMessages; + /** @var ClassMetadata $metadata */ $metadata = $validator->getMetadataFor(\Symfony\Component\Form\Form::class); // Register the form constraints in the validator programmatically. @@ -43,7 +44,6 @@ public function __construct(ValidatorInterface $validator, bool $legacyErrorMess // the DIC, where the XML file is loaded automatically. Thus the following // code must be kept synchronized with validation.xml - /** @var ClassMetadata $metadata */ $metadata->addConstraint(new Form()); $metadata->addConstraint(new Traverse(false)); diff --git a/ResolvedFormType.php b/ResolvedFormType.php index 84921b4f6..2b2f747c7 100644 --- a/ResolvedFormType.php +++ b/ResolvedFormType.php @@ -129,8 +129,8 @@ public function finishView(FormView $view, FormInterface $form, array $options) $this->innerType->finishView($view, $form, $options); + /** @var FormTypeExtensionInterface $extension */ foreach ($this->typeExtensions as $extension) { - /** @var FormTypeExtensionInterface $extension */ $extension->finishView($view, $form, $options); } } From 96a43da304f0c06316fa558e461a9b0ccf0e85b5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 1 Aug 2025 17:44:34 +0200 Subject: [PATCH 08/11] Fix wrong boolean values --- ...ntegerToLocalizedStringTransformerTest.php | 6 ++--- .../MoneyToLocalizedStringTransformerTest.php | 10 +++---- ...NumberToLocalizedStringTransformerTest.php | 24 ++++++++--------- ...ercentToLocalizedStringTransformerTest.php | 24 ++++++++--------- Tests/Extension/Core/Type/DateTypeTest.php | 26 +++++++++---------- Tests/Extension/Core/Type/MoneyTypeTest.php | 6 ++--- Tests/Extension/Core/Type/NumberTypeTest.php | 2 +- Tests/Extension/Core/Type/PercentTypeTest.php | 2 +- 8 files changed, 50 insertions(+), 50 deletions(-) diff --git a/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php index 513224574..92443e201 100644 --- a/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php @@ -95,7 +95,7 @@ public function testTransformWithRounding($input, $output, $roundingMode) public function testReverseTransform() { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -115,7 +115,7 @@ public function testReverseTransformEmpty() public function testReverseTransformWithGrouping() { // Since we test against "de_DE", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_DE'); @@ -210,7 +210,7 @@ public function testReverseTransformExpectsValidNumber() public function testReverseTransformExpectsInteger($number, $locale) { $this->expectException(TransformationFailedException::class); - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault($locale); diff --git a/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php index f25d49981..fe54d34cd 100644 --- a/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php @@ -36,7 +36,7 @@ protected function tearDown(): void public function testTransform() { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -71,7 +71,7 @@ public function testTransformEmpty() public function testReverseTransform() { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -99,7 +99,7 @@ public function testReverseTransformEmpty() public function testFloatToIntConversionMismatchOnReverseTransform() { $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100); - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); $this->assertSame(3655, (int) $transformer->reverseTransform('36,55')); @@ -108,7 +108,7 @@ public function testFloatToIntConversionMismatchOnReverseTransform() public function testFloatToIntConversionMismatchOnTransform() { $transformer = new MoneyToLocalizedStringTransformer(null, null, \NumberFormatter::ROUND_DOWN, 100); - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); $this->assertSame('10,20', $transformer->transform(1020)); @@ -120,7 +120,7 @@ public function testValidNumericValuesWithNonDotDecimalPointCharacter() setlocale(\LC_ALL, 'de_AT.UTF-8'); $transformer = new MoneyToLocalizedStringTransformer(4, null, null, 100); - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); $this->assertSame('0,0035', $transformer->transform(12 / 34)); diff --git a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index fbb103045..5b1dd13c3 100644 --- a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -65,7 +65,7 @@ public static function provideTransformations() public function testTransform($from, $to, $locale) { // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault($locale); @@ -91,7 +91,7 @@ public static function provideTransformationsWithGrouping() public function testTransformWithGrouping($from, $to, $locale) { // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault($locale); @@ -103,7 +103,7 @@ public function testTransformWithGrouping($from, $to, $locale) public function testTransformWithScale() { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -208,7 +208,7 @@ public static function transformWithRoundingProvider() public function testTransformWithRounding($scale, $input, $output, $roundingMode) { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -220,7 +220,7 @@ public function testTransformWithRounding($scale, $input, $output, $roundingMode public function testTransformDoesNotRoundIfNoScale() { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -235,7 +235,7 @@ public function testTransformDoesNotRoundIfNoScale() public function testReverseTransform($to, $from, $locale) { // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault($locale); @@ -265,7 +265,7 @@ public function testReverseTransformWithGrouping($to, $from, $locale) public function testReverseTransformWithGroupingAndFixedSpaces() { // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('ru'); @@ -277,7 +277,7 @@ public function testReverseTransformWithGroupingAndFixedSpaces() public function testReverseTransformWithGroupingButWithoutGroupSeparator() { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -442,7 +442,7 @@ public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDotWithNoGro public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsDotButNoGroupingUsed() { // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('fr'); $transformer = new NumberToLocalizedStringTransformer(); @@ -588,7 +588,7 @@ public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte() $this->expectException(TransformationFailedException::class); $this->expectExceptionMessage('The number contains unrecognized characters: "foo8"'); // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('ru'); @@ -602,7 +602,7 @@ public function testReverseTransformIgnoresTrailingSpacesInExceptionMessage() $this->expectException(TransformationFailedException::class); $this->expectExceptionMessage('The number contains unrecognized characters: "foo8"'); // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('ru'); @@ -625,7 +625,7 @@ public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte() $this->expectException(TransformationFailedException::class); $this->expectExceptionMessage('The number contains unrecognized characters: "foo"'); // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('ru'); diff --git a/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php index 187017396..f0c400797 100644 --- a/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php @@ -75,7 +75,7 @@ public function testTransformWithInteger() public function testTransformWithScale() { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -224,7 +224,7 @@ public function testReverseTransformWithInteger() public function testReverseTransformWithScale() { // Since we test against "de_AT", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -296,7 +296,7 @@ public function testDecimalSeparatorMayNotBeDotIfGroupingSeparatorIsDotWithNoGro public function testDecimalSeparatorMayBeDotIfGroupingSeparatorIsDotButNoGroupingUsed() { // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('fr'); $transformer = new PercentToLocalizedStringTransformer(1, 'integer', \NumberFormatter::ROUND_HALFUP); @@ -375,7 +375,7 @@ public function testReverseTransformDisallowsCenteredExtraCharactersMultibyte() $this->expectException(TransformationFailedException::class); $this->expectExceptionMessage('The number contains unrecognized characters: "foo8"'); // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('ru'); @@ -401,7 +401,7 @@ public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte() $this->expectException(TransformationFailedException::class); $this->expectExceptionMessage('The number contains unrecognized characters: "foo"'); // Since we test against other locales, we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('ru'); @@ -415,7 +415,7 @@ public function testTransformForHtml5Format() $transformer = new PercentToLocalizedStringTransformer(null, null, \NumberFormatter::ROUND_HALFUP, true); // Since we test against "de_CH", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_CH'); @@ -429,7 +429,7 @@ public function testTransformForHtml5FormatWithInteger() $transformer = new PercentToLocalizedStringTransformer(null, 'integer', \NumberFormatter::ROUND_HALFUP, true); // Since we test against "de_CH", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_CH'); @@ -440,7 +440,7 @@ public function testTransformForHtml5FormatWithInteger() public function testTransformForHtml5FormatWithScale() { // Since we test against "de_CH", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_CH'); @@ -452,7 +452,7 @@ public function testTransformForHtml5FormatWithScale() public function testReverseTransformForHtml5Format() { // Since we test against "de_CH", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_CH'); @@ -466,7 +466,7 @@ public function testReverseTransformForHtml5Format() public function testReverseTransformForHtml5FormatWithInteger() { // Since we test against "de_CH", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_CH'); @@ -481,7 +481,7 @@ public function testReverseTransformForHtml5FormatWithInteger() public function testReverseTransformForHtml5FormatWithScale() { // Since we test against "de_CH", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_CH'); @@ -546,7 +546,7 @@ class PercentToLocalizedStringTransformerWithoutGrouping extends PercentToLocali protected function getNumberFormatter(): \NumberFormatter { $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL); - $formatter->setAttribute(\NumberFormatter::GROUPING_USED, false); + $formatter->setAttribute(\NumberFormatter::GROUPING_USED, 0); return $formatter; } diff --git a/Tests/Extension/Core/Type/DateTypeTest.php b/Tests/Extension/Core/Type/DateTypeTest.php index 1be26c34d..56f9a737b 100644 --- a/Tests/Extension/Core/Type/DateTypeTest.php +++ b/Tests/Extension/Core/Type/DateTypeTest.php @@ -93,7 +93,7 @@ public function testSubmitFromSingleTextDateTimeWithCustomFormat() public function testSubmitFromSingleTextDateTime() { // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); if (\in_array(Intl::getIcuVersion(), ['71.1', '72.1'], true)) { $this->markTestSkipped('Skipping test due to a bug in ICU 71.1/72.1.'); @@ -119,7 +119,7 @@ public function testSubmitFromSingleTextDateTime() public function testSubmitFromSingleTextDateTimeImmutable() { // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); if (\in_array(Intl::getIcuVersion(), ['71.1', '72.1'], true)) { $this->markTestSkipped('Skipping test due to a bug in ICU 71.1/72.1.'); @@ -146,7 +146,7 @@ public function testSubmitFromSingleTextDateTimeImmutable() public function testSubmitFromSingleTextString() { // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); if (\in_array(Intl::getIcuVersion(), ['71.1', '72.1'], true)) { $this->markTestSkipped('Skipping test due to a bug in ICU 71.1/72.1.'); @@ -172,7 +172,7 @@ public function testSubmitFromSingleTextString() public function testSubmitFromSingleTextTimestamp() { // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); if (\in_array(Intl::getIcuVersion(), ['71.1', '72.1'], true)) { $this->markTestSkipped('Skipping test due to a bug in ICU 71.1/72.1.'); @@ -200,7 +200,7 @@ public function testSubmitFromSingleTextTimestamp() public function testSubmitFromSingleTextRaw() { // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); if (\in_array(Intl::getIcuVersion(), ['71.1', '72.1'], true)) { $this->markTestSkipped('Skipping test due to a bug in ICU 71.1/72.1.'); @@ -232,7 +232,7 @@ public function testSubmitFromSingleTextRaw() public function testArrayDateWithReferenceDoesUseReferenceTimeOnZero() { // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_DE'); @@ -505,7 +505,7 @@ public function testThrowExceptionIfDaysIsInvalid() public function testSetDataWithNegativeTimezoneOffsetStringInput() { // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_DE'); @@ -528,7 +528,7 @@ public function testSetDataWithNegativeTimezoneOffsetStringInput() public function testSetDataWithNegativeTimezoneOffsetDateTimeInput() { // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_DE'); @@ -607,7 +607,7 @@ public function testMonthsOptionShortFormat() public function testMonthsOptionLongFormat() { // we test against "de_AT", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -627,7 +627,7 @@ public function testMonthsOptionLongFormat() public function testMonthsOptionLongFormatWithDifferentTimezone() { // we test against "de_AT", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -713,7 +713,7 @@ public function testIsSynchronizedReturnsFalseIfChoiceAndDayEmpty() public function testPassDatePatternToView() { // we test against "de_AT", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -726,7 +726,7 @@ public function testPassDatePatternToView() public function testPassDatePatternToViewDifferentFormat() { // we test against "de_AT", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_AT'); @@ -774,7 +774,7 @@ public function testDontPassDatePatternIfText() public function testDatePatternFormatWithQuotedStrings() { // we test against "es_ES", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('es_ES'); diff --git a/Tests/Extension/Core/Type/MoneyTypeTest.php b/Tests/Extension/Core/Type/MoneyTypeTest.php index b00439b57..6d5521f0e 100644 --- a/Tests/Extension/Core/Type/MoneyTypeTest.php +++ b/Tests/Extension/Core/Type/MoneyTypeTest.php @@ -23,7 +23,7 @@ protected function setUp(): void { // we test against different locales, so we need the full // implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); parent::setUp(); @@ -76,7 +76,7 @@ public function testSubmitNull($expected = null, $norm = null, $view = null) public function testMoneyPatternWithoutCurrency() { - $view = $this->factory->create(static::TESTED_TYPE, null, ['currency' => false]) + $view = $this->factory->create(static::TESTED_TYPE, null, ['currency' => null]) ->createView(); $this->assertSame('{{ widget }}', $view->vars['money_pattern']); @@ -113,7 +113,7 @@ public function testDefaultFormattingWithSpecifiedRounding() public function testHtml5EnablesSpecificFormatting() { // Since we test against "de_CH", we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); \Locale::setDefault('de_CH'); diff --git a/Tests/Extension/Core/Type/NumberTypeTest.php b/Tests/Extension/Core/Type/NumberTypeTest.php index 9efe05221..132f35e4c 100644 --- a/Tests/Extension/Core/Type/NumberTypeTest.php +++ b/Tests/Extension/Core/Type/NumberTypeTest.php @@ -26,7 +26,7 @@ protected function setUp(): void parent::setUp(); // we test against "de_DE", so we need the full implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('de_DE'); diff --git a/Tests/Extension/Core/Type/PercentTypeTest.php b/Tests/Extension/Core/Type/PercentTypeTest.php index 76595d79b..f6e713c56 100644 --- a/Tests/Extension/Core/Type/PercentTypeTest.php +++ b/Tests/Extension/Core/Type/PercentTypeTest.php @@ -25,7 +25,7 @@ protected function setUp(): void { // we test against different locales, so we need the full // implementation - IntlTestHelper::requireFullIntl($this, false); + IntlTestHelper::requireFullIntl($this); parent::setUp(); From 647ea288458d3ed06d33faf21331137f5e7fb957 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 5 Aug 2025 08:55:03 +0200 Subject: [PATCH 09/11] use false instead of null to hide the currency symbol This slipped in with #61296. Technically, there shouldn't be a difference but since we explicitly mention false in the documentation let's better be safe here. --- Tests/Extension/Core/Type/MoneyTypeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Extension/Core/Type/MoneyTypeTest.php b/Tests/Extension/Core/Type/MoneyTypeTest.php index 6d5521f0e..55bc8ee33 100644 --- a/Tests/Extension/Core/Type/MoneyTypeTest.php +++ b/Tests/Extension/Core/Type/MoneyTypeTest.php @@ -76,7 +76,7 @@ public function testSubmitNull($expected = null, $norm = null, $view = null) public function testMoneyPatternWithoutCurrency() { - $view = $this->factory->create(static::TESTED_TYPE, null, ['currency' => null]) + $view = $this->factory->create(static::TESTED_TYPE, null, ['currency' => false]) ->createView(); $this->assertSame('{{ widget }}', $view->vars['money_pattern']); From bcc7d5ead107cfc901bb68b3a28b10f39a997b51 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 13 Aug 2025 11:47:18 +0200 Subject: [PATCH 10/11] Remove calls to no-op functions, deprecated in PHP 8.5 --- .../DateTimeToLocalizedStringTransformerTest.php | 4 ++-- .../NumberToLocalizedStringTransformerTest.php | 5 ++--- .../PercentToLocalizedStringTransformerTest.php | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 6cbf6b937..c3806fd67 100644 --- a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -36,7 +36,6 @@ protected function setUp(): void // Normalize intl. configuration settings. if (\extension_loaded('intl')) { $this->initialTestCaseUseException = ini_set('intl.use_exceptions', 0); - $this->initialTestCaseErrorLevel = ini_set('intl.error_level', 0); } // Since we test against "de_AT", we need the full implementation @@ -55,7 +54,6 @@ protected function tearDown(): void if (\extension_loaded('intl')) { ini_set('intl.use_exceptions', $this->initialTestCaseUseException); - ini_set('intl.error_level', $this->initialTestCaseErrorLevel); } } @@ -346,6 +344,7 @@ public function testReverseTransformFiveDigitYearsWithTimestamp() /** * @requires extension intl + * @requires PHP < 8.5 */ public function testReverseTransformWrapsIntlErrorsWithErrorLevel() { @@ -378,6 +377,7 @@ public function testReverseTransformWrapsIntlErrorsWithExceptions() /** * @requires extension intl + * @requires PHP < 8.5 */ public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel() { diff --git a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index 5b1dd13c3..f22fa5da3 100644 --- a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -21,14 +21,12 @@ class NumberToLocalizedStringTransformerTest extends TestCase private string $defaultLocale; private $initialTestCaseUseException; - private $initialTestCaseErrorLevel; protected function setUp(): void { // Normalize intl. configuration settings. if (\extension_loaded('intl')) { $this->initialTestCaseUseException = ini_set('intl.use_exceptions', 0); - $this->initialTestCaseErrorLevel = ini_set('intl.error_level', 0); } $this->defaultLocale = \Locale::getDefault(); @@ -41,7 +39,6 @@ protected function tearDown(): void if (\extension_loaded('intl')) { ini_set('intl.use_exceptions', $this->initialTestCaseUseException); - ini_set('intl.error_level', $this->initialTestCaseErrorLevel); } } @@ -664,6 +661,7 @@ public function testReverseTransformENotation($output, $input) /** * @requires extension intl + * @requires PHP < 8.5 */ public function testReverseTransformWrapsIntlErrorsWithErrorLevel() { @@ -696,6 +694,7 @@ public function testReverseTransformWrapsIntlErrorsWithExceptions() /** * @requires extension intl + * @requires PHP < 8.5 */ public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel() { diff --git a/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php index f0c400797..ca935d564 100644 --- a/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php @@ -21,14 +21,12 @@ class PercentToLocalizedStringTransformerTest extends TestCase private string $defaultLocale; private $initialTestCaseUseException; - private $initialTestCaseErrorLevel; protected function setUp(): void { // Normalize intl. configuration settings. if (\extension_loaded('intl')) { $this->initialTestCaseUseException = ini_set('intl.use_exceptions', 0); - $this->initialTestCaseErrorLevel = ini_set('intl.error_level', 0); } $this->defaultLocale = \Locale::getDefault(); @@ -41,7 +39,6 @@ protected function tearDown(): void if (\extension_loaded('intl')) { ini_set('intl.use_exceptions', $this->initialTestCaseUseException); - ini_set('intl.error_level', $this->initialTestCaseErrorLevel); } } @@ -492,6 +489,7 @@ public function testReverseTransformForHtml5FormatWithScale() /** * @requires extension intl + * @requires PHP < 8.5 */ public function testReverseTransformWrapsIntlErrorsWithErrorLevel() { @@ -524,6 +522,7 @@ public function testReverseTransformWrapsIntlErrorsWithExceptions() /** * @requires extension intl + * @requires PHP < 8.5 */ public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel() { From ce4d50b8779556a18f72e6122107b3db2f116140 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 15 Aug 2025 14:18:53 +0200 Subject: [PATCH 11/11] Remove direct access to internal properties cross-components --- Tests/Extension/Validator/ValidatorExtensionTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Extension/Validator/ValidatorExtensionTest.php b/Tests/Extension/Validator/ValidatorExtensionTest.php index c92bbe665..b721a1153 100644 --- a/Tests/Extension/Validator/ValidatorExtensionTest.php +++ b/Tests/Extension/Validator/ValidatorExtensionTest.php @@ -42,8 +42,8 @@ public function test2Dot5ValidationApi() $this->assertCount(1, $metadata->getConstraints()); $this->assertInstanceOf(FormConstraint::class, $metadata->getConstraints()[0]); - $this->assertSame(CascadingStrategy::NONE, $metadata->cascadingStrategy); - $this->assertSame(TraversalStrategy::NONE, $metadata->traversalStrategy); + $this->assertSame(CascadingStrategy::NONE, $metadata->getCascadingStrategy()); + $this->assertSame(TraversalStrategy::NONE, $metadata->getTraversalStrategy()); $this->assertCount(0, $metadata->getPropertyMetadata('children')); } }