From 96cdf7d749e86e8e28f190f59ed07eeb12253a50 Mon Sep 17 00:00:00 2001 From: MatTheCat Date: Sat, 18 Nov 2023 15:43:39 +0100 Subject: [PATCH 01/70] [Form] Deprecate not configuring the `default_protocol` option of the `UrlType` --- CHANGELOG.md | 5 +++++ Extension/Core/Type/UrlType.php | 7 ++++++- Tests/Extension/Core/Type/TextTypeTest.php | 8 ++++---- Tests/Extension/Core/Type/UrlTypeTest.php | 13 +++++++++++++ .../Type/UrlTypeValidatorExtensionTest.php | 2 +- composer.json | 1 + 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c712cc141..1a10c50f93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.1 +--- + +* Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 + 7.0 --- diff --git a/Extension/Core/Type/UrlType.php b/Extension/Core/Type/UrlType.php index d9cd3c6fb3..fd6025729a 100644 --- a/Extension/Core/Type/UrlType.php +++ b/Extension/Core/Type/UrlType.php @@ -16,6 +16,7 @@ use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class UrlType extends AbstractType @@ -38,7 +39,11 @@ public function buildView(FormView $view, FormInterface $form, array $options): public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ - 'default_protocol' => 'http', + 'default_protocol' => static function (Options $options) { + trigger_deprecation('symfony/form', '7.1', 'Not configuring the "default_protocol" option when using the UrlType is deprecated. It will default to "null" in 8.0.'); + + return 'http'; + }, 'invalid_message' => 'Please enter a valid URL.', ]); diff --git a/Tests/Extension/Core/Type/TextTypeTest.php b/Tests/Extension/Core/Type/TextTypeTest.php index e14a816362..a28dfa9afa 100644 --- a/Tests/Extension/Core/Type/TextTypeTest.php +++ b/Tests/Extension/Core/Type/TextTypeTest.php @@ -22,9 +22,9 @@ public function testSubmitNull($expected = null, $norm = null, $view = null) public function testSubmitNullReturnsNullWithEmptyDataAsString() { - $form = $this->factory->create(static::TESTED_TYPE, 'name', [ + $form = $this->factory->create(static::TESTED_TYPE, 'name', array_merge($this->getTestOptions(), [ 'empty_data' => '', - ]); + ])); $form->submit(null); $this->assertSame('', $form->getData()); @@ -48,9 +48,9 @@ public static function provideZeros(): array */ public function testSetDataThroughParamsWithZero($data, $dataAsString) { - $form = $this->factory->create(static::TESTED_TYPE, null, [ + $form = $this->factory->create(static::TESTED_TYPE, null, array_merge($this->getTestOptions(), [ 'data' => $data, - ]); + ])); $view = $form->createView(); $this->assertFalse($form->isEmpty()); diff --git a/Tests/Extension/Core/Type/UrlTypeTest.php b/Tests/Extension/Core/Type/UrlTypeTest.php index b9387d01a4..28e8b9ac74 100644 --- a/Tests/Extension/Core/Type/UrlTypeTest.php +++ b/Tests/Extension/Core/Type/UrlTypeTest.php @@ -11,14 +11,21 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; class UrlTypeTest extends TextTypeTest { + use ExpectDeprecationTrait; + public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\UrlType'; + /** + * @group legacy + */ public function testSubmitAddsDefaultProtocolIfNoneIsIncluded() { + $this->expectDeprecation('Since symfony/form 7.1: Not configuring the "default_protocol" option when using the UrlType is deprecated. It will default to "null" in 8.0.'); $form = $this->factory->create(static::TESTED_TYPE, 'name'); $form->submit('www.domain.com'); @@ -86,6 +93,7 @@ public function testThrowExceptionIfDefaultProtocolIsInvalid() public function testSubmitNullUsesDefaultEmptyData($emptyData = 'empty', $expectedData = 'http://empty') { $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'default_protocol' => 'http', 'empty_data' => $emptyData, ]); $form->submit(null); @@ -95,4 +103,9 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = 'empty', $expect $this->assertSame($expectedData, $form->getNormData()); $this->assertSame($expectedData, $form->getData()); } + + protected function getTestOptions(): array + { + return ['default_protocol' => 'http']; + } } diff --git a/Tests/Extension/Validator/Type/UrlTypeValidatorExtensionTest.php b/Tests/Extension/Validator/Type/UrlTypeValidatorExtensionTest.php index e6314a3c59..edb212cbd4 100644 --- a/Tests/Extension/Validator/Type/UrlTypeValidatorExtensionTest.php +++ b/Tests/Extension/Validator/Type/UrlTypeValidatorExtensionTest.php @@ -20,7 +20,7 @@ class UrlTypeValidatorExtensionTest extends BaseValidatorExtensionTestCase protected function createForm(array $options = []) { - return $this->factory->create(UrlType::class, null, $options); + return $this->factory->create(UrlType::class, null, $options + ['default_protocol' => 'http']); } public function testInvalidMessage() diff --git a/composer.json b/composer.json index 914ddc6c52..7ee167817f 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/event-dispatcher": "^6.4|^7.0", "symfony/options-resolver": "^6.4|^7.0", "symfony/polyfill-ctype": "~1.8", From 28fc11e86087aaf0cddcbaf7dec578b1a82f260a Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 20 Nov 2023 10:13:42 +0100 Subject: [PATCH 02/70] [Form] Add missing whitespace in Changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a10c50f93..273a71c0cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 7.1 --- -* Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 + * Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 7.0 --- From 387ece75df4e66385014c299e4a140673b843c36 Mon Sep 17 00:00:00 2001 From: Daniel Burger <48986191+danielburger1337@users.noreply.github.com> Date: Wed, 8 Nov 2023 05:54:37 +0100 Subject: [PATCH 03/70] [HttpFoundation] Add `UploadedFile::getClientOriginalPath()` to support directory uploads --- NativeRequestHandler.php | 11 ++++++----- Tests/NativeRequestHandlerTest.php | 4 ++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/NativeRequestHandler.php b/NativeRequestHandler.php index 9ac1f2ea9a..8c74bd1ded 100644 --- a/NativeRequestHandler.php +++ b/NativeRequestHandler.php @@ -29,6 +29,7 @@ class NativeRequestHandler implements RequestHandlerInterface */ private const FILE_KEYS = [ 'error', + 'full_path', 'name', 'size', 'tmp_name', @@ -186,9 +187,7 @@ private static function fixPhpFilesArray(mixed $data): mixed return $data; } - // Remove extra key added by PHP 8.1. - unset($data['full_path']); - $keys = array_keys($data); + $keys = array_keys($data + ['full_path' => null]); sort($keys); if (self::FILE_KEYS !== $keys || !isset($data['name']) || !\is_array($data['name'])) { @@ -207,7 +206,9 @@ private static function fixPhpFilesArray(mixed $data): mixed 'type' => $data['type'][$key], 'tmp_name' => $data['tmp_name'][$key], 'size' => $data['size'][$key], - ]); + ] + (isset($data['full_path'][$key]) ? [ + 'full_path' => $data['full_path'][$key], + ] : [])); } return $files; @@ -219,7 +220,7 @@ private static function stripEmptyFiles(mixed $data): mixed return $data; } - $keys = array_keys($data); + $keys = array_keys($data + ['full_path' => null]); sort($keys); if (self::FILE_KEYS === $keys) { diff --git a/Tests/NativeRequestHandlerTest.php b/Tests/NativeRequestHandlerTest.php index bdb0763f9d..679c3366d8 100644 --- a/Tests/NativeRequestHandlerTest.php +++ b/Tests/NativeRequestHandlerTest.php @@ -99,6 +99,9 @@ public function testFixBuggyFilesArray() 'name' => [ 'field' => 'upload.txt', ], + 'full_path' => [ + 'field' => 'path/to/file/upload.txt', + ], 'type' => [ 'field' => 'text/plain', ], @@ -118,6 +121,7 @@ public function testFixBuggyFilesArray() $this->assertTrue($form->isSubmitted()); $this->assertEquals([ 'name' => 'upload.txt', + 'full_path' => 'path/to/file/upload.txt', 'type' => 'text/plain', 'tmp_name' => 'owfdskjasdfsa', 'error' => \UPLOAD_ERR_OK, From 8acd03ca09abfbdd07f9d99b2231225d4afd4186 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Mon, 20 Nov 2023 19:43:22 +0100 Subject: [PATCH 04/70] [Form] Clean unused code --- .../NumberToLocalizedStringTransformer.php | 34 ++++------- .../PercentToLocalizedStringTransformer.php | 56 +++++++------------ Form.php | 7 --- FormBuilder.php | 5 -- 4 files changed, 29 insertions(+), 73 deletions(-) diff --git a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index 911246782d..0693e79797 100644 --- a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -183,35 +183,21 @@ protected function castParsedValue(int|float $value): int|float */ private function round(int|float $number): int|float { - if (null !== $this->scale && null !== $this->roundingMode) { + if (null !== $this->scale) { // shift number to maintain the correct scale during rounding $roundingCoef = 10 ** $this->scale; // string representation to avoid rounding errors, similar to bcmul() $number = (string) ($number * $roundingCoef); - switch ($this->roundingMode) { - case \NumberFormatter::ROUND_CEILING: - $number = ceil($number); - break; - case \NumberFormatter::ROUND_FLOOR: - $number = floor($number); - break; - case \NumberFormatter::ROUND_UP: - $number = $number > 0 ? ceil($number) : floor($number); - break; - case \NumberFormatter::ROUND_DOWN: - $number = $number > 0 ? floor($number) : ceil($number); - break; - case \NumberFormatter::ROUND_HALFEVEN: - $number = round($number, 0, \PHP_ROUND_HALF_EVEN); - break; - case \NumberFormatter::ROUND_HALFUP: - $number = round($number, 0, \PHP_ROUND_HALF_UP); - break; - case \NumberFormatter::ROUND_HALFDOWN: - $number = round($number, 0, \PHP_ROUND_HALF_DOWN); - break; - } + $number = match ($this->roundingMode) { + \NumberFormatter::ROUND_CEILING => ceil($number), + \NumberFormatter::ROUND_FLOOR => floor($number), + \NumberFormatter::ROUND_UP => $number > 0 ? ceil($number) : floor($number), + \NumberFormatter::ROUND_DOWN => $number > 0 ? floor($number) : ceil($number), + \NumberFormatter::ROUND_HALFEVEN => round($number, 0, \PHP_ROUND_HALF_EVEN), + \NumberFormatter::ROUND_HALFUP => round($number, 0, \PHP_ROUND_HALF_UP), + \NumberFormatter::ROUND_HALFDOWN => round($number, 0, \PHP_ROUND_HALF_DOWN), + }; $number = 1 === $roundingCoef ? (int) $number : $number / $roundingCoef; } diff --git a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php index 0915021d3b..98d62783c1 100644 --- a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php @@ -180,9 +180,7 @@ protected function getNumberFormatter(): \NumberFormatter $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->scale); - if (null !== $this->roundingMode) { - $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode); - } + $formatter->setAttribute(\NumberFormatter::ROUNDING_MODE, $this->roundingMode); return $formatter; } @@ -192,43 +190,27 @@ protected function getNumberFormatter(): \NumberFormatter */ private function round(int|float $number): int|float { - if (null !== $this->scale && null !== $this->roundingMode) { - // shift number to maintain the correct scale during rounding - $roundingCoef = 10 ** $this->scale; + // shift number to maintain the correct scale during rounding + $roundingCoef = 10 ** $this->scale; - if (self::FRACTIONAL == $this->type) { - $roundingCoef *= 100; - } + if (self::FRACTIONAL === $this->type) { + $roundingCoef *= 100; + } - // string representation to avoid rounding errors, similar to bcmul() - $number = (string) ($number * $roundingCoef); - - switch ($this->roundingMode) { - case \NumberFormatter::ROUND_CEILING: - $number = ceil($number); - break; - case \NumberFormatter::ROUND_FLOOR: - $number = floor($number); - break; - case \NumberFormatter::ROUND_UP: - $number = $number > 0 ? ceil($number) : floor($number); - break; - case \NumberFormatter::ROUND_DOWN: - $number = $number > 0 ? floor($number) : ceil($number); - break; - case \NumberFormatter::ROUND_HALFEVEN: - $number = round($number, 0, \PHP_ROUND_HALF_EVEN); - break; - case \NumberFormatter::ROUND_HALFUP: - $number = round($number, 0, \PHP_ROUND_HALF_UP); - break; - case \NumberFormatter::ROUND_HALFDOWN: - $number = round($number, 0, \PHP_ROUND_HALF_DOWN); - break; - } + // string representation to avoid rounding errors, similar to bcmul() + $number = (string) ($number * $roundingCoef); - $number = 1 === $roundingCoef ? (int) $number : $number / $roundingCoef; - } + $number = match ($this->roundingMode) { + \NumberFormatter::ROUND_CEILING => ceil($number), + \NumberFormatter::ROUND_FLOOR => floor($number), + \NumberFormatter::ROUND_UP => $number > 0 ? ceil($number) : floor($number), + \NumberFormatter::ROUND_DOWN => $number > 0 ? floor($number) : ceil($number), + \NumberFormatter::ROUND_HALFEVEN => round($number, 0, \PHP_ROUND_HALF_EVEN), + \NumberFormatter::ROUND_HALFUP => round($number, 0, \PHP_ROUND_HALF_UP), + \NumberFormatter::ROUND_HALFDOWN => round($number, 0, \PHP_ROUND_HALF_DOWN), + }; + + $number = 1 === $roundingCoef ? (int) $number : $number / $roundingCoef; return $number; } diff --git a/Form.php b/Form.php index 5c86d27b56..88c4376619 100644 --- a/Form.php +++ b/Form.php @@ -21,7 +21,6 @@ use Symfony\Component\Form\Exception\OutOfBoundsException; use Symfony\Component\Form\Exception\RuntimeException; use Symfony\Component\Form\Exception\TransformationFailedException; -use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Util\FormUtil; use Symfony\Component\Form\Util\InheritDataAwareIterator; @@ -727,12 +726,6 @@ public function add(FormInterface|string $child, string $type = null, array $opt } if (!$child instanceof FormInterface) { - if (!\is_string($child) && !\is_int($child)) { - throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormInterface'); - } - - $child = (string) $child; - // Never initialize child forms automatically $options['auto_initialize'] = false; diff --git a/FormBuilder.php b/FormBuilder.php index 33f07b0f1d..816c38810f 100644 --- a/FormBuilder.php +++ b/FormBuilder.php @@ -14,7 +14,6 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\InvalidArgumentException; -use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\Type\TextType; /** @@ -60,10 +59,6 @@ public function add(FormBuilderInterface|string $child, string $type = null, arr return $this; } - if (!\is_string($child) && !\is_int($child)) { - throw new UnexpectedTypeException($child, 'string or Symfony\Component\Form\FormBuilderInterface'); - } - // Add to "children" to maintain order $this->children[$child] = null; $this->unresolvedChildren[$child] = [$type, $options]; From e0aa685324ca461290b6fc2dc461732d423b63d6 Mon Sep 17 00:00:00 2001 From: Cristoforo Cervino Date: Tue, 13 Apr 2021 20:02:24 +0200 Subject: [PATCH 05/70] [Form] Errors Property Paths mismatch CollectionType children when removing an entry --- CHANGELOG.md | 1 + .../Core/EventListener/ResizeFormListener.php | 18 +- Extension/Core/Type/CollectionType.php | 5 +- .../Type/FormTypeValidatorExtensionTest.php | 184 ++++++++++++++++++ Tests/Fixtures/Organization.php | 32 +++ 5 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 Tests/Fixtures/Organization.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 273a71c0cd..2035e8f805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 + * Add a `keep_as_list` option to `CollectionType` 7.0 --- diff --git a/Extension/Core/EventListener/ResizeFormListener.php b/Extension/Core/EventListener/ResizeFormListener.php index 482007d53b..641f165257 100644 --- a/Extension/Core/EventListener/ResizeFormListener.php +++ b/Extension/Core/EventListener/ResizeFormListener.php @@ -31,8 +31,9 @@ class ResizeFormListener implements EventSubscriberInterface protected bool $allowDelete; private \Closure|bool $deleteEmpty; + private bool $keepAsList; - public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, bool|callable $deleteEmpty = false, array $prototypeOptions = null) + public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, bool|callable $deleteEmpty = false, array $prototypeOptions = null, bool $keepAsList = false) { $this->type = $type; $this->allowAdd = $allowAdd; @@ -40,6 +41,7 @@ public function __construct(string $type, array $options = [], bool $allowAdd = $this->options = $options; $this->deleteEmpty = \is_bool($deleteEmpty) ? $deleteEmpty : $deleteEmpty(...); $this->prototypeOptions = $prototypeOptions ?? $options; + $this->keepAsList = $keepAsList; } public static function getSubscribedEvents(): array @@ -153,6 +155,20 @@ public function onSubmit(FormEvent $event): void } } + if ($this->keepAsList) { + $formReindex = []; + foreach ($form as $name => $child) { + $formReindex[] = $child; + $form->remove($name); + } + foreach ($formReindex as $index => $child) { + $form->add($index, $this->type, array_replace([ + 'property_path' => '['.$index.']', + ], $this->options)); + } + $data = array_values($data); + } + $event->setData($data); } } diff --git a/Extension/Core/Type/CollectionType.php b/Extension/Core/Type/CollectionType.php index c9d3ec5b7c..3cef931526 100644 --- a/Extension/Core/Type/CollectionType.php +++ b/Extension/Core/Type/CollectionType.php @@ -45,7 +45,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $options['allow_add'], $options['allow_delete'], $options['delete_empty'], - $resizePrototypeOptions + $resizePrototypeOptions, + $options['keep_as_list'] ); $builder->addEventSubscriber($resizeListener); @@ -114,12 +115,14 @@ public function configureOptions(OptionsResolver $resolver): void 'prototype_options' => [], 'delete_empty' => false, 'invalid_message' => 'The collection is invalid.', + 'keep_as_list' => false, ]); $resolver->setNormalizer('entry_options', $entryOptionsNormalizer); $resolver->setAllowedTypes('delete_empty', ['bool', 'callable']); $resolver->setAllowedTypes('prototype_options', 'array'); + $resolver->setAllowedTypes('keep_as_list', ['bool']); } public function getBlockPrefix(): string diff --git a/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php b/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php index 3b4cd77396..a1d1a38402 100644 --- a/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php +++ b/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php @@ -15,9 +15,12 @@ use Symfony\Component\Form\Form; use Symfony\Component\Form\Forms; use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait; +use Symfony\Component\Form\Tests\Extension\Core\Type\CollectionTypeTest; use Symfony\Component\Form\Tests\Extension\Core\Type\FormTypeTest; use Symfony\Component\Form\Tests\Extension\Core\Type\TextTypeTest; use Symfony\Component\Form\Tests\Fixtures\Author; +use Symfony\Component\Form\Tests\Fixtures\AuthorType; +use Symfony\Component\Form\Tests\Fixtures\Organization; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\Constraints\Length; @@ -158,4 +161,185 @@ protected function createForm(array $options = []) { return $this->factory->create(FormTypeTest::TESTED_TYPE, null, $options); } + + public function testCollectionTypeKeepAsListOptionFalse() + { + $formMetadata = new ClassMetadata(Form::class); + $authorMetadata = (new ClassMetadata(Author::class)) + ->addPropertyConstraint('firstName', new NotBlank()); + $organizationMetadata = (new ClassMetadata(Organization::class)) + ->addPropertyConstraint('authors', new Valid()); + $metadataFactory = $this->createMock(MetadataFactoryInterface::class); + $metadataFactory->expects($this->any()) + ->method('getMetadataFor') + ->willReturnCallback(static function ($classOrObject) use ($formMetadata, $authorMetadata, $organizationMetadata) { + if (Author::class === $classOrObject || $classOrObject instanceof Author) { + return $authorMetadata; + } + + if (Organization::class === $classOrObject || $classOrObject instanceof Organization) { + return $organizationMetadata; + } + + if (Form::class === $classOrObject || $classOrObject instanceof Form) { + return $formMetadata; + } + + return new ClassMetadata(\is_string($classOrObject) ? $classOrObject : $classOrObject::class); + }); + + $validator = Validation::createValidatorBuilder() + ->setMetadataFactory($metadataFactory) + ->getValidator(); + + $form = Forms::createFormFactoryBuilder() + ->addExtension(new ValidatorExtension($validator)) + ->getFormFactory() + ->create(FormTypeTest::TESTED_TYPE, new Organization([]), [ + 'data_class' => Organization::class, + 'by_reference' => false, + ]) + ->add('authors', CollectionTypeTest::TESTED_TYPE, [ + 'entry_type' => AuthorType::class, + 'allow_add' => true, + 'allow_delete' => true, + 'keep_as_list' => false, + ]) + ; + + $form->submit([ + 'authors' => [ + 0 => [ + 'firstName' => '', // Fires a Not Blank Error + 'lastName' => 'lastName1', + ], + // key "1" could be missing if we add 4 blank form entries and then remove it. + 2 => [ + 'firstName' => '', // Fires a Not Blank Error + 'lastName' => 'lastName3', + ], + 3 => [ + 'firstName' => '', // Fires a Not Blank Error + 'lastName' => 'lastName3', + ], + ], + ]); + + // Form does have 3 not blank errors + $errors = $form->getErrors(true); + $this->assertCount(3, $errors); + + // Form behaves as expected. It has index 0, 2 and 3 (1 has been removed) + // But errors property paths mismatch happening with "keep_as_list" option set to false + $errorPaths = [ + $errors[0]->getCause()->getPropertyPath(), + $errors[1]->getCause()->getPropertyPath(), + $errors[2]->getCause()->getPropertyPath(), + ]; + + $this->assertTrue($form->get('authors')->has('0')); + $this->assertContains('data.authors[0].firstName', $errorPaths); + + $this->assertFalse($form->get('authors')->has('1')); + $this->assertContains('data.authors[1].firstName', $errorPaths); + + $this->assertTrue($form->get('authors')->has('2')); + $this->assertContains('data.authors[2].firstName', $errorPaths); + + $this->assertTrue($form->get('authors')->has('3')); + $this->assertNotContains('data.authors[3].firstName', $errorPaths); + + // As result, root form contain errors + $this->assertCount(1, $form->getErrors(false)); + } + + public function testCollectionTypeKeepAsListOptionTrue() + { + $formMetadata = new ClassMetadata(Form::class); + $authorMetadata = (new ClassMetadata(Author::class)) + ->addPropertyConstraint('firstName', new NotBlank()); + $organizationMetadata = (new ClassMetadata(Organization::class)) + ->addPropertyConstraint('authors', new Valid()); + $metadataFactory = $this->createMock(MetadataFactoryInterface::class); + $metadataFactory->expects($this->any()) + ->method('getMetadataFor') + ->willReturnCallback(static function ($classOrObject) use ($formMetadata, $authorMetadata, $organizationMetadata) { + if (Author::class === $classOrObject || $classOrObject instanceof Author) { + return $authorMetadata; + } + + if (Organization::class === $classOrObject || $classOrObject instanceof Organization) { + return $organizationMetadata; + } + + if (Form::class === $classOrObject || $classOrObject instanceof Form) { + return $formMetadata; + } + + return new ClassMetadata(\is_string($classOrObject) ? $classOrObject : $classOrObject::class); + }); + + $validator = Validation::createValidatorBuilder() + ->setMetadataFactory($metadataFactory) + ->getValidator(); + + $form = Forms::createFormFactoryBuilder() + ->addExtension(new ValidatorExtension($validator)) + ->getFormFactory() + ->create(FormTypeTest::TESTED_TYPE, new Organization([]), [ + 'data_class' => Organization::class, + 'by_reference' => false, + ]) + ->add('authors', CollectionTypeTest::TESTED_TYPE, [ + 'entry_type' => AuthorType::class, + 'allow_add' => true, + 'allow_delete' => true, + 'keep_as_list' => true, + ]) + ; + + $form->submit([ + 'authors' => [ + 0 => [ + 'firstName' => '', // Fires a Not Blank Error + 'lastName' => 'lastName1', + ], + // key "1" could be missing if we add 4 blank form entries and then remove it. + 2 => [ + 'firstName' => '', // Fires a Not Blank Error + 'lastName' => 'lastName3', + ], + 3 => [ + 'firstName' => '', // Fires a Not Blank Error + 'lastName' => 'lastName3', + ], + ], + ]); + + // Form does have 3 not blank errors + $errors = $form->getErrors(true); + $this->assertCount(3, $errors); + + // No property paths mismatch happening with "keep_as_list" option set to true + $errorPaths = [ + $errors[0]->getCause()->getPropertyPath(), + $errors[1]->getCause()->getPropertyPath(), + $errors[2]->getCause()->getPropertyPath(), + ]; + + $this->assertTrue($form->get('authors')->has('0')); + $this->assertContains('data.authors[0].firstName', $errorPaths); + + $this->assertTrue($form->get('authors')->has('1')); + $this->assertContains('data.authors[1].firstName', $errorPaths); + + $this->assertTrue($form->get('authors')->has('2')); + $this->assertContains('data.authors[2].firstName', $errorPaths); + + $this->assertFalse($form->get('authors')->has('3')); + $this->assertNotContains('data.authors[3].firstName', $errorPaths); + + // Root form does NOT contain errors + $this->assertCount(0, $form->getErrors(false)); + } } diff --git a/Tests/Fixtures/Organization.php b/Tests/Fixtures/Organization.php new file mode 100644 index 0000000000..db9cee9f96 --- /dev/null +++ b/Tests/Fixtures/Organization.php @@ -0,0 +1,32 @@ +authors = $authors; + } + + public function getAuthors(): array + { + return $this->authors; + } + + public function addAuthor(Author $author): self + { + $this->authors[] = $author; + return $this; + } + + public function removeAuthor(Author $author): self + { + if (false !== $key = array_search($author, $this->authors, true)) { + array_splice($this->authors, $key, 1); + } + return $this; + } +} From b7cb324fdb411a26e5dec51c5063f627189defaa Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 14 Dec 2023 11:03:37 +0100 Subject: [PATCH 06/70] Set `strict` parameter of `in_array` to true where possible --- Extension/Validator/Constraints/FormValidator.php | 2 +- Test/TypeTestCase.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Extension/Validator/Constraints/FormValidator.php b/Extension/Validator/Constraints/FormValidator.php index 4a05981a86..4163587576 100644 --- a/Extension/Validator/Constraints/FormValidator.php +++ b/Extension/Validator/Constraints/FormValidator.php @@ -120,7 +120,7 @@ public function validate(mixed $form, Constraint $formConstraint): void // Otherwise validate a constraint only once for the first // matching group foreach ($groups as $group) { - if (\in_array($group, $constraint->groups)) { + if (\in_array($group, $constraint->groups, true)) { $groupedConstraints[$group][] = $constraint; // Prevent duplicate validation diff --git a/Test/TypeTestCase.php b/Test/TypeTestCase.php index 5d4c2ba9c6..960b44228b 100644 --- a/Test/TypeTestCase.php +++ b/Test/TypeTestCase.php @@ -32,7 +32,7 @@ protected function getExtensions() { $extensions = []; - if (\in_array(ValidatorExtensionTrait::class, class_uses($this))) { + if (\in_array(ValidatorExtensionTrait::class, class_uses($this), true)) { $extensions[] = $this->getValidatorExtension(); } From a55a75f0c1576663c436c180a6037da71a845057 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 18 Dec 2023 08:46:12 +0100 Subject: [PATCH 07/70] Code updates --- Console/Descriptor/Descriptor.php | 2 +- Extension/Core/Type/ChoiceType.php | 2 +- Util/OrderedHashMapIterator.php | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Console/Descriptor/Descriptor.php b/Console/Descriptor/Descriptor.php index b8d0399ee1..f4835fb1ee 100644 --- a/Console/Descriptor/Descriptor.php +++ b/Console/Descriptor/Descriptor.php @@ -128,7 +128,7 @@ protected function getOptionDefinition(OptionsResolver $optionsResolver, string } } - if (isset($definition['deprecation']) && isset($definition['deprecation']['message']) && \is_string($definition['deprecation']['message'])) { + if (isset($definition['deprecation']['message']) && \is_string($definition['deprecation']['message'])) { $definition['deprecationMessage'] = strtr($definition['deprecation']['message'], ['%name%' => $option]); $definition['deprecationPackage'] = $definition['deprecation']['package']; $definition['deprecationVersion'] = $definition['deprecation']['version']; diff --git a/Extension/Core/Type/ChoiceType.php b/Extension/Core/Type/ChoiceType.php index 0030a835ff..8cdf89e511 100644 --- a/Extension/Core/Type/ChoiceType.php +++ b/Extension/Core/Type/ChoiceType.php @@ -437,7 +437,7 @@ private function createChoiceList(array $options): ChoiceListInterface } // Harden against NULL values (like in EntityType and ModelType) - $choices = null !== $options['choices'] ? $options['choices'] : []; + $choices = $options['choices'] ?? []; return $this->choiceListFactory->createListFromChoices( $choices, diff --git a/Util/OrderedHashMapIterator.php b/Util/OrderedHashMapIterator.php index a0c400e21a..4a8eebe61d 100644 --- a/Util/OrderedHashMapIterator.php +++ b/Util/OrderedHashMapIterator.php @@ -98,10 +98,6 @@ public function next(): void public function key(): mixed { - if (null === $this->key) { - return null; - } - return $this->key; } From 2e9671eb5636fd0e9e5085f2a60af8b3535be276 Mon Sep 17 00:00:00 2001 From: Massimiliano Arione Date: Sat, 7 Oct 2023 18:48:28 +0200 Subject: [PATCH 08/70] [Form] add "model_type" option to MoneyType --- CHANGELOG.md | 1 + .../MoneyToLocalizedStringTransformer.php | 7 ++++-- Extension/Core/Type/MoneyType.php | 14 ++++++++++- Tests/Extension/Core/Type/MoneyTypeTest.php | 24 +++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2035e8f805..d78622d9fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 * Add a `keep_as_list` option to `CollectionType` + * Add a new `model_type` option to `MoneyType`, to be able to cast the transformed value to `integer` 7.0 --- diff --git a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php index fd943cc820..9a768e8979 100644 --- a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php @@ -22,12 +22,14 @@ class MoneyToLocalizedStringTransformer extends NumberToLocalizedStringTransformer { private int $divisor; + private string $modelType; - public function __construct(?int $scale = 2, ?bool $grouping = true, ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, ?int $divisor = 1, string $locale = null) + public function __construct(?int $scale = 2, ?bool $grouping = true, ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, ?int $divisor = 1, string $locale = null, string $modelType = 'float') { parent::__construct($scale ?? 2, $grouping ?? true, $roundingMode, $locale); $this->divisor = $divisor ?? 1; + $this->modelType = $modelType; } /** @@ -62,7 +64,8 @@ public function reverseTransform(mixed $value): int|float|null { $value = parent::reverseTransform($value); if (null !== $value && 1 !== $this->divisor) { - $value = (float) (string) ($value * $this->divisor); + $value = (string) ($value * $this->divisor); + $value = 'integer' === $this->modelType ? (int) $value : (float) $value; } return $value; diff --git a/Extension/Core/Type/MoneyType.php b/Extension/Core/Type/MoneyType.php index c82911a216..e4d402d8d0 100644 --- a/Extension/Core/Type/MoneyType.php +++ b/Extension/Core/Type/MoneyType.php @@ -34,7 +34,8 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $options['grouping'], $options['rounding_mode'], $options['divisor'], - $options['html5'] ? 'en' : null + $options['html5'] ? 'en' : null, + $options['model_type'], )) ; } @@ -59,6 +60,7 @@ public function configureOptions(OptionsResolver $resolver): void 'compound' => false, 'html5' => false, 'invalid_message' => 'Please enter a valid money amount.', + 'model_type' => 'float', ]); $resolver->setAllowedValues('rounding_mode', [ @@ -75,6 +77,8 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('html5', 'bool'); + $resolver->setAllowedValues('model_type', ['float', 'integer']); + $resolver->setNormalizer('grouping', static function (Options $options, $value) { if ($value && $options['html5']) { throw new LogicException('Cannot use the "grouping" option when the "html5" option is enabled.'); @@ -82,6 +86,14 @@ public function configureOptions(OptionsResolver $resolver): void return $value; }); + + $resolver->setNormalizer('model_type', static function (Options $options, $value) { + if ('integer' === $value && 1 === $options['divisor']) { + throw new LogicException('When the "model_type" option is set to "integer", the "divisor" option should not be set to "1".'); + } + + return $value; + }); } public function getBlockPrefix(): string diff --git a/Tests/Extension/Core/Type/MoneyTypeTest.php b/Tests/Extension/Core/Type/MoneyTypeTest.php index b00439b574..75d0729438 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\LogicException; use Symfony\Component\Intl\Util\IntlTestHelper; class MoneyTypeTest extends BaseTypeTestCase @@ -123,4 +124,27 @@ public function testHtml5EnablesSpecificFormatting() $this->assertSame('12345.60', $form->createView()->vars['value']); $this->assertSame('number', $form->createView()->vars['type']); } + + public function testDefaultModelType() + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['divisor' => 100]); + $form->submit('12345.67'); + + $this->assertSame(1234567.0, $form->getData()); + } + + public function testIntegerModelType() + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['divisor' => 100, 'model_type' => 'integer']); + $form->submit('12345.67'); + + $this->assertSame(1234567, $form->getData()); + } + + public function testIntegerModelTypeExpectsDivisorNotEqualToOne() + { + $this->expectException(LogicException::class); + + $form = $this->factory->create(static::TESTED_TYPE, null, ['divisor' => 1, 'model_type' => 'integer']); + } } From 27b742805ea29e858259856786a657d2d7fdd429 Mon Sep 17 00:00:00 2001 From: mboultoureau Date: Fri, 3 Nov 2023 22:00:57 +0100 Subject: [PATCH 09/70] [Form] Add option `separator` to `ChoiceType` to use a custom separator after preferred choices --- CHANGELOG.md | 1 + Extension/Core/Type/ChoiceType.php | 7 ++++++- Tests/Fixtures/Descriptor/resolved_form_type_1.json | 4 +++- Tests/Fixtures/Descriptor/resolved_form_type_1.txt | 4 ++-- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 273a71c0cd..eb374a589d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 7.1 --- + * Add option `separator` to `ChoiceType` to use a custom separator after preferred choices (use the new `separator_html` option to display the separator text as HTML) * Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 7.0 diff --git a/Extension/Core/Type/ChoiceType.php b/Extension/Core/Type/ChoiceType.php index 0030a835ff..8d4584761c 100644 --- a/Extension/Core/Type/ChoiceType.php +++ b/Extension/Core/Type/ChoiceType.php @@ -234,7 +234,8 @@ public function buildView(FormView $view, FormInterface $form, array $options): 'expanded' => $options['expanded'], 'preferred_choices' => $choiceListView->preferredChoices, 'choices' => $choiceListView->choices, - 'separator' => '-------------------', + 'separator' => $options['separator'], + 'separator_html' => $options['separator_html'], 'placeholder' => null, 'placeholder_attr' => [], 'choice_translation_domain' => $choiceTranslationDomain, @@ -342,6 +343,8 @@ public function configureOptions(OptionsResolver $resolver): void 'choice_attr' => null, 'choice_translation_parameters' => [], 'preferred_choices' => [], + 'separator' => '-------------------', + 'separator_html' => false, 'duplicate_preferred_choices' => true, 'group_by' => null, 'empty_data' => $emptyData, @@ -372,6 +375,8 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('choice_translation_parameters', ['null', 'array', 'callable', ChoiceTranslationParameters::class]); $resolver->setAllowedTypes('placeholder_attr', ['array']); $resolver->setAllowedTypes('preferred_choices', ['array', \Traversable::class, 'callable', 'string', PropertyPath::class, PreferredChoice::class]); + $resolver->setAllowedTypes('separator', ['string']); + $resolver->setAllowedTypes('separator_html', ['bool']); $resolver->setAllowedTypes('duplicate_preferred_choices', 'bool'); $resolver->setAllowedTypes('group_by', ['null', 'callable', 'string', PropertyPath::class, GroupBy::class]); } diff --git a/Tests/Fixtures/Descriptor/resolved_form_type_1.json b/Tests/Fixtures/Descriptor/resolved_form_type_1.json index 27371fd6f6..e071ec712f 100644 --- a/Tests/Fixtures/Descriptor/resolved_form_type_1.json +++ b/Tests/Fixtures/Descriptor/resolved_form_type_1.json @@ -18,7 +18,9 @@ "multiple", "placeholder", "placeholder_attr", - "preferred_choices" + "preferred_choices", + "separator", + "separator_html" ], "overridden": { "Symfony\\Component\\Form\\Extension\\Core\\Type\\FormType": [ diff --git a/Tests/Fixtures/Descriptor/resolved_form_type_1.txt b/Tests/Fixtures/Descriptor/resolved_form_type_1.txt index c8aee5e783..005bfd3e96 100644 --- a/Tests/Fixtures/Descriptor/resolved_form_type_1.txt +++ b/Tests/Fixtures/Descriptor/resolved_form_type_1.txt @@ -21,8 +21,8 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice") placeholder getter placeholder_attr help preferred_choices help_attr - help_html - help_translation_parameters + separator help_html + separator_html help_translation_parameters inherit_data invalid_message_parameters is_empty_callback From 2edb77e94354996c83140b5ebb8f07934457f749 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Mon, 15 Jan 2024 20:49:54 +0100 Subject: [PATCH 10/70] CS: enable ordered_types.null_adjustment=always_last --- FormRegistry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FormRegistry.php b/FormRegistry.php index ab3f55f9fb..cf8f66b40b 100644 --- a/FormRegistry.php +++ b/FormRegistry.php @@ -33,7 +33,7 @@ class FormRegistry implements FormRegistryInterface */ private array $types = []; - private FormTypeGuesserInterface|null|false $guesser = false; + private FormTypeGuesserInterface|false|null $guesser = false; private ResolvedFormTypeFactoryInterface $resolvedTypeFactory; private array $checkedTypes = []; From 8a2b584b1c4dcba39c6779b48113e0675c0149a6 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Wed, 10 Jan 2024 17:41:00 +0100 Subject: [PATCH 11/70] [Filesystem][Finder][Form] Use CPP --- AbstractRendererEngine.php | 8 ++---- Button.php | 7 ++--- ButtonBuilder.php | 8 +++--- ChoiceList/LazyChoiceList.php | 12 ++++---- ChoiceList/View/ChoiceGroupView.php | 11 +++----- ChoiceList/View/ChoiceListView.php | 11 +++----- ChoiceList/View/ChoiceView.php | 28 +++++-------------- Command/DebugCommand.php | 24 ++++++---------- Extension/Core/CoreExtension.php | 9 +++--- Extension/Core/DataAccessor/ChainAccessor.php | 8 ++---- .../ArrayToPartsTransformer.php | 8 ++---- .../ChoiceToValueTransformer.php | 8 ++---- .../ChoicesToValuesTransformer.php | 8 ++---- .../DataTransformer/DataTransformerChain.php | 8 ++---- .../DateIntervalToArrayTransformer.php | 8 +++--- .../DateIntervalToStringTransformer.php | 8 ++---- .../DateTimeToArrayTransformer.php | 11 +++++--- .../DateTimeToLocalizedStringTransformer.php | 14 ++++++---- .../DateTimeZoneToStringTransformer.php | 8 ++---- .../IntlTimeZoneToStringTransformer.php | 8 ++---- .../MoneyToLocalizedStringTransformer.php | 12 +++++--- .../NumberToLocalizedStringTransformer.php | 13 ++++----- .../PercentToLocalizedStringTransformer.php | 12 ++++---- .../StringToFloatTransformer.php | 8 ++---- .../ValueToDuplicatesTransformer.php | 8 ++---- .../EventListener/FixUrlProtocolListener.php | 8 ++---- .../EventListener/MergeCollectionListener.php | 11 +++----- .../Core/EventListener/ResizeFormListener.php | 21 ++++++-------- .../TransformationFailureListener.php | 8 ++---- Extension/Core/Type/ColorType.php | 8 ++---- Extension/Core/Type/FileType.php | 8 ++---- .../Type/TransformationFailureExtension.php | 8 ++---- Extension/Csrf/CsrfExtension.php | 14 ++++------ .../EventListener/CsrfValidationListener.php | 22 ++++++--------- Extension/Csrf/Type/FormTypeCsrfExtension.php | 23 ++++++--------- .../DataCollector/DataCollectorExtension.php | 8 ++---- .../EventListener/DataCollectorListener.php | 8 ++---- Extension/DataCollector/FormDataCollector.php | 9 ++---- .../Proxy/ResolvedTypeDataCollectorProxy.php | 11 +++----- .../ResolvedTypeFactoryDataCollectorProxy.php | 11 +++----- .../DependencyInjectionExtension.php | 13 ++++----- .../EventListener/ValidationListener.php | 11 +++----- .../Type/FormTypeValidatorExtension.php | 11 ++++---- .../Type/UploadValidatorExtension.php | 11 +++----- Extension/Validator/ValidatorExtension.php | 19 ++++--------- Extension/Validator/ValidatorTypeGuesser.php | 8 ++---- .../Validator/ViolationMapper/MappingRule.php | 14 ++++------ .../ViolationMapper/RelativePath.php | 9 +++--- .../ViolationMapper/ViolationMapper.php | 10 +++---- Form.php | 7 ++--- FormConfigBuilder.php | 12 ++++---- FormError.php | 18 +++++------- FormErrorIterator.php | 9 +++--- FormEvent.php | 12 +++----- FormFactory.php | 8 ++---- FormFactoryBuilder.php | 8 ++---- FormRegistry.php | 8 +++--- FormRenderer.php | 10 +++---- FormView.php | 14 ++++------ Guess/TypeGuess.php | 13 ++++----- Guess/ValueGuess.php | 10 +++---- PreloadedExtension.php | 12 ++++---- ResolvedFormType.php | 13 ++++----- ReversedTransformer.php | 8 ++---- Util/OrderedHashMap.php | 15 +++------- Util/OrderedHashMapIterator.php | 16 ++++------- Util/ServerParams.php | 8 ++---- 67 files changed, 299 insertions(+), 454 deletions(-) diff --git a/AbstractRendererEngine.php b/AbstractRendererEngine.php index bccdf69cc5..1968f5a376 100644 --- a/AbstractRendererEngine.php +++ b/AbstractRendererEngine.php @@ -25,8 +25,6 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re */ public const CACHE_KEY_VAR = 'cache_key'; - protected array $defaultThemes; - /** * @var array[] */ @@ -53,9 +51,9 @@ abstract class AbstractRendererEngine implements FormRendererEngineInterface, Re * @param array $defaultThemes The default themes. The type of these * themes is open to the implementation. */ - public function __construct(array $defaultThemes = []) - { - $this->defaultThemes = $defaultThemes; + public function __construct( + protected array $defaultThemes = [], + ) { } public function setTheme(FormView $view, mixed $themes, bool $useDefaultThemes = true): void diff --git a/Button.php b/Button.php index 67772ccfe1..ef0ee1f9c4 100644 --- a/Button.php +++ b/Button.php @@ -26,15 +26,14 @@ class Button implements \IteratorAggregate, FormInterface { private ?FormInterface $parent = null; - private FormConfigInterface $config; private bool $submitted = false; /** * Creates a new button from a form configuration. */ - public function __construct(FormConfigInterface $config) - { - $this->config = $config; + public function __construct( + private FormConfigInterface $config, + ) { } /** diff --git a/ButtonBuilder.php b/ButtonBuilder.php index e640149bb8..269412f639 100644 --- a/ButtonBuilder.php +++ b/ButtonBuilder.php @@ -31,19 +31,19 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface private ResolvedFormTypeInterface $type; private string $name; private array $attributes = []; - private array $options; /** * @throws InvalidArgumentException if the name is empty */ - public function __construct(?string $name, array $options = []) - { + public function __construct( + ?string $name, + private array $options = [], + ) { if ('' === $name || null === $name) { throw new InvalidArgumentException('Buttons cannot have empty names.'); } $this->name = $name; - $this->options = $options; FormConfigBuilder::validateName($name); } diff --git a/ChoiceList/LazyChoiceList.php b/ChoiceList/LazyChoiceList.php index b34d3708ab..28f0a2a450 100644 --- a/ChoiceList/LazyChoiceList.php +++ b/ChoiceList/LazyChoiceList.php @@ -27,8 +27,6 @@ */ class LazyChoiceList implements ChoiceListInterface { - private ChoiceLoaderInterface $loader; - /** * The callable creating string values for each choice. * @@ -43,11 +41,13 @@ class LazyChoiceList implements ChoiceListInterface * The callable receives the choice as first and the array key as the second * argument. * - * @param callable|null $value The callable generating the choice values + * @param callable|null $value The callable creating string values for each choice. + * If null, choices are cast to strings. */ - public function __construct(ChoiceLoaderInterface $loader, callable $value = null) - { - $this->loader = $loader; + public function __construct( + private ChoiceLoaderInterface $loader, + callable $value = null, + ) { $this->value = null === $value ? null : $value(...); } diff --git a/ChoiceList/View/ChoiceGroupView.php b/ChoiceList/View/ChoiceGroupView.php index 562515012c..923fab2241 100644 --- a/ChoiceList/View/ChoiceGroupView.php +++ b/ChoiceList/View/ChoiceGroupView.php @@ -20,18 +20,15 @@ */ class ChoiceGroupView implements \IteratorAggregate { - public string $label; - public array $choices; - /** * Creates a new choice group view. * * @param array $choices the choice views in the group */ - public function __construct(string $label, array $choices = []) - { - $this->label = $label; - $this->choices = $choices; + public function __construct( + public string $label, + public array $choices = [], + ) { } /** diff --git a/ChoiceList/View/ChoiceListView.php b/ChoiceList/View/ChoiceListView.php index 15afc4a8a5..f64d10e761 100644 --- a/ChoiceList/View/ChoiceListView.php +++ b/ChoiceList/View/ChoiceListView.php @@ -22,19 +22,16 @@ */ class ChoiceListView { - public array $choices; - public array $preferredChoices; - /** * Creates a new choice list view. * * @param array $choices The choice views * @param array $preferredChoices the preferred choice views */ - public function __construct(array $choices = [], array $preferredChoices = []) - { - $this->choices = $choices; - $this->preferredChoices = $preferredChoices; + public function __construct( + public array $choices = [], + public array $preferredChoices = [], + ) { } /** diff --git a/ChoiceList/View/ChoiceView.php b/ChoiceList/View/ChoiceView.php index 52587fd363..d59a7c947b 100644 --- a/ChoiceList/View/ChoiceView.php +++ b/ChoiceList/View/ChoiceView.php @@ -20,20 +20,6 @@ */ class ChoiceView { - public string|TranslatableInterface|false $label; - public string $value; - public mixed $data; - - /** - * Additional attributes for the HTML tag. - */ - public array $attr; - - /** - * Additional parameters used to translate the label. - */ - public array $labelTranslationParameters; - /** * Creates a new choice view. * @@ -43,12 +29,12 @@ class ChoiceView * @param array $attr Additional attributes for the HTML tag * @param array $labelTranslationParameters Additional parameters used to translate the label */ - public function __construct(mixed $data, string $value, string|TranslatableInterface|false $label, array $attr = [], array $labelTranslationParameters = []) - { - $this->data = $data; - $this->value = $value; - $this->label = $label; - $this->attr = $attr; - $this->labelTranslationParameters = $labelTranslationParameters; + public function __construct( + public mixed $data, + public string $value, + public string|TranslatableInterface|false $label, + public array $attr = [], + public array $labelTranslationParameters = [], + ) { } } diff --git a/Command/DebugCommand.php b/Command/DebugCommand.php index a208be3e5b..4d99012298 100644 --- a/Command/DebugCommand.php +++ b/Command/DebugCommand.php @@ -35,23 +35,15 @@ #[AsCommand(name: 'debug:form', description: 'Display form type information')] class DebugCommand extends Command { - private FormRegistryInterface $formRegistry; - private array $namespaces; - private array $types; - private array $extensions; - private array $guessers; - private ?FileLinkFormatter $fileLinkFormatter; - - public function __construct(FormRegistryInterface $formRegistry, array $namespaces = ['Symfony\Component\Form\Extension\Core\Type'], array $types = [], array $extensions = [], array $guessers = [], FileLinkFormatter $fileLinkFormatter = null) - { + public function __construct( + private FormRegistryInterface $formRegistry, + private array $namespaces = ['Symfony\Component\Form\Extension\Core\Type'], + private array $types = [], + private array $extensions = [], + private array $guessers = [], + private ?FileLinkFormatter $fileLinkFormatter = null, + ) { parent::__construct(); - - $this->formRegistry = $formRegistry; - $this->namespaces = $namespaces; - $this->types = $types; - $this->extensions = $extensions; - $this->guessers = $guessers; - $this->fileLinkFormatter = $fileLinkFormatter; } protected function configure(): void diff --git a/Extension/Core/CoreExtension.php b/Extension/Core/CoreExtension.php index 951bf345c0..f9b7cc1394 100644 --- a/Extension/Core/CoreExtension.php +++ b/Extension/Core/CoreExtension.php @@ -30,13 +30,14 @@ class CoreExtension extends AbstractExtension { private PropertyAccessorInterface $propertyAccessor; private ChoiceListFactoryInterface $choiceListFactory; - private ?TranslatorInterface $translator; - public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null, TranslatorInterface $translator = null) - { + public function __construct( + PropertyAccessorInterface $propertyAccessor = null, + ChoiceListFactoryInterface $choiceListFactory = null, + private ?TranslatorInterface $translator = null, + ) { $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); $this->choiceListFactory = $choiceListFactory ?? new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor)); - $this->translator = $translator; } protected function loadTypes(): array diff --git a/Extension/Core/DataAccessor/ChainAccessor.php b/Extension/Core/DataAccessor/ChainAccessor.php index ac600f16f0..e7b9da09ea 100644 --- a/Extension/Core/DataAccessor/ChainAccessor.php +++ b/Extension/Core/DataAccessor/ChainAccessor.php @@ -20,14 +20,12 @@ */ class ChainAccessor implements DataAccessorInterface { - private iterable $accessors; - /** * @param DataAccessorInterface[]|iterable $accessors */ - public function __construct(iterable $accessors) - { - $this->accessors = $accessors; + public function __construct( + private iterable $accessors, + ) { } public function getValue(object|array $data, FormInterface $form): mixed diff --git a/Extension/Core/DataTransformer/ArrayToPartsTransformer.php b/Extension/Core/DataTransformer/ArrayToPartsTransformer.php index 9256c0a094..828bd811e5 100644 --- a/Extension/Core/DataTransformer/ArrayToPartsTransformer.php +++ b/Extension/Core/DataTransformer/ArrayToPartsTransformer.php @@ -21,11 +21,9 @@ */ class ArrayToPartsTransformer implements DataTransformerInterface { - private array $partMapping; - - public function __construct(array $partMapping) - { - $this->partMapping = $partMapping; + public function __construct( + private array $partMapping, + ) { } public function transform(mixed $array): mixed diff --git a/Extension/Core/DataTransformer/ChoiceToValueTransformer.php b/Extension/Core/DataTransformer/ChoiceToValueTransformer.php index daec9d7195..52ee25e93e 100644 --- a/Extension/Core/DataTransformer/ChoiceToValueTransformer.php +++ b/Extension/Core/DataTransformer/ChoiceToValueTransformer.php @@ -22,11 +22,9 @@ */ class ChoiceToValueTransformer implements DataTransformerInterface { - private ChoiceListInterface $choiceList; - - public function __construct(ChoiceListInterface $choiceList) - { - $this->choiceList = $choiceList; + public function __construct( + private ChoiceListInterface $choiceList, + ) { } public function transform(mixed $choice): mixed diff --git a/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php b/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php index f284ff34f9..aa22338549 100644 --- a/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php +++ b/Extension/Core/DataTransformer/ChoicesToValuesTransformer.php @@ -22,11 +22,9 @@ */ class ChoicesToValuesTransformer implements DataTransformerInterface { - private ChoiceListInterface $choiceList; - - public function __construct(ChoiceListInterface $choiceList) - { - $this->choiceList = $choiceList; + public function __construct( + private ChoiceListInterface $choiceList, + ) { } /** diff --git a/Extension/Core/DataTransformer/DataTransformerChain.php b/Extension/Core/DataTransformer/DataTransformerChain.php index ec5def4695..e34be74556 100644 --- a/Extension/Core/DataTransformer/DataTransformerChain.php +++ b/Extension/Core/DataTransformer/DataTransformerChain.php @@ -21,16 +21,14 @@ */ class DataTransformerChain implements DataTransformerInterface { - protected array $transformers; - /** * Uses the given value transformers to transform values. * * @param DataTransformerInterface[] $transformers */ - public function __construct(array $transformers) - { - $this->transformers = $transformers; + public function __construct( + protected array $transformers, + ) { } /** diff --git a/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php b/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php index 8638e4a842..281769d2e9 100644 --- a/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php +++ b/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php @@ -42,16 +42,16 @@ class DateIntervalToArrayTransformer implements DataTransformerInterface self::INVERT => 'r', ]; private array $fields; - private bool $pad; /** * @param string[]|null $fields The date fields * @param bool $pad Whether to use padding */ - public function __construct(array $fields = null, bool $pad = false) - { + public function __construct( + array $fields = null, + private bool $pad = false, + ) { $this->fields = $fields ?? ['years', 'months', 'days', 'hours', 'minutes', 'seconds', 'invert']; - $this->pad = $pad; } /** diff --git a/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php b/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php index 4160f8f34c..e1a3d97246 100644 --- a/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php +++ b/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php @@ -24,8 +24,6 @@ */ class DateIntervalToStringTransformer implements DataTransformerInterface { - private string $format; - /** * Transforms a \DateInterval instance to a string. * @@ -33,9 +31,9 @@ class DateIntervalToStringTransformer implements DataTransformerInterface * * @param string $format The date format */ - public function __construct(string $format = 'P%yY%mM%dDT%hH%iM%sS') - { - $this->format = $format; + public function __construct( + private string $format = 'P%yY%mM%dDT%hH%iM%sS', + ) { } /** diff --git a/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php b/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php index 6675d1c24a..0596b0bcdd 100644 --- a/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php @@ -23,7 +23,6 @@ */ class DateTimeToArrayTransformer extends BaseDateTimeTransformer { - private bool $pad; private array $fields; private \DateTimeInterface $referenceDate; @@ -33,12 +32,16 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer * @param string[]|null $fields The date fields * @param bool $pad Whether to use padding */ - public function __construct(string $inputTimezone = null, string $outputTimezone = null, array $fields = null, bool $pad = false, \DateTimeInterface $referenceDate = null) - { + public function __construct( + string $inputTimezone = null, + string $outputTimezone = null, + array $fields = null, + private bool $pad = false, + \DateTimeInterface $referenceDate = null, + ) { parent::__construct($inputTimezone, $outputTimezone); $this->fields = $fields ?? ['year', 'month', 'day', 'hour', 'minute', 'second']; - $this->pad = $pad; $this->referenceDate = $referenceDate ?? new \DateTimeImmutable('1970-01-01 00:00:00'); } diff --git a/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index 22a5d41b5f..68e23071be 100644 --- a/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -26,8 +26,6 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer { private int $dateFormat; private int $timeFormat; - private ?string $pattern; - private int $calendar; /** * @see BaseDateTimeTransformer::formats for available format options @@ -41,8 +39,14 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer * * @throws UnexpectedTypeException If a format is not supported or if a timezone is not a string */ - public function __construct(string $inputTimezone = null, string $outputTimezone = null, int $dateFormat = null, int $timeFormat = null, int $calendar = \IntlDateFormatter::GREGORIAN, string $pattern = null) - { + public function __construct( + string $inputTimezone = null, + string $outputTimezone = null, + int $dateFormat = null, + int $timeFormat = null, + private int $calendar = \IntlDateFormatter::GREGORIAN, + private ?string $pattern = null, + ) { parent::__construct($inputTimezone, $outputTimezone); $dateFormat ??= \IntlDateFormatter::MEDIUM; @@ -58,8 +62,6 @@ public function __construct(string $inputTimezone = null, string $outputTimezone $this->dateFormat = $dateFormat; $this->timeFormat = $timeFormat; - $this->calendar = $calendar; - $this->pattern = $pattern; } /** diff --git a/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php b/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php index f7bda17511..50767f7a01 100644 --- a/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeZoneToStringTransformer.php @@ -23,11 +23,9 @@ */ class DateTimeZoneToStringTransformer implements DataTransformerInterface { - private bool $multiple; - - public function __construct(bool $multiple = false) - { - $this->multiple = $multiple; + public function __construct( + private bool $multiple = false, + ) { } public function transform(mixed $dateTimeZone): mixed diff --git a/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php b/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php index d379164a7a..446a95f708 100644 --- a/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php +++ b/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php @@ -23,11 +23,9 @@ */ class IntlTimeZoneToStringTransformer implements DataTransformerInterface { - private bool $multiple; - - public function __construct(bool $multiple = false) - { - $this->multiple = $multiple; + public function __construct( + private bool $multiple = false, + ) { } public function transform(mixed $intlTimeZone): mixed diff --git a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php index 9a768e8979..6f8cac989c 100644 --- a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php @@ -22,14 +22,18 @@ class MoneyToLocalizedStringTransformer extends NumberToLocalizedStringTransformer { private int $divisor; - private string $modelType; - public function __construct(?int $scale = 2, ?bool $grouping = true, ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, ?int $divisor = 1, string $locale = null, string $modelType = 'float') - { + public function __construct( + ?int $scale = 2, + ?bool $grouping = true, + ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, + ?int $divisor = 1, + string $locale = null, + private string $modelType = 'float', + ) { parent::__construct($scale ?? 2, $grouping ?? true, $roundingMode, $locale); $this->divisor = $divisor ?? 1; - $this->modelType = $modelType; } /** diff --git a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index 0693e79797..6e1c495aee 100644 --- a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -28,15 +28,14 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface protected bool $grouping; protected int $roundingMode; - private ?int $scale; - private ?string $locale; - - public function __construct(int $scale = null, ?bool $grouping = false, ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, string $locale = null) - { - $this->scale = $scale; + public function __construct( + private ?int $scale = null, + ?bool $grouping = false, + ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, + private ?string $locale = null, + ) { $this->grouping = $grouping ?? false; $this->roundingMode = $roundingMode ?? \NumberFormatter::ROUND_HALFUP; - $this->locale = $locale; } /** diff --git a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php index 98d62783c1..cb46708b22 100644 --- a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php @@ -33,10 +33,8 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface self::INTEGER, ]; - private int $roundingMode; private string $type; private int $scale; - private bool $html5Format; /** * @see self::$types for a list of supported types @@ -46,8 +44,12 @@ class PercentToLocalizedStringTransformer implements DataTransformerInterface * * @throws UnexpectedTypeException if the given value of type is unknown */ - public function __construct(int $scale = null, string $type = null, int $roundingMode = \NumberFormatter::ROUND_HALFUP, bool $html5Format = false) - { + public function __construct( + int $scale = null, + string $type = null, + private int $roundingMode = \NumberFormatter::ROUND_HALFUP, + private bool $html5Format = false, + ) { $type ??= self::FRACTIONAL; if (!\in_array($type, self::$types, true)) { @@ -56,8 +58,6 @@ public function __construct(int $scale = null, string $type = null, int $roundin $this->type = $type; $this->scale = $scale ?? 0; - $this->roundingMode = $roundingMode; - $this->html5Format = $html5Format; } /** diff --git a/Extension/Core/DataTransformer/StringToFloatTransformer.php b/Extension/Core/DataTransformer/StringToFloatTransformer.php index 09b5e51faf..f47fcb6254 100644 --- a/Extension/Core/DataTransformer/StringToFloatTransformer.php +++ b/Extension/Core/DataTransformer/StringToFloatTransformer.php @@ -19,11 +19,9 @@ */ class StringToFloatTransformer implements DataTransformerInterface { - private ?int $scale; - - public function __construct(int $scale = null) - { - $this->scale = $scale; + public function __construct( + private ?int $scale = null, + ) { } public function transform(mixed $value): ?float diff --git a/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php b/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php index 2399abf73c..9700b0424e 100644 --- a/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php +++ b/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php @@ -21,11 +21,9 @@ */ class ValueToDuplicatesTransformer implements DataTransformerInterface { - private array $keys; - - public function __construct(array $keys) - { - $this->keys = $keys; + public function __construct( + private array $keys, + ) { } /** diff --git a/Extension/Core/EventListener/FixUrlProtocolListener.php b/Extension/Core/EventListener/FixUrlProtocolListener.php index d648d6f508..97cd3ad474 100644 --- a/Extension/Core/EventListener/FixUrlProtocolListener.php +++ b/Extension/Core/EventListener/FixUrlProtocolListener.php @@ -22,14 +22,12 @@ */ class FixUrlProtocolListener implements EventSubscriberInterface { - private ?string $defaultProtocol; - /** * @param string|null $defaultProtocol The URL scheme to add when there is none or null to not modify the data */ - public function __construct(?string $defaultProtocol = 'http') - { - $this->defaultProtocol = $defaultProtocol; + public function __construct( + private ?string $defaultProtocol = 'http', + ) { } public function onSubmit(FormEvent $event): void diff --git a/Extension/Core/EventListener/MergeCollectionListener.php b/Extension/Core/EventListener/MergeCollectionListener.php index 23ee47bd2f..61428d5dfa 100644 --- a/Extension/Core/EventListener/MergeCollectionListener.php +++ b/Extension/Core/EventListener/MergeCollectionListener.php @@ -21,17 +21,14 @@ */ class MergeCollectionListener implements EventSubscriberInterface { - private bool $allowAdd; - private bool $allowDelete; - /** * @param bool $allowAdd Whether values might be added to the collection * @param bool $allowDelete Whether values might be removed from the collection */ - public function __construct(bool $allowAdd = false, bool $allowDelete = false) - { - $this->allowAdd = $allowAdd; - $this->allowDelete = $allowDelete; + public function __construct( + private bool $allowAdd = false, + private bool $allowDelete = false, + ) { } public static function getSubscribedEvents(): array diff --git a/Extension/Core/EventListener/ResizeFormListener.php b/Extension/Core/EventListener/ResizeFormListener.php index 641f165257..7e432d5af0 100644 --- a/Extension/Core/EventListener/ResizeFormListener.php +++ b/Extension/Core/EventListener/ResizeFormListener.php @@ -24,24 +24,21 @@ */ class ResizeFormListener implements EventSubscriberInterface { - protected string $type; - protected array $options; protected array $prototypeOptions; - protected bool $allowAdd; - protected bool $allowDelete; private \Closure|bool $deleteEmpty; - private bool $keepAsList; - public function __construct(string $type, array $options = [], bool $allowAdd = false, bool $allowDelete = false, bool|callable $deleteEmpty = false, array $prototypeOptions = null, bool $keepAsList = false) - { - $this->type = $type; - $this->allowAdd = $allowAdd; - $this->allowDelete = $allowDelete; - $this->options = $options; + public function __construct( + private string $type, + private array $options = [], + private bool $allowAdd = false, + private bool $allowDelete = false, + bool|callable $deleteEmpty = false, + array $prototypeOptions = null, + private bool $keepAsList = false, + ) { $this->deleteEmpty = \is_bool($deleteEmpty) ? $deleteEmpty : $deleteEmpty(...); $this->prototypeOptions = $prototypeOptions ?? $options; - $this->keepAsList = $keepAsList; } public static function getSubscribedEvents(): array diff --git a/Extension/Core/EventListener/TransformationFailureListener.php b/Extension/Core/EventListener/TransformationFailureListener.php index 570a285aae..48f0b9ac9f 100644 --- a/Extension/Core/EventListener/TransformationFailureListener.php +++ b/Extension/Core/EventListener/TransformationFailureListener.php @@ -22,11 +22,9 @@ */ class TransformationFailureListener implements EventSubscriberInterface { - private ?TranslatorInterface $translator; - - public function __construct(TranslatorInterface $translator = null) - { - $this->translator = $translator; + public function __construct( + private ?TranslatorInterface $translator = null, + ) { } public static function getSubscribedEvents(): array diff --git a/Extension/Core/Type/ColorType.php b/Extension/Core/Type/ColorType.php index 476050fbee..d67d6dc73b 100644 --- a/Extension/Core/Type/ColorType.php +++ b/Extension/Core/Type/ColorType.php @@ -26,11 +26,9 @@ class ColorType extends AbstractType */ private const HTML5_PATTERN = '/^#[0-9a-f]{6}$/i'; - private ?TranslatorInterface $translator; - - public function __construct(TranslatorInterface $translator = null) - { - $this->translator = $translator; + public function __construct( + private ?TranslatorInterface $translator = null, + ) { } public function buildForm(FormBuilderInterface $builder, array $options): void diff --git a/Extension/Core/Type/FileType.php b/Extension/Core/Type/FileType.php index 948f897f68..b4b4d86d95 100644 --- a/Extension/Core/Type/FileType.php +++ b/Extension/Core/Type/FileType.php @@ -35,11 +35,9 @@ class FileType extends AbstractType self::MIB_BYTES => 'MiB', ]; - private ?TranslatorInterface $translator; - - public function __construct(TranslatorInterface $translator = null) - { - $this->translator = $translator; + public function __construct( + private ?TranslatorInterface $translator = null, + ) { } public function buildForm(FormBuilderInterface $builder, array $options): void diff --git a/Extension/Core/Type/TransformationFailureExtension.php b/Extension/Core/Type/TransformationFailureExtension.php index 5539e57f9f..e90cd714e8 100644 --- a/Extension/Core/Type/TransformationFailureExtension.php +++ b/Extension/Core/Type/TransformationFailureExtension.php @@ -21,11 +21,9 @@ */ class TransformationFailureExtension extends AbstractTypeExtension { - private ?TranslatorInterface $translator; - - public function __construct(TranslatorInterface $translator = null) - { - $this->translator = $translator; + public function __construct( + private ?TranslatorInterface $translator = null, + ) { } public function buildForm(FormBuilderInterface $builder, array $options): void diff --git a/Extension/Csrf/CsrfExtension.php b/Extension/Csrf/CsrfExtension.php index 026bed3604..33c4616b4c 100644 --- a/Extension/Csrf/CsrfExtension.php +++ b/Extension/Csrf/CsrfExtension.php @@ -22,15 +22,11 @@ */ class CsrfExtension extends AbstractExtension { - private CsrfTokenManagerInterface $tokenManager; - private ?TranslatorInterface $translator; - private ?string $translationDomain; - - public function __construct(CsrfTokenManagerInterface $tokenManager, TranslatorInterface $translator = null, string $translationDomain = null) - { - $this->tokenManager = $tokenManager; - $this->translator = $translator; - $this->translationDomain = $translationDomain; + public function __construct( + private CsrfTokenManagerInterface $tokenManager, + private ?TranslatorInterface $translator = null, + private ?string $translationDomain = null, + ) { } protected function loadTypeExtensions(): array diff --git a/Extension/Csrf/EventListener/CsrfValidationListener.php b/Extension/Csrf/EventListener/CsrfValidationListener.php index dab31fb65f..5b018e8c8a 100644 --- a/Extension/Csrf/EventListener/CsrfValidationListener.php +++ b/Extension/Csrf/EventListener/CsrfValidationListener.php @@ -25,12 +25,6 @@ */ class CsrfValidationListener implements EventSubscriberInterface { - private string $fieldName; - private CsrfTokenManagerInterface $tokenManager; - private string $tokenId; - private string $errorMessage; - private ?TranslatorInterface $translator; - private ?string $translationDomain; private ServerParams $serverParams; public static function getSubscribedEvents(): array @@ -40,14 +34,16 @@ public static function getSubscribedEvents(): array ]; } - public function __construct(string $fieldName, CsrfTokenManagerInterface $tokenManager, string $tokenId, string $errorMessage, TranslatorInterface $translator = null, string $translationDomain = null, ServerParams $serverParams = null) + public function __construct( + private string $fieldName, + private CsrfTokenManagerInterface $tokenManager, + private string $tokenId, + private string $errorMessage, + private ?TranslatorInterface $translator = null, + private ?string $translationDomain = null, + ServerParams $serverParams = null, + ) { - $this->fieldName = $fieldName; - $this->tokenManager = $tokenManager; - $this->tokenId = $tokenId; - $this->errorMessage = $errorMessage; - $this->translator = $translator; - $this->translationDomain = $translationDomain; $this->serverParams = $serverParams ?? new ServerParams(); } diff --git a/Extension/Csrf/Type/FormTypeCsrfExtension.php b/Extension/Csrf/Type/FormTypeCsrfExtension.php index 7096b8957d..0ad4daeb3c 100644 --- a/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -28,21 +28,14 @@ */ class FormTypeCsrfExtension extends AbstractTypeExtension { - private CsrfTokenManagerInterface $defaultTokenManager; - private bool $defaultEnabled; - private string $defaultFieldName; - private ?TranslatorInterface $translator; - private ?string $translationDomain; - private ?ServerParams $serverParams; - - public function __construct(CsrfTokenManagerInterface $defaultTokenManager, bool $defaultEnabled = true, string $defaultFieldName = '_token', TranslatorInterface $translator = null, string $translationDomain = null, ServerParams $serverParams = null) - { - $this->defaultTokenManager = $defaultTokenManager; - $this->defaultEnabled = $defaultEnabled; - $this->defaultFieldName = $defaultFieldName; - $this->translator = $translator; - $this->translationDomain = $translationDomain; - $this->serverParams = $serverParams; + public function __construct( + private CsrfTokenManagerInterface $defaultTokenManager, + private bool $defaultEnabled = true, + private string $defaultFieldName = '_token', + private ?TranslatorInterface $translator = null, + private ?string $translationDomain = null, + private ?ServerParams $serverParams = null, + ) { } /** diff --git a/Extension/DataCollector/DataCollectorExtension.php b/Extension/DataCollector/DataCollectorExtension.php index 50b36bd67f..9fb8422447 100644 --- a/Extension/DataCollector/DataCollectorExtension.php +++ b/Extension/DataCollector/DataCollectorExtension.php @@ -21,11 +21,9 @@ */ class DataCollectorExtension extends AbstractExtension { - private FormDataCollectorInterface $dataCollector; - - public function __construct(FormDataCollectorInterface $dataCollector) - { - $this->dataCollector = $dataCollector; + public function __construct( + private FormDataCollectorInterface $dataCollector, + ) { } protected function loadTypeExtensions(): array diff --git a/Extension/DataCollector/EventListener/DataCollectorListener.php b/Extension/DataCollector/EventListener/DataCollectorListener.php index f32dc9bc7d..02cffbeffe 100644 --- a/Extension/DataCollector/EventListener/DataCollectorListener.php +++ b/Extension/DataCollector/EventListener/DataCollectorListener.php @@ -24,11 +24,9 @@ */ class DataCollectorListener implements EventSubscriberInterface { - private FormDataCollectorInterface $dataCollector; - - public function __construct(FormDataCollectorInterface $dataCollector) - { - $this->dataCollector = $dataCollector; + public function __construct( + private FormDataCollectorInterface $dataCollector, + ) { } public static function getSubscribedEvents(): array diff --git a/Extension/DataCollector/FormDataCollector.php b/Extension/DataCollector/FormDataCollector.php index dab72bb309..f83b7b4951 100644 --- a/Extension/DataCollector/FormDataCollector.php +++ b/Extension/DataCollector/FormDataCollector.php @@ -33,8 +33,6 @@ */ class FormDataCollector extends DataCollector implements FormDataCollectorInterface { - private FormDataExtractorInterface $dataExtractor; - /** * Stores the collected data per {@link FormInterface} instance. * @@ -62,14 +60,13 @@ class FormDataCollector extends DataCollector implements FormDataCollectorInterf */ private array $formsByView; - public function __construct(FormDataExtractorInterface $dataExtractor) - { + public function __construct( + private FormDataExtractorInterface $dataExtractor, + ) { if (!class_exists(ClassStub::class)) { throw new \LogicException(sprintf('The VarDumper component is needed for using the "%s" class. Install symfony/var-dumper version 3.4 or above.', __CLASS__)); } - $this->dataExtractor = $dataExtractor; - $this->reset(); } diff --git a/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php b/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php index 1e922ff2ea..bb16e31890 100644 --- a/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php +++ b/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php @@ -27,13 +27,10 @@ */ class ResolvedTypeDataCollectorProxy implements ResolvedFormTypeInterface { - private ResolvedFormTypeInterface $proxiedType; - private FormDataCollectorInterface $dataCollector; - - public function __construct(ResolvedFormTypeInterface $proxiedType, FormDataCollectorInterface $dataCollector) - { - $this->proxiedType = $proxiedType; - $this->dataCollector = $dataCollector; + public function __construct( + private ResolvedFormTypeInterface $proxiedType, + private FormDataCollectorInterface $dataCollector, + ) { } public function getBlockPrefix(): string diff --git a/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php b/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php index eea5bfd4ae..898c5dfa80 100644 --- a/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php +++ b/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php @@ -24,13 +24,10 @@ */ class ResolvedTypeFactoryDataCollectorProxy implements ResolvedFormTypeFactoryInterface { - private ResolvedFormTypeFactoryInterface $proxiedFactory; - private FormDataCollectorInterface $dataCollector; - - public function __construct(ResolvedFormTypeFactoryInterface $proxiedFactory, FormDataCollectorInterface $dataCollector) - { - $this->proxiedFactory = $proxiedFactory; - $this->dataCollector = $dataCollector; + public function __construct( + private ResolvedFormTypeFactoryInterface $proxiedFactory, + private FormDataCollectorInterface $dataCollector, + ) { } public function createResolvedType(FormTypeInterface $type, array $typeExtensions, ResolvedFormTypeInterface $parent = null): ResolvedFormTypeInterface diff --git a/Extension/DependencyInjection/DependencyInjectionExtension.php b/Extension/DependencyInjection/DependencyInjectionExtension.php index 6564bd5657..420f26b743 100644 --- a/Extension/DependencyInjection/DependencyInjectionExtension.php +++ b/Extension/DependencyInjection/DependencyInjectionExtension.php @@ -23,18 +23,15 @@ class DependencyInjectionExtension implements FormExtensionInterface { private ?FormTypeGuesserChain $guesser = null; private bool $guesserLoaded = false; - private ContainerInterface $typeContainer; - private array $typeExtensionServices; - private iterable $guesserServices; /** * @param array> $typeExtensionServices */ - public function __construct(ContainerInterface $typeContainer, array $typeExtensionServices, iterable $guesserServices) - { - $this->typeContainer = $typeContainer; - $this->typeExtensionServices = $typeExtensionServices; - $this->guesserServices = $guesserServices; + public function __construct( + private ContainerInterface $typeContainer, + private array $typeExtensionServices, + private iterable $guesserServices, + ) { } public function getType(string $name): FormTypeInterface diff --git a/Extension/Validator/EventListener/ValidationListener.php b/Extension/Validator/EventListener/ValidationListener.php index d24264f244..b3c16dbad2 100644 --- a/Extension/Validator/EventListener/ValidationListener.php +++ b/Extension/Validator/EventListener/ValidationListener.php @@ -23,18 +23,15 @@ */ class ValidationListener implements EventSubscriberInterface { - private ValidatorInterface $validator; - private ViolationMapperInterface $violationMapper; - public static function getSubscribedEvents(): array { return [FormEvents::POST_SUBMIT => 'validateForm']; } - public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper) - { - $this->validator = $validator; - $this->violationMapper = $violationMapper; + public function __construct( + private ValidatorInterface $validator, + private ViolationMapperInterface $violationMapper, + ) { } public function validateForm(FormEvent $event): void diff --git a/Extension/Validator/Type/FormTypeValidatorExtension.php b/Extension/Validator/Type/FormTypeValidatorExtension.php index e904a4f16e..82ee63399d 100644 --- a/Extension/Validator/Type/FormTypeValidatorExtension.php +++ b/Extension/Validator/Type/FormTypeValidatorExtension.php @@ -27,13 +27,14 @@ */ class FormTypeValidatorExtension extends BaseValidatorExtension { - private ValidatorInterface $validator; private ViolationMapper $violationMapper; - private bool $legacyErrorMessages; - public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null) - { - $this->validator = $validator; + public function __construct( + private ValidatorInterface $validator, + private bool $legacyErrorMessages = true, + FormRendererInterface $formRenderer = null, + TranslatorInterface $translator = null, + ) { $this->violationMapper = new ViolationMapper($formRenderer, $translator); } diff --git a/Extension/Validator/Type/UploadValidatorExtension.php b/Extension/Validator/Type/UploadValidatorExtension.php index 80e3315ae9..7c1e965aba 100644 --- a/Extension/Validator/Type/UploadValidatorExtension.php +++ b/Extension/Validator/Type/UploadValidatorExtension.php @@ -23,13 +23,10 @@ */ class UploadValidatorExtension extends AbstractTypeExtension { - private TranslatorInterface $translator; - private ?string $translationDomain; - - public function __construct(TranslatorInterface $translator, string $translationDomain = null) - { - $this->translator = $translator; - $this->translationDomain = $translationDomain; + public function __construct( + private TranslatorInterface $translator, + private ?string $translationDomain = null, + ) { } public function configureOptions(OptionsResolver $resolver): void diff --git a/Extension/Validator/ValidatorExtension.php b/Extension/Validator/ValidatorExtension.php index fe1bd33f5f..522a769629 100644 --- a/Extension/Validator/ValidatorExtension.php +++ b/Extension/Validator/ValidatorExtension.php @@ -27,15 +27,12 @@ */ class ValidatorExtension extends AbstractExtension { - private ValidatorInterface $validator; - private ?FormRendererInterface $formRenderer; - private ?TranslatorInterface $translator; - private bool $legacyErrorMessages; - - public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null) - { - $this->legacyErrorMessages = $legacyErrorMessages; - + public function __construct( + private ValidatorInterface $validator, + private bool $legacyErrorMessages = true, + private ?FormRendererInterface $formRenderer = null, + private ?TranslatorInterface $translator = null, + ) { $metadata = $validator->getMetadataFor(\Symfony\Component\Form\Form::class); // Register the form constraints in the validator programmatically. @@ -46,10 +43,6 @@ public function __construct(ValidatorInterface $validator, bool $legacyErrorMess /* @var $metadata ClassMetadata */ $metadata->addConstraint(new Form()); $metadata->addConstraint(new Traverse(false)); - - $this->validator = $validator; - $this->formRenderer = $formRenderer; - $this->translator = $translator; } public function loadTypeGuesser(): ?FormTypeGuesserInterface diff --git a/Extension/Validator/ValidatorTypeGuesser.php b/Extension/Validator/ValidatorTypeGuesser.php index 57bccaa39f..72ae8ddd57 100644 --- a/Extension/Validator/ValidatorTypeGuesser.php +++ b/Extension/Validator/ValidatorTypeGuesser.php @@ -57,11 +57,9 @@ class ValidatorTypeGuesser implements FormTypeGuesserInterface { - private MetadataFactoryInterface $metadataFactory; - - public function __construct(MetadataFactoryInterface $metadataFactory) - { - $this->metadataFactory = $metadataFactory; + public function __construct( + private MetadataFactoryInterface $metadataFactory, + ) { } public function guessType(string $class, string $property): ?TypeGuess diff --git a/Extension/Validator/ViolationMapper/MappingRule.php b/Extension/Validator/ViolationMapper/MappingRule.php index 6e33f22297..f9a61cc817 100644 --- a/Extension/Validator/ViolationMapper/MappingRule.php +++ b/Extension/Validator/ViolationMapper/MappingRule.php @@ -19,15 +19,11 @@ */ class MappingRule { - private FormInterface $origin; - private string $propertyPath; - private string $targetPath; - - public function __construct(FormInterface $origin, string $propertyPath, string $targetPath) - { - $this->origin = $origin; - $this->propertyPath = $propertyPath; - $this->targetPath = $targetPath; + public function __construct( + private FormInterface $origin, + private string $propertyPath, + private string $targetPath, + ) { } public function getOrigin(): FormInterface diff --git a/Extension/Validator/ViolationMapper/RelativePath.php b/Extension/Validator/ViolationMapper/RelativePath.php index 0384edb444..dbf0712e2f 100644 --- a/Extension/Validator/ViolationMapper/RelativePath.php +++ b/Extension/Validator/ViolationMapper/RelativePath.php @@ -19,13 +19,12 @@ */ class RelativePath extends PropertyPath { - private FormInterface $root; - - public function __construct(FormInterface $root, string $propertyPath) + public function __construct( + private FormInterface $root, + string $propertyPath, + ) { parent::__construct($propertyPath); - - $this->root = $root; } public function getRoot(): FormInterface diff --git a/Extension/Validator/ViolationMapper/ViolationMapper.php b/Extension/Validator/ViolationMapper/ViolationMapper.php index fca010d70e..faca255b5d 100644 --- a/Extension/Validator/ViolationMapper/ViolationMapper.php +++ b/Extension/Validator/ViolationMapper/ViolationMapper.php @@ -28,14 +28,12 @@ */ class ViolationMapper implements ViolationMapperInterface { - private ?FormRendererInterface $formRenderer; - private ?TranslatorInterface $translator; private bool $allowNonSynchronized = false; - public function __construct(FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null) - { - $this->formRenderer = $formRenderer; - $this->translator = $translator; + public function __construct( + private ?FormRendererInterface $formRenderer = null, + private ?TranslatorInterface $translator = null, + ) { } public function mapViolation(ConstraintViolation $violation, FormInterface $form, bool $allowNonSynchronized = false): void diff --git a/Form.php b/Form.php index 88c4376619..7ff939a2d8 100644 --- a/Form.php +++ b/Form.php @@ -70,7 +70,6 @@ */ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterface { - private FormConfigInterface $config; private ?FormInterface $parent = null; /** @@ -135,8 +134,9 @@ class Form implements \IteratorAggregate, FormInterface, ClearableErrorsInterfac /** * @throws LogicException if a data mapper is not provided for a compound form */ - public function __construct(FormConfigInterface $config) - { + public function __construct( + private FormConfigInterface $config, + ) { // Compound forms always need a data mapper, otherwise calls to // `setData` and `add` will not lead to the correct population of // the child forms. @@ -150,7 +150,6 @@ public function __construct(FormConfigInterface $config) $this->defaultDataSet = true; } - $this->config = $config; $this->children = new OrderedHashMap(); $this->name = $config->getName(); } diff --git a/FormConfigBuilder.php b/FormConfigBuilder.php index 49aa89ab04..e0fb01dad9 100644 --- a/FormConfigBuilder.php +++ b/FormConfigBuilder.php @@ -33,7 +33,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface */ private static NativeRequestHandler $nativeRequestHandler; - private EventDispatcherInterface $dispatcher; private string $name; private ?PropertyPathInterface $propertyPath = null; private bool $mapped = true; @@ -57,7 +56,6 @@ class FormConfigBuilder implements FormConfigBuilderInterface private string $method = 'POST'; private RequestHandlerInterface $requestHandler; private bool $autoInitialize = false; - private array $options; private ?\Closure $isEmptyCallback = null; /** @@ -69,8 +67,12 @@ class FormConfigBuilder implements FormConfigBuilderInterface * @throws InvalidArgumentException if the data class is not a valid class or if * the name contains invalid characters */ - public function __construct(?string $name, ?string $dataClass, EventDispatcherInterface $dispatcher, array $options = []) - { + public function __construct( + ?string $name, + ?string $dataClass, + private EventDispatcherInterface $dispatcher, + private array $options = [], + ) { self::validateName($name); if (null !== $dataClass && !class_exists($dataClass) && !interface_exists($dataClass, false)) { @@ -79,8 +81,6 @@ public function __construct(?string $name, ?string $dataClass, EventDispatcherIn $this->name = (string) $name; $this->dataClass = $dataClass; - $this->dispatcher = $dispatcher; - $this->options = $options; } public function addEventListener(string $eventName, callable $listener, int $priority = 0): static diff --git a/FormError.php b/FormError.php index face43bcef..7c3f5dd0bc 100644 --- a/FormError.php +++ b/FormError.php @@ -21,11 +21,6 @@ class FormError { protected string $messageTemplate; - protected array $messageParameters; - protected ?int $messagePluralization; - - private string $message; - private mixed $cause; /** * The form that spawned this error. @@ -45,13 +40,14 @@ class FormError * * @see \Symfony\Component\Translation\Translator */ - public function __construct(string $message, string $messageTemplate = null, array $messageParameters = [], int $messagePluralization = null, mixed $cause = null) - { - $this->message = $message; + public function __construct( + private string $message, + string $messageTemplate = null, + protected array $messageParameters = [], + protected ?int $messagePluralization = null, + private mixed $cause = null, + ) { $this->messageTemplate = $messageTemplate ?: $message; - $this->messageParameters = $messageParameters; - $this->messagePluralization = $messagePluralization; - $this->cause = $cause; } /** diff --git a/FormErrorIterator.php b/FormErrorIterator.php index 42de0c8358..a614e72c2e 100644 --- a/FormErrorIterator.php +++ b/FormErrorIterator.php @@ -42,8 +42,6 @@ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \Array */ public const INDENTATION = ' '; - private FormInterface $form; - /** * @var list */ @@ -54,15 +52,16 @@ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \Array * * @throws InvalidArgumentException If the errors are invalid */ - public function __construct(FormInterface $form, array $errors) - { + public function __construct( + private FormInterface $form, + array $errors, + ) { foreach ($errors as $error) { if (!($error instanceof FormError || $error instanceof self)) { throw new InvalidArgumentException(sprintf('The errors must be instances of "Symfony\Component\Form\FormError" or "%s". Got: "%s".', __CLASS__, get_debug_type($error))); } } - $this->form = $form; $this->errors = $errors; } diff --git a/FormEvent.php b/FormEvent.php index e46fbb6a6a..e6a3878f6d 100644 --- a/FormEvent.php +++ b/FormEvent.php @@ -18,14 +18,10 @@ */ class FormEvent extends Event { - protected mixed $data; - - private FormInterface $form; - - public function __construct(FormInterface $form, mixed $data) - { - $this->form = $form; - $this->data = $data; + public function __construct( + private FormInterface $form, + protected mixed $data, + ) { } /** diff --git a/FormFactory.php b/FormFactory.php index 9e1234f831..dcf7b36f28 100644 --- a/FormFactory.php +++ b/FormFactory.php @@ -16,11 +16,9 @@ class FormFactory implements FormFactoryInterface { - private FormRegistryInterface $registry; - - public function __construct(FormRegistryInterface $registry) - { - $this->registry = $registry; + public function __construct( + private FormRegistryInterface $registry, + ) { } public function create(string $type = FormType::class, mixed $data = null, array $options = []): FormInterface diff --git a/FormFactoryBuilder.php b/FormFactoryBuilder.php index 42b8dec9f4..90e3bf20ca 100644 --- a/FormFactoryBuilder.php +++ b/FormFactoryBuilder.php @@ -20,8 +20,6 @@ */ class FormFactoryBuilder implements FormFactoryBuilderInterface { - private bool $forceCoreExtension; - private ResolvedFormTypeFactoryInterface $resolvedTypeFactory; /** @@ -44,9 +42,9 @@ class FormFactoryBuilder implements FormFactoryBuilderInterface */ private array $typeGuessers = []; - public function __construct(bool $forceCoreExtension = false) - { - $this->forceCoreExtension = $forceCoreExtension; + public function __construct( + private bool $forceCoreExtension = false, + ) { } public function setResolvedTypeFactory(ResolvedFormTypeFactoryInterface $resolvedTypeFactory): static diff --git a/FormRegistry.php b/FormRegistry.php index cf8f66b40b..95a0077378 100644 --- a/FormRegistry.php +++ b/FormRegistry.php @@ -34,7 +34,6 @@ class FormRegistry implements FormRegistryInterface private array $types = []; private FormTypeGuesserInterface|false|null $guesser = false; - private ResolvedFormTypeFactoryInterface $resolvedTypeFactory; private array $checkedTypes = []; /** @@ -42,8 +41,10 @@ class FormRegistry implements FormRegistryInterface * * @throws UnexpectedTypeException if any extension does not implement FormExtensionInterface */ - public function __construct(array $extensions, ResolvedFormTypeFactoryInterface $resolvedTypeFactory) - { + public function __construct( + array $extensions, + private ResolvedFormTypeFactoryInterface $resolvedTypeFactory, + ) { foreach ($extensions as $extension) { if (!$extension instanceof FormExtensionInterface) { throw new UnexpectedTypeException($extension, FormExtensionInterface::class); @@ -51,7 +52,6 @@ public function __construct(array $extensions, ResolvedFormTypeFactoryInterface } $this->extensions = $extensions; - $this->resolvedTypeFactory = $resolvedTypeFactory; } public function getType(string $name): ResolvedFormTypeInterface diff --git a/FormRenderer.php b/FormRenderer.php index c2771d28c9..a9ffd4f41e 100644 --- a/FormRenderer.php +++ b/FormRenderer.php @@ -25,16 +25,14 @@ class FormRenderer implements FormRendererInterface { public const CACHE_KEY_VAR = 'unique_block_prefix'; - private FormRendererEngineInterface $engine; - private ?CsrfTokenManagerInterface $csrfTokenManager; private array $blockNameHierarchyMap = []; private array $hierarchyLevelMap = []; private array $variableStack = []; - public function __construct(FormRendererEngineInterface $engine, CsrfTokenManagerInterface $csrfTokenManager = null) - { - $this->engine = $engine; - $this->csrfTokenManager = $csrfTokenManager; + public function __construct( + private FormRendererEngineInterface $engine, + private ?CsrfTokenManagerInterface $csrfTokenManager = null, + ) { } public function getEngine(): FormRendererEngineInterface diff --git a/FormView.php b/FormView.php index e9e9e9957b..93804bb879 100644 --- a/FormView.php +++ b/FormView.php @@ -29,11 +29,6 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable 'attr' => [], ]; - /** - * The parent view. - */ - public ?self $parent = null; - /** * The child views. * @@ -52,9 +47,12 @@ class FormView implements \ArrayAccess, \IteratorAggregate, \Countable private bool $methodRendered = false; - public function __construct(self $parent = null) - { - $this->parent = $parent; + /** + * @param FormView|null $parent The parent view + */ + public function __construct( + public ?self $parent = null, + ) { } /** diff --git a/Guess/TypeGuess.php b/Guess/TypeGuess.php index 8ede78eb8c..b62873daa4 100644 --- a/Guess/TypeGuess.php +++ b/Guess/TypeGuess.php @@ -19,9 +19,6 @@ */ class TypeGuess extends Guess { - private string $type; - private array $options; - /** * @param string $type The guessed field type * @param array $options The options for creating instances of the @@ -29,12 +26,12 @@ class TypeGuess extends Guess * @param int $confidence The confidence that the guessed class name * is correct */ - public function __construct(string $type, array $options, int $confidence) - { + public function __construct( + private string $type, + private array $options, + int $confidence, + ) { parent::__construct($confidence); - - $this->type = $type; - $this->options = $options; } /** diff --git a/Guess/ValueGuess.php b/Guess/ValueGuess.php index 36abe6602d..2283287472 100644 --- a/Guess/ValueGuess.php +++ b/Guess/ValueGuess.php @@ -18,16 +18,14 @@ */ class ValueGuess extends Guess { - private string|int|bool|null $value; - /** * @param int $confidence The confidence that the guessed class name is correct */ - public function __construct(string|int|bool|null $value, int $confidence) - { + public function __construct( + private string|int|bool|null $value, + int $confidence, + ) { parent::__construct($confidence); - - $this->value = $value; } /** diff --git a/PreloadedExtension.php b/PreloadedExtension.php index c8e628d2d2..58d8f13b1b 100644 --- a/PreloadedExtension.php +++ b/PreloadedExtension.php @@ -21,8 +21,6 @@ class PreloadedExtension implements FormExtensionInterface { private array $types = []; - private array $typeExtensions = []; - private ?FormTypeGuesserInterface $typeGuesser; /** * Creates a new preloaded extension. @@ -30,11 +28,11 @@ class PreloadedExtension implements FormExtensionInterface * @param FormTypeInterface[] $types The types that the extension should support * @param FormTypeExtensionInterface[][] $typeExtensions The type extensions that the extension should support */ - public function __construct(array $types, array $typeExtensions, FormTypeGuesserInterface $typeGuesser = null) - { - $this->typeExtensions = $typeExtensions; - $this->typeGuesser = $typeGuesser; - + public function __construct( + array $types, + private array $typeExtensions, + private ?FormTypeGuesserInterface $typeGuesser = null, + ) { foreach ($types as $type) { $this->types[$type::class] = $type; } diff --git a/ResolvedFormType.php b/ResolvedFormType.php index 1acdce8375..6c856db8b4 100644 --- a/ResolvedFormType.php +++ b/ResolvedFormType.php @@ -23,31 +23,28 @@ */ class ResolvedFormType implements ResolvedFormTypeInterface { - private FormTypeInterface $innerType; - /** * @var FormTypeExtensionInterface[] */ private array $typeExtensions; - private ?ResolvedFormTypeInterface $parent; - private OptionsResolver $optionsResolver; /** * @param FormTypeExtensionInterface[] $typeExtensions */ - public function __construct(FormTypeInterface $innerType, array $typeExtensions = [], ResolvedFormTypeInterface $parent = null) - { + public function __construct( + private FormTypeInterface $innerType, + array $typeExtensions = [], + private ?ResolvedFormTypeInterface $parent = null, + ) { foreach ($typeExtensions as $extension) { if (!$extension instanceof FormTypeExtensionInterface) { throw new UnexpectedTypeException($extension, FormTypeExtensionInterface::class); } } - $this->innerType = $innerType; $this->typeExtensions = $typeExtensions; - $this->parent = $parent; } public function getBlockPrefix(): string diff --git a/ReversedTransformer.php b/ReversedTransformer.php index b683879080..4aa92450a2 100644 --- a/ReversedTransformer.php +++ b/ReversedTransformer.php @@ -21,11 +21,9 @@ */ class ReversedTransformer implements DataTransformerInterface { - protected DataTransformerInterface $reversedTransformer; - - public function __construct(DataTransformerInterface $reversedTransformer) - { - $this->reversedTransformer = $reversedTransformer; + public function __construct( + protected DataTransformerInterface $reversedTransformer, + ) { } public function transform(mixed $value): mixed diff --git a/Util/OrderedHashMap.php b/Util/OrderedHashMap.php index 32d08caa8f..c0cab7aac6 100644 --- a/Util/OrderedHashMap.php +++ b/Util/OrderedHashMap.php @@ -71,13 +71,6 @@ */ class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable { - /** - * The elements of the map, indexed by their keys. - * - * @var TValue[] - */ - private array $elements = []; - /** * The keys of the map in the order in which they were inserted or changed. * @@ -95,11 +88,11 @@ class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable /** * Creates a new map. * - * @param TValue[] $elements The elements to insert initially + * @param TValue[] $elements The initial elements of the map, indexed by their keys. */ - public function __construct(array $elements = []) - { - $this->elements = $elements; + public function __construct( + private array $elements = [], + ) { // the explicit string type-cast is necessary as digit-only keys would be returned as integers otherwise $this->orderedKeys = array_map(strval(...), array_keys($elements)); } diff --git a/Util/OrderedHashMapIterator.php b/Util/OrderedHashMapIterator.php index 4a8eebe61d..927a28c04a 100644 --- a/Util/OrderedHashMapIterator.php +++ b/Util/OrderedHashMapIterator.php @@ -24,14 +24,8 @@ */ class OrderedHashMapIterator implements \Iterator { - /** @var TValue[] */ - private array $elements; - /** @var list */ - private array $orderedKeys; private int $cursor = 0; private int $cursorId; - /** @var array */ - private array $managedCursors; private ?string $key = null; /** @var TValue|null */ private mixed $current = null; @@ -47,11 +41,11 @@ class OrderedHashMapIterator implements \Iterator * {@link OrderedHashMap} instance to support * recognizing the deletion of elements. */ - public function __construct(array &$elements, array &$orderedKeys, array &$managedCursors) - { - $this->elements = &$elements; - $this->orderedKeys = &$orderedKeys; - $this->managedCursors = &$managedCursors; + public function __construct( + private array &$elements, + private array &$orderedKeys, + private array &$managedCursors, + ) { $this->cursorId = \count($managedCursors); $this->managedCursors[$this->cursorId] = &$this->cursor; diff --git a/Util/ServerParams.php b/Util/ServerParams.php index eb317ff36a..2c23efcc88 100644 --- a/Util/ServerParams.php +++ b/Util/ServerParams.php @@ -18,11 +18,9 @@ */ class ServerParams { - private ?RequestStack $requestStack; - - public function __construct(RequestStack $requestStack = null) - { - $this->requestStack = $requestStack; + public function __construct( + private ?RequestStack $requestStack = null, + ) { } /** From 3d545bea7066520d1e7b275634f339bcbef1f15d Mon Sep 17 00:00:00 2001 From: Fan2Shrek Date: Wed, 14 Feb 2024 19:02:05 +0100 Subject: [PATCH 12/70] Throw error if the number is too high on moneyTransformer --- .../MoneyToLocalizedStringTransformer.php | 11 ++++++++++- .../MoneyToLocalizedStringTransformerTest.php | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php index d9a75a2604..6ce24d3c63 100644 --- a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php @@ -69,7 +69,16 @@ public function reverseTransform(mixed $value): int|float|null $value = parent::reverseTransform($value); if (null !== $value && 1 !== $this->divisor) { $value = (string) ($value * $this->divisor); - $value = 'integer' === $this->modelType ? (int) $value : (float) $value; + + if ('float' === $this->modelType) { + return (float) $value; + } + + if ($value > \PHP_INT_MAX || $value < \PHP_INT_MIN) { + throw new TransformationFailedException(sprintf("The value '%d' is too large you should pass the 'model_type' to 'float'.", $value)); + } + + $value = (int) $value; } return $value; diff --git a/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php index 2d43e95332..e5733ad96a 100644 --- a/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php @@ -118,4 +118,13 @@ public function testValidNumericValuesWithNonDotDecimalPointCharacter() $this->assertSame('0,0035', $transformer->transform(12 / 34)); } + + public function testHighIntNumberConversion() + { + $transformer = new MoneyToLocalizedStringTransformer(4, null, null, 100); + + $this->expectException(TransformationFailedException::class); + + $transformer->reverseTransform(111111111111111110.00); + } } From fd6e0a55e5f7526d4fe5a07a4dc3fbb42ec7cb78 Mon Sep 17 00:00:00 2001 From: patrickmaynard Date: Sun, 23 Apr 2023 13:58:03 +0200 Subject: [PATCH 13/70] 46867 - add more helpful property path accessor exceptions --- Extension/Core/DataAccessor/PropertyPathAccessor.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Extension/Core/DataAccessor/PropertyPathAccessor.php b/Extension/Core/DataAccessor/PropertyPathAccessor.php index 85efa150f4..6ea8b8ddef 100644 --- a/Extension/Core/DataAccessor/PropertyPathAccessor.php +++ b/Extension/Core/DataAccessor/PropertyPathAccessor.php @@ -16,6 +16,7 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\PropertyAccess\Exception\AccessException as PropertyAccessException; use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; +use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -60,7 +61,11 @@ public function setValue(object|array &$data, mixed $value, FormInterface $form) // If the data is identical to the value in $data, we are // dealing with a reference if (!\is_object($data) || !$form->getConfig()->getByReference() || $value !== $this->getPropertyValue($data, $propertyPath)) { - $this->propertyAccessor->setValue($data, $propertyPath, $value); + try { + $this->propertyAccessor->setValue($data, $propertyPath, $value); + } catch (NoSuchPropertyException $e) { + throw new NoSuchPropertyException($e->getMessage().' Make the property public, add a setter, or set the "mapped" field option in the form type to be false.', 0, $e); + } } } From 7b4f01d319061c21f55b051577049660737a7fd0 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Mon, 18 Mar 2024 20:27:13 +0100 Subject: [PATCH 14/70] chore: CS fixes --- Button.php | 2 +- Extension/Core/Type/TimeType.php | 2 +- Extension/Csrf/EventListener/CsrfValidationListener.php | 3 +-- Extension/Validator/ViolationMapper/RelativePath.php | 3 +-- Form.php | 2 +- NativeRequestHandler.php | 2 +- Tests/Extension/Validator/ValidatorTypeGuesserTest.php | 2 +- Tests/FormFactoryTest.php | 8 ++++---- Util/OrderedHashMap.php | 2 +- 9 files changed, 12 insertions(+), 14 deletions(-) diff --git a/Button.php b/Button.php index f172a7ee31..c35f93d606 100644 --- a/Button.php +++ b/Button.php @@ -311,7 +311,7 @@ public function handleRequest(mixed $request = null): static * * @return $this * - * @throws Exception\AlreadySubmittedException if the button has already been submitted + * @throws AlreadySubmittedException if the button has already been submitted */ public function submit(array|string|null $submittedData, bool $clearMissing = true): static { diff --git a/Extension/Core/Type/TimeType.php b/Extension/Core/Type/TimeType.php index cf46b76acd..4e01489e73 100644 --- a/Extension/Core/Type/TimeType.php +++ b/Extension/Core/Type/TimeType.php @@ -12,13 +12,13 @@ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Event\PreSubmitEvent; use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; -use Symfony\Component\Form\Event\PreSubmitEvent; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; diff --git a/Extension/Csrf/EventListener/CsrfValidationListener.php b/Extension/Csrf/EventListener/CsrfValidationListener.php index 5aac521c84..44922402ff 100644 --- a/Extension/Csrf/EventListener/CsrfValidationListener.php +++ b/Extension/Csrf/EventListener/CsrfValidationListener.php @@ -42,8 +42,7 @@ public function __construct( private ?TranslatorInterface $translator = null, private ?string $translationDomain = null, ?ServerParams $serverParams = null, - ) - { + ) { $this->serverParams = $serverParams ?? new ServerParams(); } diff --git a/Extension/Validator/ViolationMapper/RelativePath.php b/Extension/Validator/ViolationMapper/RelativePath.php index dbf0712e2f..c139933743 100644 --- a/Extension/Validator/ViolationMapper/RelativePath.php +++ b/Extension/Validator/ViolationMapper/RelativePath.php @@ -22,8 +22,7 @@ class RelativePath extends PropertyPath public function __construct( private FormInterface $root, string $propertyPath, - ) - { + ) { parent::__construct($propertyPath); } diff --git a/Form.php b/Form.php index ee75311a14..44b97261bd 100644 --- a/Form.php +++ b/Form.php @@ -613,7 +613,7 @@ public function isSynchronized(): bool return null === $this->transformationFailure; } - public function getTransformationFailure(): ?Exception\TransformationFailedException + public function getTransformationFailure(): ?TransformationFailedException { return $this->transformationFailure; } diff --git a/NativeRequestHandler.php b/NativeRequestHandler.php index 4c03df13d5..bee54fa60d 100644 --- a/NativeRequestHandler.php +++ b/NativeRequestHandler.php @@ -42,7 +42,7 @@ public function __construct(?ServerParams $params = null) } /** - * @throws Exception\UnexpectedTypeException If the $request is not null + * @throws UnexpectedTypeException If the $request is not null */ public function handleRequest(FormInterface $form, mixed $request = null): void { diff --git a/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index 0ac6b39148..c561cd76f2 100644 --- a/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -50,7 +50,7 @@ class ValidatorTypeGuesserTest extends TestCase /** * @var MetadataFactoryInterface */ - private \Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory $metadataFactory; + private FakeMetadataFactory $metadataFactory; protected function setUp(): void { diff --git a/Tests/FormFactoryTest.php b/Tests/FormFactoryTest.php index bb18464c78..0cb3cad730 100644 --- a/Tests/FormFactoryTest.php +++ b/Tests/FormFactoryTest.php @@ -173,10 +173,10 @@ public function testCreateBuilderUsesPatternIfFound() class ConfigurableFormTypeGuesser implements FormTypeGuesserInterface { - private ?\Symfony\Component\Form\Guess\TypeGuess $typeGuess = null; - private ?\Symfony\Component\Form\Guess\ValueGuess $requiredGuess = null; - private ?\Symfony\Component\Form\Guess\ValueGuess $maxLengthGuess = null; - private ?\Symfony\Component\Form\Guess\ValueGuess $patternGuess = null; + private ?TypeGuess $typeGuess = null; + private ?ValueGuess $requiredGuess = null; + private ?ValueGuess $maxLengthGuess = null; + private ?ValueGuess $patternGuess = null; public function guessType($class, $property): ?TypeGuess { diff --git a/Util/OrderedHashMap.php b/Util/OrderedHashMap.php index c0cab7aac6..145bd2e25e 100644 --- a/Util/OrderedHashMap.php +++ b/Util/OrderedHashMap.php @@ -88,7 +88,7 @@ class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable /** * Creates a new map. * - * @param TValue[] $elements The initial elements of the map, indexed by their keys. + * @param TValue[] $elements The initial elements of the map, indexed by their keys */ public function __construct( private array $elements = [], From 2d1c888f00866164b7705107070db1c73fb41e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sun, 31 Mar 2024 15:15:18 +0200 Subject: [PATCH 15/70] Remove unnecessary empty usages --- Extension/Core/DataTransformer/DateTimeToStringTransformer.php | 2 +- Extension/Validator/Type/BaseValidatorExtension.php | 2 +- Tests/Extension/Core/Type/CollectionTypeTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Extension/Core/DataTransformer/DateTimeToStringTransformer.php b/Extension/Core/DataTransformer/DateTimeToStringTransformer.php index 96bdc7c0de..1353614208 100644 --- a/Extension/Core/DataTransformer/DateTimeToStringTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeToStringTransformer.php @@ -101,7 +101,7 @@ public function transform(mixed $dateTime): string */ public function reverseTransform(mixed $value): ?\DateTime { - if (empty($value)) { + if (!$value) { return null; } diff --git a/Extension/Validator/Type/BaseValidatorExtension.php b/Extension/Validator/Type/BaseValidatorExtension.php index 4b3fb49624..6b70df75fa 100644 --- a/Extension/Validator/Type/BaseValidatorExtension.php +++ b/Extension/Validator/Type/BaseValidatorExtension.php @@ -32,7 +32,7 @@ public function configureOptions(OptionsResolver $resolver): void return []; } - if (empty($groups)) { + if (!$groups) { return null; } diff --git a/Tests/Extension/Core/Type/CollectionTypeTest.php b/Tests/Extension/Core/Type/CollectionTypeTest.php index 08d512caf1..79134db993 100644 --- a/Tests/Extension/Core/Type/CollectionTypeTest.php +++ b/Tests/Extension/Core/Type/CollectionTypeTest.php @@ -120,7 +120,7 @@ public function testResizedDownWithDeleteEmptyCallable() $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => AuthorType::class, 'allow_delete' => true, - 'delete_empty' => fn (?Author $obj = null) => null === $obj || empty($obj->firstName), + 'delete_empty' => fn (?Author $obj = null) => null === $obj || !$obj->firstName, ]); $form->setData([new Author('Bob'), new Author('Alice')]); From 5a7886b3d342d58f1e54031cec9d421a7be02d51 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 7 Apr 2024 23:52:35 +0200 Subject: [PATCH 16/70] Proofread UPGRADE guide --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e42aebae7..836823fa19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ CHANGELOG --- * Add option `separator` to `ChoiceType` to use a custom separator after preferred choices (use the new `separator_html` option to display the separator text as HTML) - * Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 + * Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 (the current default is `'http'`) * Add a `keep_as_list` option to `CollectionType` * Add a new `model_type` option to `MoneyType`, to be able to cast the transformed value to `integer` From a492b5cc53f90d0da5ca5ee0cd0c27072f8d4377 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 29 Apr 2024 15:41:47 +0200 Subject: [PATCH 17/70] rename the model_type option to input and rework it --- CHANGELOG.md | 2 +- .../MoneyToLocalizedStringTransformer.php | 8 ++++---- Extension/Core/Type/MoneyType.php | 14 +++----------- Tests/Extension/Core/Type/MoneyTypeTest.php | 14 +++++++------- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 836823fa19..0420af3413 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ CHANGELOG * Add option `separator` to `ChoiceType` to use a custom separator after preferred choices (use the new `separator_html` option to display the separator text as HTML) * Deprecate not configuring the `default_protocol` option of the `UrlType`, it will default to `null` in 8.0 (the current default is `'http'`) * Add a `keep_as_list` option to `CollectionType` - * Add a new `model_type` option to `MoneyType`, to be able to cast the transformed value to `integer` + * Add an `input` option to `MoneyType`, to be able to cast the transformed value to `integer` 7.0 --- diff --git a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php index 6ce24d3c63..caf6750e9f 100644 --- a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php @@ -29,7 +29,7 @@ public function __construct( ?int $roundingMode = \NumberFormatter::ROUND_HALFUP, ?int $divisor = 1, ?string $locale = null, - private string $modelType = 'float', + private readonly string $input = 'float', ) { parent::__construct($scale ?? 2, $grouping ?? true, $roundingMode, $locale); @@ -67,15 +67,15 @@ public function transform(mixed $value): string public function reverseTransform(mixed $value): int|float|null { $value = parent::reverseTransform($value); - if (null !== $value && 1 !== $this->divisor) { + if (null !== $value) { $value = (string) ($value * $this->divisor); - if ('float' === $this->modelType) { + if ('float' === $this->input) { return (float) $value; } if ($value > \PHP_INT_MAX || $value < \PHP_INT_MIN) { - throw new TransformationFailedException(sprintf("The value '%d' is too large you should pass the 'model_type' to 'float'.", $value)); + throw new TransformationFailedException(sprintf('Cannot cast "%s" to an integer. Try setting the input to "float" instead.', $value)); } $value = (int) $value; diff --git a/Extension/Core/Type/MoneyType.php b/Extension/Core/Type/MoneyType.php index e4d402d8d0..2657b03afb 100644 --- a/Extension/Core/Type/MoneyType.php +++ b/Extension/Core/Type/MoneyType.php @@ -35,7 +35,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $options['rounding_mode'], $options['divisor'], $options['html5'] ? 'en' : null, - $options['model_type'], + $options['input'], )) ; } @@ -60,7 +60,7 @@ public function configureOptions(OptionsResolver $resolver): void 'compound' => false, 'html5' => false, 'invalid_message' => 'Please enter a valid money amount.', - 'model_type' => 'float', + 'input' => 'float', ]); $resolver->setAllowedValues('rounding_mode', [ @@ -77,7 +77,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('html5', 'bool'); - $resolver->setAllowedValues('model_type', ['float', 'integer']); + $resolver->setAllowedValues('input', ['float', 'integer']); $resolver->setNormalizer('grouping', static function (Options $options, $value) { if ($value && $options['html5']) { @@ -86,14 +86,6 @@ public function configureOptions(OptionsResolver $resolver): void return $value; }); - - $resolver->setNormalizer('model_type', static function (Options $options, $value) { - if ('integer' === $value && 1 === $options['divisor']) { - throw new LogicException('When the "model_type" option is set to "integer", the "divisor" option should not be set to "1".'); - } - - return $value; - }); } public function getBlockPrefix(): string diff --git a/Tests/Extension/Core/Type/MoneyTypeTest.php b/Tests/Extension/Core/Type/MoneyTypeTest.php index 75d0729438..58e33af19b 100644 --- a/Tests/Extension/Core/Type/MoneyTypeTest.php +++ b/Tests/Extension/Core/Type/MoneyTypeTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; -use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Intl\Util\IntlTestHelper; class MoneyTypeTest extends BaseTypeTestCase @@ -125,7 +124,7 @@ public function testHtml5EnablesSpecificFormatting() $this->assertSame('number', $form->createView()->vars['type']); } - public function testDefaultModelType() + public function testDefaultInput() { $form = $this->factory->create(static::TESTED_TYPE, null, ['divisor' => 100]); $form->submit('12345.67'); @@ -133,18 +132,19 @@ public function testDefaultModelType() $this->assertSame(1234567.0, $form->getData()); } - public function testIntegerModelType() + public function testIntegerInput() { - $form = $this->factory->create(static::TESTED_TYPE, null, ['divisor' => 100, 'model_type' => 'integer']); + $form = $this->factory->create(static::TESTED_TYPE, null, ['divisor' => 100, 'input' => 'integer']); $form->submit('12345.67'); $this->assertSame(1234567, $form->getData()); } - public function testIntegerModelTypeExpectsDivisorNotEqualToOne() + public function testIntegerInputWithoutDivisor() { - $this->expectException(LogicException::class); + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'integer']); + $form->submit('1234567'); - $form = $this->factory->create(static::TESTED_TYPE, null, ['divisor' => 1, 'model_type' => 'integer']); + $this->assertSame(1234567, $form->getData()); } } From 50a9e64496b4d6cba7c7cc29be308593e34f6883 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Mon, 20 May 2024 18:41:11 +0200 Subject: [PATCH 18/70] Fix singular phpdoc --- FormRegistryInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FormRegistryInterface.php b/FormRegistryInterface.php index b1e77898e2..5c76b5c678 100644 --- a/FormRegistryInterface.php +++ b/FormRegistryInterface.php @@ -21,7 +21,7 @@ interface FormRegistryInterface /** * Returns a form type by name. * - * This methods registers the type extensions from the form extensions. + * This method registers the type extensions from the form extensions. * * @throws Exception\InvalidArgumentException if the type cannot be retrieved from any extension */ From 0981f0b0955a764393f77bd22ed961e0449a3aa6 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 20 Jun 2024 17:52:34 +0200 Subject: [PATCH 19/70] Prefix all sprintf() calls --- AbstractExtension.php | 2 +- Command/DebugCommand.php | 10 +++++----- Console/Descriptor/Descriptor.php | 2 +- Console/Descriptor/TextDescriptor.php | 8 ++++---- DependencyInjection/FormPass.php | 2 +- Exception/UnexpectedTypeException.php | 2 +- .../DataTransformer/ArrayToPartsTransformer.php | 2 +- .../DataTransformer/BaseDateTimeTransformer.php | 4 ++-- .../DataTransformer/ChoiceToValueTransformer.php | 2 +- .../DateIntervalToArrayTransformer.php | 8 ++++---- .../DateIntervalToStringTransformer.php | 2 +- .../DataTransformer/DateTimeToArrayTransformer.php | 4 ++-- .../DateTimeToHtml5LocalDateTimeTransformer.php | 4 ++-- .../DateTimeToLocalizedStringTransformer.php | 4 ++-- .../DateTimeToRfc3339Transformer.php | 4 ++-- .../IntegerToLocalizedStringTransformer.php | 2 +- .../IntlTimeZoneToStringTransformer.php | 2 +- .../MoneyToLocalizedStringTransformer.php | 2 +- .../NumberToLocalizedStringTransformer.php | 2 +- .../PercentToLocalizedStringTransformer.php | 2 +- .../DataTransformer/UlidToStringTransformer.php | 2 +- .../DataTransformer/UuidToStringTransformer.php | 4 ++-- .../ValueToDuplicatesTransformer.php | 2 +- .../DataTransformer/WeekToArrayTransformer.php | 14 +++++++------- Extension/Core/Type/BaseType.php | 6 +++--- Extension/Core/Type/ChoiceType.php | 4 ++-- Extension/Core/Type/CountryType.php | 2 +- Extension/Core/Type/CurrencyType.php | 2 +- Extension/Core/Type/DateTimeType.php | 10 +++++----- Extension/Core/Type/DateType.php | 8 ++++---- Extension/Core/Type/LanguageType.php | 2 +- Extension/Core/Type/LocaleType.php | 2 +- Extension/Core/Type/TimeType.php | 8 ++++---- Extension/Core/Type/TimezoneType.php | 2 +- Extension/Core/Type/WeekType.php | 2 +- Extension/DataCollector/FormDataCollector.php | 2 +- .../DependencyInjectionExtension.php | 4 ++-- .../EventListener/PasswordHasherListener.php | 2 +- Extension/Validator/Constraints/FormValidator.php | 6 +++--- Extension/Validator/ValidatorTypeGuesser.php | 4 ++-- .../Validator/ViolationMapper/MappingRule.php | 2 +- .../Validator/ViolationMapper/ViolationPath.php | 8 ++++---- Form.php | 12 ++++++------ FormBuilder.php | 2 +- FormConfigBuilder.php | 4 ++-- FormErrorIterator.php | 4 ++-- FormRegistry.php | 6 +++--- FormRenderer.php | 8 ++++---- PreloadedExtension.php | 2 +- ResolvedFormType.php | 2 +- Test/FormPerformanceTestCase.php | 2 +- Test/Traits/ValidatorExtensionTrait.php | 2 +- .../Descriptor/AbstractDescriptorTestCase.php | 2 +- .../Core/Type/ChoiceTypeTranslationTest.php | 2 +- .../DependencyInjectionExtensionTest.php | 2 +- Tests/ResolvedFormTypeTest.php | 2 +- Tests/Resources/TranslationFilesTest.php | 4 ++-- Tests/VersionAwareTest.php | 2 +- Util/OrderedHashMap.php | 2 +- 59 files changed, 114 insertions(+), 114 deletions(-) diff --git a/AbstractExtension.php b/AbstractExtension.php index 908f4f86ff..27665727cf 100644 --- a/AbstractExtension.php +++ b/AbstractExtension.php @@ -50,7 +50,7 @@ public function getType(string $name): FormTypeInterface } if (!isset($this->types[$name])) { - throw new InvalidArgumentException(sprintf('The type "%s" cannot be loaded by this extension.', $name)); + throw new InvalidArgumentException(\sprintf('The type "%s" cannot be loaded by this extension.', $name)); } return $this->types[$name]; diff --git a/Command/DebugCommand.php b/Command/DebugCommand.php index 4d99012298..18d208cbe8 100644 --- a/Command/DebugCommand.php +++ b/Command/DebugCommand.php @@ -53,7 +53,7 @@ protected function configure(): void new InputArgument('class', InputArgument::OPTIONAL, 'The form type class'), new InputArgument('option', InputArgument::OPTIONAL, 'The form type option'), new InputOption('show-deprecated', null, InputOption::VALUE_NONE, 'Display deprecated options in form types'), - new InputOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'txt'), + new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'txt'), ]) ->setHelp(<<<'EOF' The %command.name% command displays information about form types. @@ -114,7 +114,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $object = $resolvedType->getOptionsResolver(); if (!$object->isDefined($option)) { - $message = sprintf('Option "%s" is not defined in "%s".', $option, $resolvedType->getInnerType()::class); + $message = \sprintf('Option "%s" is not defined in "%s".', $option, $resolvedType->getInnerType()::class); if ($alternatives = $this->findAlternatives($option, $object->getDefinedOptions())) { if (1 === \count($alternatives)) { @@ -148,7 +148,7 @@ private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, strin $classes = $this->getFqcnTypeClasses($shortClassName); if (0 === $count = \count($classes)) { - $message = sprintf("Could not find type \"%s\" into the following namespaces:\n %s", $shortClassName, implode("\n ", $this->namespaces)); + $message = \sprintf("Could not find type \"%s\" into the following namespaces:\n %s", $shortClassName, implode("\n ", $this->namespaces)); $allTypes = array_merge($this->getCoreTypes(), $this->types); if ($alternatives = $this->findAlternatives($shortClassName, $allTypes)) { @@ -166,10 +166,10 @@ private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, strin return $classes[0]; } if (!$input->isInteractive()) { - throw new InvalidArgumentException(sprintf("The type \"%s\" is ambiguous.\n\nDid you mean one of these?\n %s.", $shortClassName, implode("\n ", $classes))); + throw new InvalidArgumentException(\sprintf("The type \"%s\" is ambiguous.\n\nDid you mean one of these?\n %s.", $shortClassName, implode("\n ", $classes))); } - return $io->choice(sprintf("The type \"%s\" is ambiguous.\n\nSelect one of the following form types to display its information:", $shortClassName), $classes, $classes[0]); + return $io->choice(\sprintf("The type \"%s\" is ambiguous.\n\nSelect one of the following form types to display its information:", $shortClassName), $classes, $classes[0]); } private function getFqcnTypeClasses(string $shortClassName): array diff --git a/Console/Descriptor/Descriptor.php b/Console/Descriptor/Descriptor.php index f4835fb1ee..c910acdf4d 100644 --- a/Console/Descriptor/Descriptor.php +++ b/Console/Descriptor/Descriptor.php @@ -46,7 +46,7 @@ public function describe(OutputInterface $output, ?object $object, array $option null === $object => $this->describeDefaults($options), $object instanceof ResolvedFormTypeInterface => $this->describeResolvedFormType($object, $options), $object instanceof OptionsResolver => $this->describeOption($object, $options), - default => throw new \InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object))), + default => throw new \InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', get_debug_type($object))), }; } diff --git a/Console/Descriptor/TextDescriptor.php b/Console/Descriptor/TextDescriptor.php index 7b723a0af6..630b872535 100644 --- a/Console/Descriptor/TextDescriptor.php +++ b/Console/Descriptor/TextDescriptor.php @@ -80,7 +80,7 @@ protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedF 'extension' => 'Extension options', ], $formOptions); - $this->output->title(sprintf('%s (Block prefix: "%s")', $resolvedFormType->getInnerType()::class, $resolvedFormType->getInnerType()->getBlockPrefix())); + $this->output->title(\sprintf('%s (Block prefix: "%s")', $resolvedFormType->getInnerType()::class, $resolvedFormType->getInnerType()->getBlockPrefix())); if ($formOptions) { $this->output->table($tableHeaders, $this->buildTableRows($tableHeaders, $formOptions)); @@ -131,7 +131,7 @@ protected function describeOption(OptionsResolver $optionsResolver, array $optio } array_pop($rows); - $this->output->title(sprintf('%s (%s)', $options['type']::class, $options['option'])); + $this->output->title(\sprintf('%s (%s)', $options['type']::class, $options['option'])); $this->output->table([], $rows); } @@ -172,7 +172,7 @@ private function normalizeAndSortOptionsColumns(array $options): array } else { $options[$group][] = null; } - $options[$group][] = sprintf('%s', (new \ReflectionClass($class))->getShortName()); + $options[$group][] = \sprintf('%s', (new \ReflectionClass($class))->getShortName()); $options[$group][] = new TableSeparator(); sort($opt); @@ -196,7 +196,7 @@ private function formatClassLink(string $class, ?string $text = null): string return $text; } - return sprintf('%s', $fileLink, $text); + return \sprintf('%s', $fileLink, $text); } private function getFileLink(string $class): string diff --git a/DependencyInjection/FormPass.php b/DependencyInjection/FormPass.php index 4087311631..1d2b2a87e5 100644 --- a/DependencyInjection/FormPass.php +++ b/DependencyInjection/FormPass.php @@ -89,7 +89,7 @@ private function processFormTypeExtensions(ContainerBuilder $container): array } if (!$extendsTypes) { - throw new InvalidArgumentException(sprintf('The getExtendedTypes() method for service "%s" does not return any extended types.', $serviceId)); + throw new InvalidArgumentException(\sprintf('The getExtendedTypes() method for service "%s" does not return any extended types.', $serviceId)); } } } diff --git a/Exception/UnexpectedTypeException.php b/Exception/UnexpectedTypeException.php index 7a4dc295c6..223061b77b 100644 --- a/Exception/UnexpectedTypeException.php +++ b/Exception/UnexpectedTypeException.php @@ -15,6 +15,6 @@ class UnexpectedTypeException extends InvalidArgumentException { public function __construct(mixed $value, string $expectedType) { - parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, get_debug_type($value))); + parent::__construct(\sprintf('Expected argument of type "%s", "%s" given', $expectedType, get_debug_type($value))); } } diff --git a/Extension/Core/DataTransformer/ArrayToPartsTransformer.php b/Extension/Core/DataTransformer/ArrayToPartsTransformer.php index 828bd811e5..92f59c906e 100644 --- a/Extension/Core/DataTransformer/ArrayToPartsTransformer.php +++ b/Extension/Core/DataTransformer/ArrayToPartsTransformer.php @@ -72,7 +72,7 @@ public function reverseTransform(mixed $array): mixed return null; } - throw new TransformationFailedException(sprintf('The keys "%s" should not be empty.', implode('", "', $emptyKeys))); + throw new TransformationFailedException(\sprintf('The keys "%s" should not be empty.', implode('", "', $emptyKeys))); } return $result; diff --git a/Extension/Core/DataTransformer/BaseDateTimeTransformer.php b/Extension/Core/DataTransformer/BaseDateTimeTransformer.php index 8d311b3f8f..ca85fd44d0 100644 --- a/Extension/Core/DataTransformer/BaseDateTimeTransformer.php +++ b/Extension/Core/DataTransformer/BaseDateTimeTransformer.php @@ -47,13 +47,13 @@ public function __construct(?string $inputTimezone = null, ?string $outputTimezo try { new \DateTimeZone($this->inputTimezone); } catch (\Exception $e) { - throw new InvalidArgumentException(sprintf('Input timezone is invalid: "%s".', $this->inputTimezone), $e->getCode(), $e); + throw new InvalidArgumentException(\sprintf('Input timezone is invalid: "%s".', $this->inputTimezone), $e->getCode(), $e); } try { new \DateTimeZone($this->outputTimezone); } catch (\Exception $e) { - throw new InvalidArgumentException(sprintf('Output timezone is invalid: "%s".', $this->outputTimezone), $e->getCode(), $e); + throw new InvalidArgumentException(\sprintf('Output timezone is invalid: "%s".', $this->outputTimezone), $e->getCode(), $e); } } } diff --git a/Extension/Core/DataTransformer/ChoiceToValueTransformer.php b/Extension/Core/DataTransformer/ChoiceToValueTransformer.php index 52ee25e93e..e75bc31dee 100644 --- a/Extension/Core/DataTransformer/ChoiceToValueTransformer.php +++ b/Extension/Core/DataTransformer/ChoiceToValueTransformer.php @@ -45,7 +45,7 @@ public function reverseTransform(mixed $value): mixed return null; } - throw new TransformationFailedException(sprintf('The choice "%s" does not exist or is not unique.', $value)); + throw new TransformationFailedException(\sprintf('The choice "%s" does not exist or is not unique.', $value)); } return current($choices); diff --git a/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php b/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php index 08c0585979..0475b55bfd 100644 --- a/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php +++ b/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php @@ -124,19 +124,19 @@ public function reverseTransform(mixed $value): ?\DateInterval } } if (\count($emptyFields) > 0) { - throw new TransformationFailedException(sprintf('The fields "%s" should not be empty.', implode('", "', $emptyFields))); + throw new TransformationFailedException(\sprintf('The fields "%s" should not be empty.', implode('", "', $emptyFields))); } if (isset($value['invert']) && !\is_bool($value['invert'])) { throw new TransformationFailedException('The value of "invert" must be boolean.'); } foreach (self::AVAILABLE_FIELDS as $field => $char) { if ('invert' !== $field && isset($value[$field]) && !ctype_digit((string) $value[$field])) { - throw new TransformationFailedException(sprintf('This amount of "%s" is invalid.', $field)); + throw new TransformationFailedException(\sprintf('This amount of "%s" is invalid.', $field)); } } try { if (!empty($value['weeks'])) { - $interval = sprintf( + $interval = \sprintf( 'P%sY%sM%sWT%sH%sM%sS', empty($value['years']) ? '0' : $value['years'], empty($value['months']) ? '0' : $value['months'], @@ -146,7 +146,7 @@ public function reverseTransform(mixed $value): ?\DateInterval empty($value['seconds']) ? '0' : $value['seconds'] ); } else { - $interval = sprintf( + $interval = \sprintf( 'P%sY%sM%sDT%sH%sM%sS', empty($value['years']) ? '0' : $value['years'], empty($value['months']) ? '0' : $value['months'], diff --git a/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php b/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php index e1a3d97246..527836bf55 100644 --- a/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php +++ b/Extension/Core/DataTransformer/DateIntervalToStringTransformer.php @@ -79,7 +79,7 @@ public function reverseTransform(mixed $value): ?\DateInterval } $valuePattern = '/^'.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?P<$1>\d+)$2', $this->format).'$/'; if (!preg_match($valuePattern, $value)) { - throw new TransformationFailedException(sprintf('Value "%s" contains intervals not accepted by format "%s".', $value, $this->format)); + throw new TransformationFailedException(\sprintf('Value "%s" contains intervals not accepted by format "%s".', $value, $this->format)); } try { $dateInterval = new \DateInterval($value); diff --git a/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php b/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php index 8c3d2d2266..06d24cf8e0 100644 --- a/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php @@ -126,7 +126,7 @@ public function reverseTransform(mixed $value): ?\DateTime } if (\count($emptyFields) > 0) { - throw new TransformationFailedException(sprintf('The fields "%s" should not be empty.', implode('", "', $emptyFields))); + throw new TransformationFailedException(\sprintf('The fields "%s" should not be empty.', implode('", "', $emptyFields))); } if (isset($value['month']) && !ctype_digit((string) $value['month'])) { @@ -158,7 +158,7 @@ public function reverseTransform(mixed $value): ?\DateTime } try { - $dateTime = new \DateTime(sprintf( + $dateTime = new \DateTime(\sprintf( '%s-%s-%s %s:%s:%s', empty($value['year']) ? $this->referenceDate->format('Y') : $value['year'], empty($value['month']) ? $this->referenceDate->format('m') : $value['month'], diff --git a/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php b/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php index 855b22a499..dbeed8e490 100644 --- a/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformer.php @@ -85,7 +85,7 @@ public function reverseTransform(mixed $dateTimeLocal): ?\DateTime // to maintain backwards compatibility we do not strictly validate the submitted date // see https://github.com/symfony/symfony/issues/28699 if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})[T ]\d{2}:\d{2}(?::\d{2})?/', $dateTimeLocal, $matches)) { - throw new TransformationFailedException(sprintf('The date "%s" is not a valid date.', $dateTimeLocal)); + throw new TransformationFailedException(\sprintf('The date "%s" is not a valid date.', $dateTimeLocal)); } try { @@ -99,7 +99,7 @@ public function reverseTransform(mixed $dateTimeLocal): ?\DateTime } if (!checkdate($matches[2], $matches[3], $matches[1])) { - throw new TransformationFailedException(sprintf('The date "%s-%s-%s" is not a valid date.', $matches[1], $matches[2], $matches[3])); + throw new TransformationFailedException(\sprintf('The date "%s-%s-%s" is not a valid date.', $matches[1], $matches[2], $matches[3])); } return $dateTime; diff --git a/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index b7ea092591..a93803cd8b 100644 --- a/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -128,7 +128,7 @@ public function reverseTransform(mixed $value): ?\DateTime } elseif (false === $timestamp) { // the value couldn't be parsed but the Intl extension didn't report an error code, this // could be the case when the Intl polyfill is used which always returns 0 as the error code - throw new TransformationFailedException(sprintf('"%s" could not be parsed as a date.', $value)); + throw new TransformationFailedException(\sprintf('"%s" could not be parsed as a date.', $value)); } try { @@ -137,7 +137,7 @@ public function reverseTransform(mixed $value): ?\DateTime $dateTime = new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->outputTimezone)); } else { // read timestamp into DateTime object - the formatter delivers a timestamp - $dateTime = new \DateTime(sprintf('@%s', $timestamp)); + $dateTime = new \DateTime(\sprintf('@%s', $timestamp)); } // set timezone separately, as it would be ignored if set via the constructor, // see https://php.net/datetime.construct diff --git a/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php b/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php index 41e63e57ca..d32b3eae2b 100644 --- a/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php +++ b/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php @@ -64,7 +64,7 @@ public function reverseTransform(mixed $rfc3339): ?\DateTime } if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})T\d{2}:\d{2}(?::\d{2})?(?:\.\d+)?(?:Z|(?:(?:\+|-)\d{2}:\d{2}))$/', $rfc3339, $matches)) { - throw new TransformationFailedException(sprintf('The date "%s" is not a valid date.', $rfc3339)); + throw new TransformationFailedException(\sprintf('The date "%s" is not a valid date.', $rfc3339)); } try { @@ -78,7 +78,7 @@ public function reverseTransform(mixed $rfc3339): ?\DateTime } if (!checkdate($matches[2], $matches[3], $matches[1])) { - throw new TransformationFailedException(sprintf('The date "%s-%s-%s" is not a valid date.', $matches[1], $matches[2], $matches[3])); + throw new TransformationFailedException(\sprintf('The date "%s-%s-%s" is not a valid date.', $matches[1], $matches[2], $matches[3])); } return $dateTime; diff --git a/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php index eb5a2d6ff1..d83e31b42d 100644 --- a/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php @@ -38,7 +38,7 @@ public function reverseTransform(mixed $value): int|float|null $decimalSeparator = $this->getNumberFormatter()->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); if (\is_string($value) && str_contains($value, $decimalSeparator)) { - throw new TransformationFailedException(sprintf('The value "%s" is not a valid integer.', $value)); + throw new TransformationFailedException(\sprintf('The value "%s" is not a valid integer.', $value)); } $result = parent::reverseTransform($value); diff --git a/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php b/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php index 446a95f708..19626e49ca 100644 --- a/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php +++ b/Extension/Core/DataTransformer/IntlTimeZoneToStringTransformer.php @@ -70,7 +70,7 @@ public function reverseTransform(mixed $value): mixed $intlTimeZone = \IntlTimeZone::createTimeZone($value); if ('Etc/Unknown' === $intlTimeZone->getID()) { - throw new TransformationFailedException(sprintf('Unknown timezone identifier "%s".', $value)); + throw new TransformationFailedException(\sprintf('Unknown timezone identifier "%s".', $value)); } return $intlTimeZone; diff --git a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php index caf6750e9f..b03f8da444 100644 --- a/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php @@ -75,7 +75,7 @@ public function reverseTransform(mixed $value): int|float|null } if ($value > \PHP_INT_MAX || $value < \PHP_INT_MIN) { - throw new TransformationFailedException(sprintf('Cannot cast "%s" to an integer. Try setting the input to "float" instead.', $value)); + throw new TransformationFailedException(\sprintf('Cannot cast "%s" to an integer. Try setting the input to "float" instead.', $value)); } $value = (int) $value; diff --git a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index 6e1c495aee..2a6d146f90 100644 --- a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -140,7 +140,7 @@ public function reverseTransform(mixed $value): int|float|null $remainder = trim($remainder, " \t\n\r\0\x0b\xc2\xa0"); if ('' !== $remainder) { - throw new TransformationFailedException(sprintf('The number contains unrecognized characters: "%s".', $remainder)); + throw new TransformationFailedException(\sprintf('The number contains unrecognized characters: "%s".', $remainder)); } } diff --git a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php index d4d8aad9d4..8ae5e4c968 100644 --- a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php @@ -158,7 +158,7 @@ public function reverseTransform(mixed $value): int|float|null $remainder = trim($remainder, " \t\n\r\0\x0b\xc2\xa0"); if ('' !== $remainder) { - throw new TransformationFailedException(sprintf('The number contains unrecognized characters: "%s".', $remainder)); + throw new TransformationFailedException(\sprintf('The number contains unrecognized characters: "%s".', $remainder)); } } diff --git a/Extension/Core/DataTransformer/UlidToStringTransformer.php b/Extension/Core/DataTransformer/UlidToStringTransformer.php index 7ace73ad09..9365cab15e 100644 --- a/Extension/Core/DataTransformer/UlidToStringTransformer.php +++ b/Extension/Core/DataTransformer/UlidToStringTransformer.php @@ -65,7 +65,7 @@ public function reverseTransform(mixed $value): ?Ulid try { $ulid = new Ulid($value); } catch (\InvalidArgumentException $e) { - throw new TransformationFailedException(sprintf('The value "%s" is not a valid ULID.', $value), $e->getCode(), $e); + throw new TransformationFailedException(\sprintf('The value "%s" is not a valid ULID.', $value), $e->getCode(), $e); } return $ulid; diff --git a/Extension/Core/DataTransformer/UuidToStringTransformer.php b/Extension/Core/DataTransformer/UuidToStringTransformer.php index cc794a0247..43326eb644 100644 --- a/Extension/Core/DataTransformer/UuidToStringTransformer.php +++ b/Extension/Core/DataTransformer/UuidToStringTransformer.php @@ -63,13 +63,13 @@ public function reverseTransform(mixed $value): ?Uuid } if (!Uuid::isValid($value)) { - throw new TransformationFailedException(sprintf('The value "%s" is not a valid UUID.', $value)); + throw new TransformationFailedException(\sprintf('The value "%s" is not a valid UUID.', $value)); } try { return Uuid::fromString($value); } catch (\InvalidArgumentException $e) { - throw new TransformationFailedException(sprintf('The value "%s" is not a valid UUID.', $value), $e->getCode(), $e); + throw new TransformationFailedException(\sprintf('The value "%s" is not a valid UUID.', $value), $e->getCode(), $e); } } } diff --git a/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php b/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php index 9700b0424e..43ed176491 100644 --- a/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php +++ b/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php @@ -71,7 +71,7 @@ public function reverseTransform(mixed $array): mixed return null; } - throw new TransformationFailedException(sprintf('The keys "%s" should not be empty.', implode('", "', $emptyKeys))); + throw new TransformationFailedException(\sprintf('The keys "%s" should not be empty.', implode('", "', $emptyKeys))); } return $result; diff --git a/Extension/Core/DataTransformer/WeekToArrayTransformer.php b/Extension/Core/DataTransformer/WeekToArrayTransformer.php index c10bc735f6..448ae4278b 100644 --- a/Extension/Core/DataTransformer/WeekToArrayTransformer.php +++ b/Extension/Core/DataTransformer/WeekToArrayTransformer.php @@ -40,7 +40,7 @@ public function transform(mixed $value): array } if (!\is_string($value)) { - throw new TransformationFailedException(sprintf('Value is expected to be a string but was "%s".', get_debug_type($value))); + throw new TransformationFailedException(\sprintf('Value is expected to be a string but was "%s".', get_debug_type($value))); } if (0 === preg_match('/^(?P\d{4})-W(?P\d{2})$/', $value, $matches)) { @@ -70,7 +70,7 @@ public function reverseTransform(mixed $value): ?string } if (!\is_array($value)) { - throw new TransformationFailedException(sprintf('Value is expected to be an array, but was "%s".', get_debug_type($value))); + throw new TransformationFailedException(\sprintf('Value is expected to be an array, but was "%s".', get_debug_type($value))); } if (!\array_key_exists('year', $value)) { @@ -82,7 +82,7 @@ public function reverseTransform(mixed $value): ?string } if ($additionalKeys = array_diff(array_keys($value), ['year', 'week'])) { - throw new TransformationFailedException(sprintf('Expected only keys "year" and "week" to be present, but also got ["%s"].', implode('", "', $additionalKeys))); + throw new TransformationFailedException(\sprintf('Expected only keys "year" and "week" to be present, but also got ["%s"].', implode('", "', $additionalKeys))); } if (null === $value['year'] && null === $value['week']) { @@ -90,18 +90,18 @@ public function reverseTransform(mixed $value): ?string } if (!\is_int($value['year'])) { - throw new TransformationFailedException(sprintf('Year is expected to be an integer, but was "%s".', get_debug_type($value['year']))); + throw new TransformationFailedException(\sprintf('Year is expected to be an integer, but was "%s".', get_debug_type($value['year']))); } if (!\is_int($value['week'])) { - throw new TransformationFailedException(sprintf('Week is expected to be an integer, but was "%s".', get_debug_type($value['week']))); + throw new TransformationFailedException(\sprintf('Week is expected to be an integer, but was "%s".', get_debug_type($value['week']))); } // The 28th December is always in the last week of the year if (date('W', strtotime('28th December '.$value['year'])) < $value['week']) { - throw new TransformationFailedException(sprintf('Week "%d" does not exist for year "%d".', $value['week'], $value['year'])); + throw new TransformationFailedException(\sprintf('Week "%d" does not exist for year "%d".', $value['week'], $value['year'])); } - return sprintf('%d-W%02d', $value['year'], $value['week']); + return \sprintf('%d-W%02d', $value['year'], $value['week']); } } diff --git a/Extension/Core/Type/BaseType.php b/Extension/Core/Type/BaseType.php index 68190c742f..a7f745d78a 100644 --- a/Extension/Core/Type/BaseType.php +++ b/Extension/Core/Type/BaseType.php @@ -46,9 +46,9 @@ public function buildView(FormView $view, FormInterface $form, array $options): if ($view->parent) { if ('' !== ($parentFullName = $view->parent->vars['full_name'])) { - $id = sprintf('%s_%s', $view->parent->vars['id'], $name); - $fullName = sprintf('%s[%s]', $parentFullName, $name); - $uniqueBlockPrefix = sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName); + $id = \sprintf('%s_%s', $view->parent->vars['id'], $name); + $fullName = \sprintf('%s[%s]', $parentFullName, $name); + $uniqueBlockPrefix = \sprintf('%s_%s', $view->parent->vars['unique_block_prefix'], $blockName); } else { $id = $name; $fullName = $name; diff --git a/Extension/Core/Type/ChoiceType.php b/Extension/Core/Type/ChoiceType.php index 2e9cb7087f..36ebe6c840 100644 --- a/Extension/Core/Type/ChoiceType.php +++ b/Extension/Core/Type/ChoiceType.php @@ -158,7 +158,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void // Throw exception if unknown values were submitted (multiple choices will be handled in a different event listener below) if (\count($unknownValues) > 0 && !$options['multiple']) { - throw new TransformationFailedException(sprintf('The choices "%s" do not exist in the choice list.', implode('", "', array_keys($unknownValues)))); + throw new TransformationFailedException(\sprintf('The choices "%s" do not exist in the choice list.', implode('", "', array_keys($unknownValues)))); } $event->setData($knownValues); @@ -182,7 +182,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $message = strtr($messageTemplate, ['{{ value }}' => $clientDataAsString]); } - $form->addError(new FormError($message, $messageTemplate, ['{{ value }}' => $clientDataAsString], null, new TransformationFailedException(sprintf('The choices "%s" do not exist in the choice list.', $clientDataAsString)))); + $form->addError(new FormError($message, $messageTemplate, ['{{ value }}' => $clientDataAsString], null, new TransformationFailedException(\sprintf('The choices "%s" do not exist in the choice list.', $clientDataAsString)))); } }); diff --git a/Extension/Core/Type/CountryType.php b/Extension/Core/Type/CountryType.php index adef745c54..503bc8327e 100644 --- a/Extension/Core/Type/CountryType.php +++ b/Extension/Core/Type/CountryType.php @@ -27,7 +27,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults([ 'choice_loader' => function (Options $options) { if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); + throw new LogicException(\sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; diff --git a/Extension/Core/Type/CurrencyType.php b/Extension/Core/Type/CurrencyType.php index 3581a77d9b..abfa39729b 100644 --- a/Extension/Core/Type/CurrencyType.php +++ b/Extension/Core/Type/CurrencyType.php @@ -27,7 +27,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults([ 'choice_loader' => function (Options $options) { if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); + throw new LogicException(\sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; diff --git a/Extension/Core/Type/DateTimeType.php b/Extension/Core/Type/DateTimeType.php index 1c67eeb159..cf4c2b7416 100644 --- a/Extension/Core/Type/DateTimeType.php +++ b/Extension/Core/Type/DateTimeType.php @@ -203,7 +203,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void } if ($date->getTimezone()->getName() !== $options['model_timezone']) { - throw new LogicException(sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', get_debug_type($date), $date->getTimezone()->getName(), $options['model_timezone'])); + throw new LogicException(\sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', get_debug_type($date), $date->getTimezone()->getName(), $options['model_timezone'])); } }); } @@ -311,7 +311,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer('date_format', static function (Options $options, $dateFormat) { if (null !== $dateFormat && 'single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) { - throw new LogicException(sprintf('Cannot use the "date_format" option of the "%s" with an HTML5 date.', self::class)); + throw new LogicException(\sprintf('Cannot use the "date_format" option of the "%s" with an HTML5 date.', self::class)); } return $dateFormat; @@ -319,10 +319,10 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer('widget', static function (Options $options, $widget) { if ('single_text' === $widget) { if (null !== $options['date_widget']) { - throw new LogicException(sprintf('Cannot use the "date_widget" option of the "%s" when the "widget" option is set to "single_text".', self::class)); + throw new LogicException(\sprintf('Cannot use the "date_widget" option of the "%s" when the "widget" option is set to "single_text".', self::class)); } if (null !== $options['time_widget']) { - throw new LogicException(sprintf('Cannot use the "time_widget" option of the "%s" when the "widget" option is set to "single_text".', self::class)); + throw new LogicException(\sprintf('Cannot use the "time_widget" option of the "%s" when the "widget" option is set to "single_text".', self::class)); } } elseif (null === $widget && null === $options['date_widget'] && null === $options['time_widget']) { return 'single_text'; @@ -332,7 +332,7 @@ public function configureOptions(OptionsResolver $resolver): void }); $resolver->setNormalizer('html5', static function (Options $options, $html5) { if ($html5 && self::HTML5_FORMAT !== $options['format']) { - throw new LogicException(sprintf('Cannot use the "format" option of "%s" when the "html5" option is enabled.', self::class)); + throw new LogicException(\sprintf('Cannot use the "format" option of "%s" when the "html5" option is enabled.', self::class)); } return $html5; diff --git a/Extension/Core/Type/DateType.php b/Extension/Core/Type/DateType.php index cfbbaf4c0d..773a51cbdd 100644 --- a/Extension/Core/Type/DateType.php +++ b/Extension/Core/Type/DateType.php @@ -58,7 +58,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void if ('single_text' === $options['widget']) { if ('' !== $pattern && !str_contains($pattern, 'y') && !str_contains($pattern, 'M') && !str_contains($pattern, 'd')) { - throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" or "d". Its current value is "%s".', $pattern)); + throw new InvalidOptionsException(\sprintf('The "format" option should contain the letters "y", "M" or "d". Its current value is "%s".', $pattern)); } $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer( @@ -71,7 +71,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void )); } else { if ('' !== $pattern && (!str_contains($pattern, 'y') || !str_contains($pattern, 'M') || !str_contains($pattern, 'd'))) { - throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern)); + throw new InvalidOptionsException(\sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern)); } $yearOptions = $monthOptions = $dayOptions = [ @@ -187,7 +187,7 @@ class_exists(\IntlTimeZone::class, false) ? \IntlTimeZone::createDefault() : nul } if ($date->getTimezone()->getName() !== $options['model_timezone']) { - throw new LogicException(sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', get_debug_type($date), $date->getTimezone()->getName(), $options['model_timezone'])); + throw new LogicException(\sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', get_debug_type($date), $date->getTimezone()->getName(), $options['model_timezone'])); } }); } @@ -323,7 +323,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer('html5', static function (Options $options, $html5) { if ($html5 && 'single_text' === $options['widget'] && self::HTML5_FORMAT !== $options['format']) { - throw new LogicException(sprintf('Cannot use the "format" option of "%s" when the "html5" option is enabled.', self::class)); + throw new LogicException(\sprintf('Cannot use the "format" option of "%s" when the "html5" option is enabled.', self::class)); } return $html5; diff --git a/Extension/Core/Type/LanguageType.php b/Extension/Core/Type/LanguageType.php index e81571f8c4..638976a8cf 100644 --- a/Extension/Core/Type/LanguageType.php +++ b/Extension/Core/Type/LanguageType.php @@ -28,7 +28,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults([ 'choice_loader' => function (Options $options) { if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); + throw new LogicException(\sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; $useAlpha3Codes = $options['alpha3']; diff --git a/Extension/Core/Type/LocaleType.php b/Extension/Core/Type/LocaleType.php index d0124e6000..1529ca83f9 100644 --- a/Extension/Core/Type/LocaleType.php +++ b/Extension/Core/Type/LocaleType.php @@ -27,7 +27,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setDefaults([ 'choice_loader' => function (Options $options) { if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); + throw new LogicException(\sprintf('The "symfony/intl" component is required to use "%s". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; diff --git a/Extension/Core/Type/TimeType.php b/Extension/Core/Type/TimeType.php index 4e01489e73..ad559760d1 100644 --- a/Extension/Core/Type/TimeType.php +++ b/Extension/Core/Type/TimeType.php @@ -45,7 +45,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void } if (null !== $options['reference_date'] && $options['reference_date']->getTimezone()->getName() !== $options['model_timezone']) { - throw new InvalidConfigurationException(sprintf('The configured "model_timezone" (%s) must match the timezone of the "reference_date" (%s).', $options['model_timezone'], $options['reference_date']->getTimezone()->getName())); + throw new InvalidConfigurationException(\sprintf('The configured "model_timezone" (%s) must match the timezone of the "reference_date" (%s).', $options['model_timezone'], $options['reference_date']->getTimezone()->getName())); } if ($options['with_minutes']) { @@ -66,9 +66,9 @@ public function buildForm(FormBuilderInterface $builder, array $options): void if ($options['with_seconds']) { // handle seconds ignored by user's browser when with_seconds enabled // https://codereview.chromium.org/450533009/ - $e->setData(sprintf('%s:%s:%s', $matches['hours'], $matches['minutes'], $matches['seconds'] ?? '00')); + $e->setData(\sprintf('%s:%s:%s', $matches['hours'], $matches['minutes'], $matches['seconds'] ?? '00')); } else { - $e->setData(sprintf('%s:%s', $matches['hours'], $matches['minutes'])); + $e->setData(\sprintf('%s:%s', $matches['hours'], $matches['minutes'])); } } }); @@ -217,7 +217,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void } if ($date->getTimezone()->getName() !== $options['model_timezone']) { - throw new LogicException(sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', get_debug_type($date), $date->getTimezone()->getName(), $options['model_timezone'])); + throw new LogicException(\sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', get_debug_type($date), $date->getTimezone()->getName(), $options['model_timezone'])); } }); } diff --git a/Extension/Core/Type/TimezoneType.php b/Extension/Core/Type/TimezoneType.php index 01ce68ce37..2316d666b5 100644 --- a/Extension/Core/Type/TimezoneType.php +++ b/Extension/Core/Type/TimezoneType.php @@ -43,7 +43,7 @@ public function configureOptions(OptionsResolver $resolver): void if ($options['intl']) { if (!class_exists(Intl::class)) { - throw new LogicException(sprintf('The "symfony/intl" component is required to use "%s" with option "intl=true". Try running "composer require symfony/intl".', static::class)); + throw new LogicException(\sprintf('The "symfony/intl" component is required to use "%s" with option "intl=true". Try running "composer require symfony/intl".', static::class)); } $choiceTranslationLocale = $options['choice_translation_locale']; diff --git a/Extension/Core/Type/WeekType.php b/Extension/Core/Type/WeekType.php index c3ffae0617..ec5cc93037 100644 --- a/Extension/Core/Type/WeekType.php +++ b/Extension/Core/Type/WeekType.php @@ -145,7 +145,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); $resolver->setNormalizer('html5', static function (Options $options, $html5) { if ($html5 && 'single_text' !== $options['widget']) { - throw new LogicException(sprintf('The "widget" option of "%s" must be set to "single_text" when the "html5" option is enabled.', self::class)); + throw new LogicException(\sprintf('The "widget" option of "%s" must be set to "single_text" when the "html5" option is enabled.', self::class)); } return $html5; diff --git a/Extension/DataCollector/FormDataCollector.php b/Extension/DataCollector/FormDataCollector.php index 348be44aaa..e6cae863e8 100644 --- a/Extension/DataCollector/FormDataCollector.php +++ b/Extension/DataCollector/FormDataCollector.php @@ -64,7 +64,7 @@ public function __construct( private FormDataExtractorInterface $dataExtractor, ) { if (!class_exists(ClassStub::class)) { - throw new \LogicException(sprintf('The VarDumper component is needed for using the "%s" class. Install symfony/var-dumper version 3.4 or above.', __CLASS__)); + throw new \LogicException(\sprintf('The VarDumper component is needed for using the "%s" class. Install symfony/var-dumper version 3.4 or above.', __CLASS__)); } $this->reset(); diff --git a/Extension/DependencyInjection/DependencyInjectionExtension.php b/Extension/DependencyInjection/DependencyInjectionExtension.php index 420f26b743..f986bda415 100644 --- a/Extension/DependencyInjection/DependencyInjectionExtension.php +++ b/Extension/DependencyInjection/DependencyInjectionExtension.php @@ -37,7 +37,7 @@ public function __construct( public function getType(string $name): FormTypeInterface { if (!$this->typeContainer->has($name)) { - throw new InvalidArgumentException(sprintf('The field type "%s" is not registered in the service container.', $name)); + throw new InvalidArgumentException(\sprintf('The field type "%s" is not registered in the service container.', $name)); } return $this->typeContainer->get($name); @@ -63,7 +63,7 @@ public function getTypeExtensions(string $name): array // validate the result of getExtendedTypes() to ensure it is consistent with the service definition if (!\in_array($name, $extendedTypes, true)) { - throw new InvalidArgumentException(sprintf('The extended type "%s" specified for the type extension class "%s" does not match any of the actual extended types (["%s"]).', $name, $extension::class, implode('", "', $extendedTypes))); + throw new InvalidArgumentException(\sprintf('The extended type "%s" specified for the type extension class "%s" does not match any of the actual extended types (["%s"]).', $name, $extension::class, implode('", "', $extendedTypes))); } } } diff --git a/Extension/PasswordHasher/EventListener/PasswordHasherListener.php b/Extension/PasswordHasher/EventListener/PasswordHasherListener.php index 3ddac5ff35..0144cc3ffa 100644 --- a/Extension/PasswordHasher/EventListener/PasswordHasherListener.php +++ b/Extension/PasswordHasher/EventListener/PasswordHasherListener.php @@ -95,7 +95,7 @@ private function getUser(FormInterface $form): PasswordAuthenticatedUserInterfac $parent = $this->getTargetForm($form)->getParent(); if (!($user = $parent?->getData()) || !$user instanceof PasswordAuthenticatedUserInterface) { - throw new InvalidConfigurationException(sprintf('The "hash_property_path" option only supports "%s" objects, "%s" given.', PasswordAuthenticatedUserInterface::class, get_debug_type($user))); + throw new InvalidConfigurationException(\sprintf('The "hash_property_path" option only supports "%s" objects, "%s" given.', PasswordAuthenticatedUserInterface::class, get_debug_type($user))); } return $user; diff --git a/Extension/Validator/Constraints/FormValidator.php b/Extension/Validator/Constraints/FormValidator.php index 4163587576..703bac1484 100644 --- a/Extension/Validator/Constraints/FormValidator.php +++ b/Extension/Validator/Constraints/FormValidator.php @@ -92,7 +92,7 @@ public function validate(mixed $form, Constraint $formConstraint): void $fieldFormConstraint = new Form(); $fieldFormConstraint->groups = $group; $this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath()); - $validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint, $group); + $validator->atPath(\sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint, $group); } } @@ -139,7 +139,7 @@ public function validate(mixed $form, Constraint $formConstraint): void if ($field->isSubmitted()) { $this->resolvedGroups[$field] = $groups; $this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath()); - $validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $formConstraint); + $validator->atPath(\sprintf('children[%s]', $field->getName()))->validate($field, $formConstraint); } } } @@ -156,7 +156,7 @@ public function validate(mixed $form, Constraint $formConstraint): void if (!$child->isSynchronized()) { $childrenSynchronized = false; $this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath()); - $validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $formConstraint); + $validator->atPath(\sprintf('children[%s]', $child->getName()))->validate($child, $formConstraint); } } diff --git a/Extension/Validator/ValidatorTypeGuesser.php b/Extension/Validator/ValidatorTypeGuesser.php index 72ae8ddd57..08dc6e2d58 100644 --- a/Extension/Validator/ValidatorTypeGuesser.php +++ b/Extension/Validator/ValidatorTypeGuesser.php @@ -230,7 +230,7 @@ public function guessPatternForConstraint(Constraint $constraint): ?ValueGuess switch ($constraint::class) { case Length::class: if (is_numeric($constraint->min)) { - return new ValueGuess(sprintf('.{%s,}', (string) $constraint->min), Guess::LOW_CONFIDENCE); + return new ValueGuess(\sprintf('.{%s,}', (string) $constraint->min), Guess::LOW_CONFIDENCE); } break; @@ -244,7 +244,7 @@ public function guessPatternForConstraint(Constraint $constraint): ?ValueGuess case Range::class: if (is_numeric($constraint->min)) { - return new ValueGuess(sprintf('.{%s,}', \strlen((string) $constraint->min)), Guess::LOW_CONFIDENCE); + return new ValueGuess(\sprintf('.{%s,}', \strlen((string) $constraint->min)), Guess::LOW_CONFIDENCE); } break; diff --git a/Extension/Validator/ViolationMapper/MappingRule.php b/Extension/Validator/ViolationMapper/MappingRule.php index f9a61cc817..3263f66df2 100644 --- a/Extension/Validator/ViolationMapper/MappingRule.php +++ b/Extension/Validator/ViolationMapper/MappingRule.php @@ -64,7 +64,7 @@ public function getTarget(): FormInterface foreach ($childNames as $childName) { if (!$target->has($childName)) { - throw new ErrorMappingException(sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName())); + throw new ErrorMappingException(\sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName())); } $target = $target->get($childName); } diff --git a/Extension/Validator/ViolationMapper/ViolationPath.php b/Extension/Validator/ViolationMapper/ViolationPath.php index a9a0f15d6e..0c2a130cc8 100644 --- a/Extension/Validator/ViolationMapper/ViolationPath.php +++ b/Extension/Validator/ViolationMapper/ViolationPath.php @@ -132,7 +132,7 @@ public function getElements(): array public function getElement(int $index): string { if (!isset($this->elements[$index])) { - throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index)); + throw new OutOfBoundsException(\sprintf('The index "%s" is not within the violation path.', $index)); } return $this->elements[$index]; @@ -141,7 +141,7 @@ public function getElement(int $index): string public function isProperty(int $index): bool { if (!isset($this->isIndex[$index])) { - throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index)); + throw new OutOfBoundsException(\sprintf('The index "%s" is not within the violation path.', $index)); } return !$this->isIndex[$index]; @@ -150,7 +150,7 @@ public function isProperty(int $index): bool public function isIndex(int $index): bool { if (!isset($this->isIndex[$index])) { - throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index)); + throw new OutOfBoundsException(\sprintf('The index "%s" is not within the violation path.', $index)); } return $this->isIndex[$index]; @@ -176,7 +176,7 @@ public function isNullSafe(int $index): bool public function mapsForm(int $index): bool { if (!isset($this->mapsForm[$index])) { - throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index)); + throw new OutOfBoundsException(\sprintf('The index "%s" is not within the violation path.', $index)); } return $this->mapsForm[$index]; diff --git a/Form.php b/Form.php index 44b97261bd..72c60ee41a 100644 --- a/Form.php +++ b/Form.php @@ -738,7 +738,7 @@ public function add(FormInterface|string $child, ?string $type = null, array $op $child = $this->config->getFormFactory()->createNamed($child, $type, null, $options); } } elseif ($child->getConfig()->getAutoInitialize()) { - throw new RuntimeException(sprintf('Automatic initialization is only supported on root forms. You should set the "auto_initialize" option to false on the field "%s".', $child->getName())); + throw new RuntimeException(\sprintf('Automatic initialization is only supported on root forms. You should set the "auto_initialize" option to false on the field "%s".', $child->getName())); } $this->children[$child->getName()] = $child; @@ -800,7 +800,7 @@ public function get(string $name): FormInterface return $this->children[$name]; } - throw new OutOfBoundsException(sprintf('Child "%s" does not exist.', $name)); + throw new OutOfBoundsException(\sprintf('Child "%s" does not exist.', $name)); } /** @@ -933,7 +933,7 @@ private function modelToNorm(mixed $value): mixed $value = $transformer->transform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException(sprintf('Unable to transform data for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); + throw new TransformationFailedException(\sprintf('Unable to transform data for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; @@ -953,7 +953,7 @@ private function normToModel(mixed $value): mixed $value = $transformers[$i]->reverseTransform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException(sprintf('Unable to reverse value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); + throw new TransformationFailedException(\sprintf('Unable to reverse value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; @@ -980,7 +980,7 @@ private function normToView(mixed $value): mixed $value = $transformer->transform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException(sprintf('Unable to transform value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); + throw new TransformationFailedException(\sprintf('Unable to transform value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; @@ -1002,7 +1002,7 @@ private function viewToNorm(mixed $value): mixed $value = $transformers[$i]->reverseTransform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException(sprintf('Unable to reverse value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); + throw new TransformationFailedException(\sprintf('Unable to reverse value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; diff --git a/FormBuilder.php b/FormBuilder.php index 58bc9c86d9..2bfd92a688 100644 --- a/FormBuilder.php +++ b/FormBuilder.php @@ -97,7 +97,7 @@ public function get(string $name): FormBuilderInterface return $this->children[$name]; } - throw new InvalidArgumentException(sprintf('The child with the name "%s" does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The child with the name "%s" does not exist.', $name)); } public function remove(string $name): static diff --git a/FormConfigBuilder.php b/FormConfigBuilder.php index e0fb01dad9..5d6bd653d4 100644 --- a/FormConfigBuilder.php +++ b/FormConfigBuilder.php @@ -76,7 +76,7 @@ public function __construct( self::validateName($name); if (null !== $dataClass && !class_exists($dataClass) && !interface_exists($dataClass, false)) { - throw new InvalidArgumentException(sprintf('Class "%s" not found. Is the "data_class" form option set correctly?', $dataClass)); + throw new InvalidArgumentException(\sprintf('Class "%s" not found. Is the "data_class" form option set correctly?', $dataClass)); } $this->name = (string) $name; @@ -632,7 +632,7 @@ public function setIsEmptyCallback(?callable $isEmptyCallback): static final public static function validateName(?string $name): void { if (!self::isValidName($name)) { - throw new InvalidArgumentException(sprintf('The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").', $name)); + throw new InvalidArgumentException(\sprintf('The name "%s" contains illegal characters. Names should start with a letter, digit or underscore and only contain letters, digits, numbers, underscores ("_"), hyphens ("-") and colons (":").', $name)); } } diff --git a/FormErrorIterator.php b/FormErrorIterator.php index a614e72c2e..4f4a2574d2 100644 --- a/FormErrorIterator.php +++ b/FormErrorIterator.php @@ -58,7 +58,7 @@ public function __construct( ) { foreach ($errors as $error) { if (!($error instanceof FormError || $error instanceof self)) { - throw new InvalidArgumentException(sprintf('The errors must be instances of "Symfony\Component\Form\FormError" or "%s". Got: "%s".', __CLASS__, get_debug_type($error))); + throw new InvalidArgumentException(\sprintf('The errors must be instances of "Symfony\Component\Form\FormError" or "%s". Got: "%s".', __CLASS__, get_debug_type($error))); } } @@ -198,7 +198,7 @@ public function hasChildren(): bool public function getChildren(): self { if (!$this->hasChildren()) { - throw new LogicException(sprintf('The current element is not iterable. Use "%s" to get the current element.', self::class.'::current()')); + throw new LogicException(\sprintf('The current element is not iterable. Use "%s" to get the current element.', self::class.'::current()')); } /** @var self $children */ diff --git a/FormRegistry.php b/FormRegistry.php index 95a0077378..ecf654a2a3 100644 --- a/FormRegistry.php +++ b/FormRegistry.php @@ -69,10 +69,10 @@ public function getType(string $name): ResolvedFormTypeInterface if (!$type) { // Support fully-qualified class names if (!class_exists($name)) { - throw new InvalidArgumentException(sprintf('Could not load type "%s": class does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('Could not load type "%s": class does not exist.', $name)); } if (!is_subclass_of($name, FormTypeInterface::class)) { - throw new InvalidArgumentException(sprintf('Could not load type "%s": class does not implement "Symfony\Component\Form\FormTypeInterface".', $name)); + throw new InvalidArgumentException(\sprintf('Could not load type "%s": class does not implement "Symfony\Component\Form\FormTypeInterface".', $name)); } $type = new $name(); @@ -94,7 +94,7 @@ private function resolveType(FormTypeInterface $type): ResolvedFormTypeInterface if (isset($this->checkedTypes[$fqcn])) { $types = implode(' > ', array_merge(array_keys($this->checkedTypes), [$fqcn])); - throw new LogicException(sprintf('Circular reference detected for form type "%s" (%s).', $fqcn, $types)); + throw new LogicException(\sprintf('Circular reference detected for form type "%s" (%s).', $fqcn, $types)); } $this->checkedTypes[$fqcn] = true; diff --git a/FormRenderer.php b/FormRenderer.php index a9ffd4f41e..4478432b26 100644 --- a/FormRenderer.php +++ b/FormRenderer.php @@ -59,7 +59,7 @@ public function renderBlock(FormView $view, string $blockName, array $variables $resource = $this->engine->getResourceForBlockName($view, $blockName); if (!$resource) { - throw new LogicException(sprintf('No block "%s" found while rendering the form.', $blockName)); + throw new LogicException(\sprintf('No block "%s" found while rendering the form.', $blockName)); } $viewCacheKey = $view->vars[self::CACHE_KEY_VAR]; @@ -116,7 +116,7 @@ public function searchAndRenderBlock(FormView $view, string $blockNameSuffix, ar if ($renderOnlyOnce && $view->isRendered()) { // This is not allowed, because it would result in rendering same IDs multiple times, which is not valid. - throw new BadMethodCallException(sprintf('Field "%s" has already been rendered, save the result of previous render call to a variable and output that instead.', $view->vars['name'])); + throw new BadMethodCallException(\sprintf('Field "%s" has already been rendered, save the result of previous render call to a variable and output that instead.', $view->vars['name'])); } // The cache key for storing the variables and types @@ -203,10 +203,10 @@ public function searchAndRenderBlock(FormView $view, string $blockNameSuffix, ar // Escape if no resource exists for this block if (!$resource) { if (\count($blockNameHierarchy) !== \count(array_unique($blockNameHierarchy))) { - throw new LogicException(sprintf('Unable to render the form because the block names array contains duplicates: "%s".', implode('", "', array_reverse($blockNameHierarchy)))); + throw new LogicException(\sprintf('Unable to render the form because the block names array contains duplicates: "%s".', implode('", "', array_reverse($blockNameHierarchy)))); } - throw new LogicException(sprintf('Unable to render the form as none of the following blocks exist: "%s".', implode('", "', array_reverse($blockNameHierarchy)))); + throw new LogicException(\sprintf('Unable to render the form as none of the following blocks exist: "%s".', implode('", "', array_reverse($blockNameHierarchy)))); } // Merge the passed with the existing attributes diff --git a/PreloadedExtension.php b/PreloadedExtension.php index 58d8f13b1b..26090e00df 100644 --- a/PreloadedExtension.php +++ b/PreloadedExtension.php @@ -41,7 +41,7 @@ public function __construct( public function getType(string $name): FormTypeInterface { if (!isset($this->types[$name])) { - throw new InvalidArgumentException(sprintf('The type "%s" cannot be loaded by this extension.', $name)); + throw new InvalidArgumentException(\sprintf('The type "%s" cannot be loaded by this extension.', $name)); } return $this->types[$name]; diff --git a/ResolvedFormType.php b/ResolvedFormType.php index 964619c396..82065f6511 100644 --- a/ResolvedFormType.php +++ b/ResolvedFormType.php @@ -72,7 +72,7 @@ public function createBuilder(FormFactoryInterface $factory, string $name, array try { $options = $this->getOptionsResolver()->resolve($options); } catch (ExceptionInterface $e) { - throw new $e(sprintf('An error has occurred resolving the options of the form "%s": ', get_debug_type($this->getInnerType())).$e->getMessage(), $e->getCode(), $e); + throw new $e(\sprintf('An error has occurred resolving the options of the form "%s": ', get_debug_type($this->getInnerType())).$e->getMessage(), $e->getCode(), $e); } // Should be decoupled from the specific option at some point diff --git a/Test/FormPerformanceTestCase.php b/Test/FormPerformanceTestCase.php index 54ccc67cfd..1d631a2fde 100644 --- a/Test/FormPerformanceTestCase.php +++ b/Test/FormPerformanceTestCase.php @@ -34,7 +34,7 @@ protected function runTest(): mixed $time = microtime(true) - $s; if (0 != $this->maxRunningTime && $time > $this->maxRunningTime) { - $this->fail(sprintf('expected running time: <= %s but was: %s', $this->maxRunningTime, $time)); + $this->fail(\sprintf('expected running time: <= %s but was: %s', $this->maxRunningTime, $time)); } return $result; diff --git a/Test/Traits/ValidatorExtensionTrait.php b/Test/Traits/ValidatorExtensionTrait.php index b89095de72..5d0486e8cf 100644 --- a/Test/Traits/ValidatorExtensionTrait.php +++ b/Test/Traits/ValidatorExtensionTrait.php @@ -28,7 +28,7 @@ protected function getValidatorExtension(): ValidatorExtension } if (!$this instanceof TypeTestCase) { - throw new \Exception(sprintf('The trait "ValidatorExtensionTrait" can only be added to a class that extends "%s".', TypeTestCase::class)); + throw new \Exception(\sprintf('The trait "ValidatorExtensionTrait" can only be added to a class that extends "%s".', TypeTestCase::class)); } $this->validator = $this->createMock(ValidatorInterface::class); diff --git a/Tests/Console/Descriptor/AbstractDescriptorTestCase.php b/Tests/Console/Descriptor/AbstractDescriptorTestCase.php index fa8745b584..8a99c205cb 100644 --- a/Tests/Console/Descriptor/AbstractDescriptorTestCase.php +++ b/Tests/Console/Descriptor/AbstractDescriptorTestCase.php @@ -153,7 +153,7 @@ private function getExpectedDescription($name) private function getFixtureFilename($name) { - return sprintf('%s/../../Fixtures/Descriptor/%s.%s', __DIR__, $name, $this->getFormat()); + return \sprintf('%s/../../Fixtures/Descriptor/%s.%s', __DIR__, $name, $this->getFormat()); } } diff --git a/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php b/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php index 26055c203c..5d1e77eece 100644 --- a/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php +++ b/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php @@ -31,7 +31,7 @@ protected function getExtensions() { $translator = $this->createMock(TranslatorInterface::class); $translator->expects($this->any())->method('trans') - ->willReturnCallback(fn ($key, $params) => strtr(sprintf('Translation of: %s', $key), $params) + ->willReturnCallback(fn ($key, $params) => strtr(\sprintf('Translation of: %s', $key), $params) ); return array_merge(parent::getExtensions(), [new CoreExtension(null, null, $translator)]); diff --git a/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php b/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php index b99240c8cb..8f2cbdcd5d 100644 --- a/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php +++ b/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php @@ -44,7 +44,7 @@ public function testGetTypeExtensions() public function testThrowExceptionForInvalidExtendedType() { $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage(sprintf('The extended type "unmatched" specified for the type extension class "%s" does not match any of the actual extended types (["test"]).', TestTypeExtension::class)); + $this->expectExceptionMessage(\sprintf('The extended type "unmatched" specified for the type extension class "%s" does not match any of the actual extended types (["test"]).', TestTypeExtension::class)); $extensions = [ 'unmatched' => new \ArrayIterator([new TestTypeExtension()]), diff --git a/Tests/ResolvedFormTypeTest.php b/Tests/ResolvedFormTypeTest.php index ba0bf243d0..fa28f75472 100644 --- a/Tests/ResolvedFormTypeTest.php +++ b/Tests/ResolvedFormTypeTest.php @@ -100,7 +100,7 @@ public function testCreateBuilderWithDataClassOption() public function testFailsCreateBuilderOnInvalidFormOptionsResolution() { $this->expectException(MissingOptionsException::class); - $this->expectExceptionMessage(sprintf('An error has occurred resolving the options of the form "%s": The required option "foo" is missing.', UsageTrackingFormType::class)); + $this->expectExceptionMessage(\sprintf('An error has occurred resolving the options of the form "%s": The required option "foo" is missing.', UsageTrackingFormType::class)); $this->resolvedType->createBuilder($this->formFactory, 'name'); } diff --git a/Tests/Resources/TranslationFilesTest.php b/Tests/Resources/TranslationFilesTest.php index 3b2fe40f4d..157335dc6d 100644 --- a/Tests/Resources/TranslationFilesTest.php +++ b/Tests/Resources/TranslationFilesTest.php @@ -26,7 +26,7 @@ public function testTranslationFileIsValid($filePath) $errors = XliffUtils::validateSchema($document); - $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); + $this->assertCount(0, $errors, \sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); } /** @@ -39,7 +39,7 @@ public function testTranslationFileIsValidWithoutEntityLoader($filePath) $errors = XliffUtils::validateSchema($document); - $this->assertCount(0, $errors, sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); + $this->assertCount(0, $errors, \sprintf('"%s" is invalid:%s', $filePath, \PHP_EOL.implode(\PHP_EOL, array_column($errors, 'message')))); } public static function provideTranslationFiles() diff --git a/Tests/VersionAwareTest.php b/Tests/VersionAwareTest.php index 1a35b72fc0..90e0d10af6 100644 --- a/Tests/VersionAwareTest.php +++ b/Tests/VersionAwareTest.php @@ -18,7 +18,7 @@ trait VersionAwareTest protected function requiresFeatureSet(int $requiredFeatureSetVersion) { if ($requiredFeatureSetVersion > static::$supportedFeatureSetVersion) { - $this->markTestSkipped(sprintf('Test requires features from symfony/form %.2f but only version %.2f is supported.', $requiredFeatureSetVersion / 100, static::$supportedFeatureSetVersion / 100)); + $this->markTestSkipped(\sprintf('Test requires features from symfony/form %.2f but only version %.2f is supported.', $requiredFeatureSetVersion / 100, static::$supportedFeatureSetVersion / 100)); } } } diff --git a/Util/OrderedHashMap.php b/Util/OrderedHashMap.php index 145bd2e25e..7f81c07390 100644 --- a/Util/OrderedHashMap.php +++ b/Util/OrderedHashMap.php @@ -105,7 +105,7 @@ public function offsetExists(mixed $key): bool public function offsetGet(mixed $key): mixed { if (!isset($this->elements[$key])) { - throw new \OutOfBoundsException(sprintf('The offset "%s" does not exist.', $key)); + throw new \OutOfBoundsException(\sprintf('The offset "%s" does not exist.', $key)); } return $this->elements[$key]; From d131e439bb20f5c3d39cfde0b0d8eedf7c7a9fa5 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sun, 16 Jun 2024 17:17:26 +0200 Subject: [PATCH 20/70] chore: CS fixes --- AbstractTypeExtension.php | 3 -- FormTypeExtensionInterface.php | 3 -- .../Factory/DefaultChoiceListFactoryTest.php | 10 +++---- .../Loader/CallbackChoiceLoaderTest.php | 4 +-- Tests/Extension/Core/Type/ChoiceTypeTest.php | 4 +-- Tests/Extension/Core/Type/FormTypeTest.php | 18 +++++------ .../DataCollector/FormDataCollectorTest.php | 14 ++++----- .../FormValidatorFunctionalTest.php | 6 ++-- .../Constraints/FormValidatorTest.php | 30 +++++++++---------- Tests/NativeRequestHandlerTest.php | 4 +-- Tests/SimpleFormTest.php | 6 ++-- Tests/Util/StringUtilTest.php | 2 +- 12 files changed, 49 insertions(+), 55 deletions(-) diff --git a/AbstractTypeExtension.php b/AbstractTypeExtension.php index 9f6da0a336..b32f3b522f 100644 --- a/AbstractTypeExtension.php +++ b/AbstractTypeExtension.php @@ -18,9 +18,6 @@ */ abstract class AbstractTypeExtension implements FormTypeExtensionInterface { - /** - * @return void - */ public function configureOptions(OptionsResolver $resolver): void { } diff --git a/FormTypeExtensionInterface.php b/FormTypeExtensionInterface.php index 3e2d2d03e4..838406d2af 100644 --- a/FormTypeExtensionInterface.php +++ b/FormTypeExtensionInterface.php @@ -25,9 +25,6 @@ interface FormTypeExtensionInterface */ public static function getExtendedTypes(): iterable; - /** - * @return void - */ public function configureOptions(OptionsResolver $resolver): void; /** diff --git a/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php b/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php index e7bf26d178..f82fdc2f99 100644 --- a/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php +++ b/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php @@ -159,9 +159,9 @@ public function testCreateFromChoicesGroupedTraversable() { $list = $this->factory->createListFromChoices( new \ArrayIterator([ - 'Group 1' => ['A' => $this->obj1, 'B' => $this->obj2], - 'Group 2' => ['C' => $this->obj3, 'D' => $this->obj4], - ]) + 'Group 1' => ['A' => $this->obj1, 'B' => $this->obj2], + 'Group 2' => ['C' => $this->obj3, 'D' => $this->obj4], + ]) ); $this->assertObjectListWithGeneratedValues($list); @@ -941,7 +941,7 @@ private function assertFlatViewWithAttr($view) 'C', ['attr2' => 'value2'] ), - ] + ] ), $view); } @@ -987,7 +987,7 @@ private function assertGroupedView($view) 'Group 2', [2 => new ChoiceView($this->obj3, '2', 'C')] ), - ] + ] ), $view); } diff --git a/Tests/ChoiceList/Loader/CallbackChoiceLoaderTest.php b/Tests/ChoiceList/Loader/CallbackChoiceLoaderTest.php index d394196ee1..791a6f006e 100644 --- a/Tests/ChoiceList/Loader/CallbackChoiceLoaderTest.php +++ b/Tests/ChoiceList/Loader/CallbackChoiceLoaderTest.php @@ -69,8 +69,8 @@ public function testLoadChoicesForValuesLoadsChoiceListOnFirstCall() public function testLoadValuesForChoicesCastsCallbackItemsToString() { $choices = [ - (object) ['id' => 2], - (object) ['id' => 3], + (object) ['id' => 2], + (object) ['id' => 3], ]; $value = fn ($item) => $item->id; diff --git a/Tests/Extension/Core/Type/ChoiceTypeTest.php b/Tests/Extension/Core/Type/ChoiceTypeTest.php index 8e2372d7e1..c4f18734f8 100644 --- a/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -1895,8 +1895,8 @@ public function testInitializeWithEmptyChoices() { $this->assertInstanceOf( FormInterface::class, $this->factory->createNamed('name', static::TESTED_TYPE, null, [ - 'choices' => [], - ])); + 'choices' => [], + ])); } public function testInitializeWithDefaultObjectChoice() diff --git a/Tests/Extension/Core/Type/FormTypeTest.php b/Tests/Extension/Core/Type/FormTypeTest.php index be89c559f6..fe838885ed 100644 --- a/Tests/Extension/Core/Type/FormTypeTest.php +++ b/Tests/Extension/Core/Type/FormTypeTest.php @@ -156,24 +156,24 @@ public function testDataClassMayBeNull() { $this->assertInstanceOf( FormBuilderInterface::class, $this->factory->createBuilder(static::TESTED_TYPE, null, [ - 'data_class' => null, - ])); + 'data_class' => null, + ])); } public function testDataClassMayBeAbstractClass() { $this->assertInstanceOf( FormBuilderInterface::class, $this->factory->createBuilder(static::TESTED_TYPE, null, [ - 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\AbstractAuthor', - ])); + 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\AbstractAuthor', + ])); } public function testDataClassMayBeInterface() { $this->assertInstanceOf( FormBuilderInterface::class, $this->factory->createBuilder(static::TESTED_TYPE, null, [ - 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\AuthorInterface', - ])); + 'data_class' => 'Symfony\Component\Form\Tests\Fixtures\AuthorInterface', + ])); } public function testDataClassMustBeValidClassOrInterface() @@ -402,7 +402,7 @@ public function testSubformCallsSettersIfTheObjectChanged() // referenceCopy has a getter that returns a copy 'referenceCopy' => [ 'firstName' => 'Foo', - ], + ], ]); $this->assertEquals('Foo', $author->getReferenceCopy()->firstName); @@ -680,8 +680,8 @@ public function testDataMapperTransformationFailedExceptionInvalidMessageIsUsed( public function testPassZeroLabelToView() { $view = $this->factory->create(static::TESTED_TYPE, null, [ - 'label' => '0', - ]) + 'label' => '0', + ]) ->createView(); $this->assertSame('0', $view->vars['label']); diff --git a/Tests/Extension/DataCollector/FormDataCollectorTest.php b/Tests/Extension/DataCollector/FormDataCollectorTest.php index 798faa0c5e..0517b26c3b 100644 --- a/Tests/Extension/DataCollector/FormDataCollectorTest.php +++ b/Tests/Extension/DataCollector/FormDataCollectorTest.php @@ -71,7 +71,7 @@ public function testBuildPreliminaryFormTree() ], 'errors' => [], 'children' => [], - ]; + ]; $formData = [ 'id' => 'name', @@ -87,11 +87,11 @@ public function testBuildPreliminaryFormTree() 'norm' => null, ], 'errors' => [], - 'has_children_error' => false, - 'children' => [ - 'child' => $childFormData, - ], - ]; + 'has_children_error' => false, + 'children' => [ + 'child' => $childFormData, + ], + ]; $this->assertEquals([ 'forms' => [ @@ -102,7 +102,7 @@ public function testBuildPreliminaryFormTree() spl_object_hash($this->childForm) => $childFormData, ], 'nb_errors' => 0, - ], $this->dataCollector->getData()); + ], $this->dataCollector->getData()); } public function testBuildMultiplePreliminaryFormTrees() diff --git a/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php b/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php index aa6056c137..14595e8cf5 100644 --- a/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php +++ b/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php @@ -88,9 +88,9 @@ public function testFieldConstraintsInvalidateFormIfFieldIsSubmitted() public function testNonCompositeConstraintValidatedOnce() { $form = $this->formFactory->create(TextType::class, null, [ - 'constraints' => [new NotBlank(['groups' => ['foo', 'bar']])], - 'validation_groups' => ['foo', 'bar'], - ]); + 'constraints' => [new NotBlank(['groups' => ['foo', 'bar']])], + 'validation_groups' => ['foo', 'bar'], + ]); $form->submit(''); $violations = $this->validator->validate($form); diff --git a/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/Tests/Extension/Validator/Constraints/FormValidatorTest.php index 4e1588a9c7..86b53ac3ad 100644 --- a/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -184,8 +184,8 @@ public function testDontValidateIfNoValidationGroups() $object = new \stdClass(); $form = $this->getBuilder('name', '\stdClass', [ - 'validation_groups' => [], - ]) + 'validation_groups' => [], + ]) ->setData($object) ->setCompound(true) ->setDataMapper(new DataMapper()) @@ -256,12 +256,12 @@ public function testDontValidateIfNotSynchronized() $object = new \stdClass(); $form = $this->getBuilder('name', '\stdClass', [ - 'invalid_message' => 'invalid_message_key', - // Invalid message parameters must be supported, because the - // invalid message can be a translation key - // see https://github.com/symfony/symfony/issues/5144 - 'invalid_message_parameters' => ['{{ foo }}' => 'bar'], - ]) + 'invalid_message' => 'invalid_message_key', + // Invalid message parameters must be supported, because the + // invalid message can be a translation key + // see https://github.com/symfony/symfony/issues/5144 + 'invalid_message_parameters' => ['{{ foo }}' => 'bar'], + ]) ->setData($object) ->addViewTransformer(new CallbackTransformer( static fn ($data) => $data, @@ -292,13 +292,13 @@ public function testAddInvalidErrorEvenIfNoValidationGroups() $object = new \stdClass(); $form = $this->getBuilder('name', '\stdClass', [ - 'invalid_message' => 'invalid_message_key', - // Invalid message parameters must be supported, because the - // invalid message can be a translation key - // see https://github.com/symfony/symfony/issues/5144 - 'invalid_message_parameters' => ['{{ foo }}' => 'bar'], - 'validation_groups' => [], - ]) + 'invalid_message' => 'invalid_message_key', + // Invalid message parameters must be supported, because the + // invalid message can be a translation key + // see https://github.com/symfony/symfony/issues/5144 + 'invalid_message_parameters' => ['{{ foo }}' => 'bar'], + 'validation_groups' => [], + ]) ->setData($object) ->addViewTransformer(new CallbackTransformer( static fn ($data) => $data, diff --git a/Tests/NativeRequestHandlerTest.php b/Tests/NativeRequestHandlerTest.php index 679c3366d8..3770e12199 100644 --- a/Tests/NativeRequestHandlerTest.php +++ b/Tests/NativeRequestHandlerTest.php @@ -172,8 +172,8 @@ public function testMethodOverrideHeaderIgnoredIfNotPost() $form = $this->createForm('param1', 'POST'); $this->setRequestData('GET', [ - 'param1' => 'DATA', - ]); + 'param1' => 'DATA', + ]); $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT'; diff --git a/Tests/SimpleFormTest.php b/Tests/SimpleFormTest.php index 7ded9b8535..d5d3549d2a 100644 --- a/Tests/SimpleFormTest.php +++ b/Tests/SimpleFormTest.php @@ -503,9 +503,9 @@ public function testSetDataConvertsScalarToStringIfOnlyModelTransformer() { $form = $this->getBuilder() ->addModelTransformer(new FixedDataTransformer([ - '' => '', - 1 => 23, - ])) + '' => '', + 1 => 23, + ])) ->getForm(); $form->setData(1); diff --git a/Tests/Util/StringUtilTest.php b/Tests/Util/StringUtilTest.php index 8199d6843e..d51481f6c1 100644 --- a/Tests/Util/StringUtilTest.php +++ b/Tests/Util/StringUtilTest.php @@ -56,7 +56,7 @@ public static function spaceProvider(): array ['0020'], ['00A0'], ['1680'], -// ['180E'], + // ['180E'], ['2000'], ['2001'], ['2002'], From 717223d83e3a1df104d0fe989b6f43c15c8e44b9 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 25 Jun 2024 14:58:00 +0200 Subject: [PATCH 21/70] Add more precise types in reusable test cases --- Test/FormIntegrationTestCase.php | 16 ++++++++++++++++ Test/TypeTestCase.php | 10 ++++++++++ .../Core/Type/ChoiceTypeTranslationTest.php | 2 +- Tests/Extension/Core/Type/FileTypeTest.php | 2 +- .../Csrf/Type/FormTypeCsrfExtensionTest.php | 2 +- .../Type/TextTypeHtmlSanitizerExtensionTest.php | 2 +- .../PasswordTypePasswordHasherExtensionTest.php | 2 +- .../Constraints/FormValidatorPerformanceTest.php | 2 +- 8 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Test/FormIntegrationTestCase.php b/Test/FormIntegrationTestCase.php index 5bf37fd48a..8756d99689 100644 --- a/Test/FormIntegrationTestCase.php +++ b/Test/FormIntegrationTestCase.php @@ -12,8 +12,12 @@ namespace Symfony\Component\Form\Test; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\FormExtensionInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\Forms; +use Symfony\Component\Form\FormTypeExtensionInterface; +use Symfony\Component\Form\FormTypeGuesserInterface; +use Symfony\Component\Form\FormTypeInterface; /** * @author Bernhard Schussek @@ -32,21 +36,33 @@ protected function setUp(): void ->getFormFactory(); } + /** + * @return FormExtensionInterface[] + */ protected function getExtensions() { return []; } + /** + * @return FormTypeExtensionInterface[] + */ protected function getTypeExtensions() { return []; } + /** + * @return FormTypeInterface[] + */ protected function getTypes() { return []; } + /** + * @return FormTypeGuesserInterface[] + */ protected function getTypeGuessers() { return []; diff --git a/Test/TypeTestCase.php b/Test/TypeTestCase.php index 960b44228b..1bbb66d25d 100644 --- a/Test/TypeTestCase.php +++ b/Test/TypeTestCase.php @@ -13,6 +13,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormExtensionInterface; use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait; abstract class TypeTestCase extends FormIntegrationTestCase @@ -28,6 +29,9 @@ protected function setUp(): void $this->builder = new FormBuilder('', null, $this->dispatcher, $this->factory); } + /** + * @return FormExtensionInterface[] + */ protected function getExtensions() { $extensions = []; @@ -39,11 +43,17 @@ protected function getExtensions() return $extensions; } + /** + * @return void + */ public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual) { self::assertEquals($expected->format('c'), $actual->format('c')); } + /** + * @return void + */ public static function assertDateIntervalEquals(\DateInterval $expected, \DateInterval $actual) { self::assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS')); diff --git a/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php b/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php index 5d1e77eece..af58e2ecfa 100644 --- a/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php +++ b/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php @@ -27,7 +27,7 @@ class ChoiceTypeTranslationTest extends TypeTestCase 'Roman' => 'e', ]; - protected function getExtensions() + protected function getExtensions(): array { $translator = $this->createMock(TranslatorInterface::class); $translator->expects($this->any())->method('trans') diff --git a/Tests/Extension/Core/Type/FileTypeTest.php b/Tests/Extension/Core/Type/FileTypeTest.php index b7f3332c1e..9c3a8efd0a 100644 --- a/Tests/Extension/Core/Type/FileTypeTest.php +++ b/Tests/Extension/Core/Type/FileTypeTest.php @@ -23,7 +23,7 @@ class FileTypeTest extends BaseTypeTestCase { public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\FileType'; - protected function getExtensions() + protected function getExtensions(): array { return array_merge(parent::getExtensions(), [new CoreExtension(null, null, new IdentityTranslator())]); } diff --git a/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php b/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php index bfa3025554..d5bce6527b 100644 --- a/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php +++ b/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php @@ -42,7 +42,7 @@ protected function setUp(): void parent::setUp(); } - protected function getExtensions() + protected function getExtensions(): array { return array_merge(parent::getExtensions(), [ new CsrfExtension($this->tokenManager, new IdentityTranslator()), diff --git a/Tests/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtensionTest.php b/Tests/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtensionTest.php index 39b8d03323..6784576b05 100644 --- a/Tests/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtensionTest.php +++ b/Tests/Extension/HtmlSanitizer/Type/TextTypeHtmlSanitizerExtensionTest.php @@ -20,7 +20,7 @@ class TextTypeHtmlSanitizerExtensionTest extends TypeTestCase { - protected function getExtensions() + protected function getExtensions(): array { $fooSanitizer = $this->createMock(HtmlSanitizerInterface::class); $fooSanitizer->expects($this->once()) diff --git a/Tests/Extension/PasswordHasher/Type/PasswordTypePasswordHasherExtensionTest.php b/Tests/Extension/PasswordHasher/Type/PasswordTypePasswordHasherExtensionTest.php index 4ec91c8274..07d1292a3f 100644 --- a/Tests/Extension/PasswordHasher/Type/PasswordTypePasswordHasherExtensionTest.php +++ b/Tests/Extension/PasswordHasher/Type/PasswordTypePasswordHasherExtensionTest.php @@ -40,7 +40,7 @@ protected function setUp(): void parent::setUp(); } - protected function getExtensions() + protected function getExtensions(): array { return array_merge(parent::getExtensions(), [ new PasswordHasherExtension(new PasswordHasherListener($this->passwordHasher)), diff --git a/Tests/Extension/Validator/Constraints/FormValidatorPerformanceTest.php b/Tests/Extension/Validator/Constraints/FormValidatorPerformanceTest.php index e8bfbc64ae..b0c7d719ae 100644 --- a/Tests/Extension/Validator/Constraints/FormValidatorPerformanceTest.php +++ b/Tests/Extension/Validator/Constraints/FormValidatorPerformanceTest.php @@ -20,7 +20,7 @@ */ class FormValidatorPerformanceTest extends FormPerformanceTestCase { - protected function getExtensions() + protected function getExtensions(): array { return [ new ValidatorExtension(Validation::createValidator(), false), From 8c1030ce9365f4e2885c55149991aae266159347 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 25 Jun 2024 08:08:32 +0200 Subject: [PATCH 22/70] Unify how --format is handle by commands --- Command/DebugCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Command/DebugCommand.php b/Command/DebugCommand.php index 18d208cbe8..91db6f1a91 100644 --- a/Command/DebugCommand.php +++ b/Command/DebugCommand.php @@ -272,6 +272,7 @@ private function completeOptions(string $class, CompletionSuggestions $suggestio $suggestions->suggestValues($resolvedType->getOptionsResolver()->getDefinedOptions()); } + /** @return string[] */ private function getAvailableFormatOptions(): array { return (new DescriptorHelper())->getFormats(); From a1664a2508e19556bf20e2c5a6e0fe8483eec4c9 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 6 Jul 2024 09:57:16 +0200 Subject: [PATCH 23/70] Update .gitattributes --- .gitattributes | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 84c7add058..14c3c35940 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ /Tests export-ignore /phpunit.xml.dist export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore +/.git* export-ignore From f63434d11b165831a089e0b90f74582184ec9679 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 18 Jul 2024 10:20:59 +0200 Subject: [PATCH 24/70] [Validator] Use CPP in `ConstraintViolation` --- Tests/Extension/DataCollector/FormDataExtractorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Extension/DataCollector/FormDataExtractorTest.php b/Tests/Extension/DataCollector/FormDataExtractorTest.php index ec01721c70..4aa9cf4d2f 100644 --- a/Tests/Extension/DataCollector/FormDataExtractorTest.php +++ b/Tests/Extension/DataCollector/FormDataExtractorTest.php @@ -314,12 +314,12 @@ public function testExtractSubmittedDataStoresErrorCause() -message: "Foo" -messageTemplate: "Foo" -parameters: [] - -plural: null -root: "Root" -propertyPath: "property.path" -invalidValue: "Invalid!" - -constraint: null + -plural: null -code: null + -constraint: null -cause: Exception {%A} } 1 => Exception {#1} From 2b2fc826310d853594889c3c4ab9cd619170c932 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 13 Apr 2024 14:18:00 +0200 Subject: [PATCH 25/70] [PhpUnitBridge] Add ExpectUserDeprecationMessageTrait --- Tests/Extension/Core/Type/UrlTypeTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Extension/Core/Type/UrlTypeTest.php b/Tests/Extension/Core/Type/UrlTypeTest.php index 28e8b9ac74..243d15297c 100644 --- a/Tests/Extension/Core/Type/UrlTypeTest.php +++ b/Tests/Extension/Core/Type/UrlTypeTest.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; -use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; +use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; class UrlTypeTest extends TextTypeTest { - use ExpectDeprecationTrait; + use ExpectUserDeprecationMessageTrait; public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\UrlType'; @@ -25,7 +25,7 @@ class UrlTypeTest extends TextTypeTest */ public function testSubmitAddsDefaultProtocolIfNoneIsIncluded() { - $this->expectDeprecation('Since symfony/form 7.1: Not configuring the "default_protocol" option when using the UrlType is deprecated. It will default to "null" in 8.0.'); + $this->expectUserDeprecationMessage('Since symfony/form 7.1: Not configuring the "default_protocol" option when using the UrlType is deprecated. It will default to "null" in 8.0.'); $form = $this->factory->create(static::TESTED_TYPE, 'name'); $form->submit('www.domain.com'); From 56575c475e10066cfb3c580a2e911b8d4df92efe Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 22 Jul 2024 10:27:43 +0200 Subject: [PATCH 26/70] Use CPP where possible --- ChoiceList/Factory/CachingFactoryDecorator.php | 8 +++----- ChoiceList/Factory/PropertyAccessDecorator.php | 8 ++++---- .../DataTransformer/BooleanToStringTransformer.php | 12 ++++-------- Extension/Core/Type/ChoiceType.php | 8 ++++---- 4 files changed, 15 insertions(+), 21 deletions(-) diff --git a/ChoiceList/Factory/CachingFactoryDecorator.php b/ChoiceList/Factory/CachingFactoryDecorator.php index 687fcec1ee..1f373228b5 100644 --- a/ChoiceList/Factory/CachingFactoryDecorator.php +++ b/ChoiceList/Factory/CachingFactoryDecorator.php @@ -27,8 +27,6 @@ */ class CachingFactoryDecorator implements ChoiceListFactoryInterface, ResetInterface { - private ChoiceListFactoryInterface $decoratedFactory; - /** * @var ChoiceListInterface[] */ @@ -64,9 +62,9 @@ public static function generateHash(mixed $value, string $namespace = ''): strin return hash('sha256', $namespace.':'.serialize($value)); } - public function __construct(ChoiceListFactoryInterface $decoratedFactory) - { - $this->decoratedFactory = $decoratedFactory; + public function __construct( + private ChoiceListFactoryInterface $decoratedFactory, + ) { } /** diff --git a/ChoiceList/Factory/PropertyAccessDecorator.php b/ChoiceList/Factory/PropertyAccessDecorator.php index c83ef17e9f..f73a8fc2aa 100644 --- a/ChoiceList/Factory/PropertyAccessDecorator.php +++ b/ChoiceList/Factory/PropertyAccessDecorator.php @@ -38,12 +38,12 @@ */ class PropertyAccessDecorator implements ChoiceListFactoryInterface { - private ChoiceListFactoryInterface $decoratedFactory; private PropertyAccessorInterface $propertyAccessor; - public function __construct(ChoiceListFactoryInterface $decoratedFactory, ?PropertyAccessorInterface $propertyAccessor = null) - { - $this->decoratedFactory = $decoratedFactory; + public function __construct( + private ChoiceListFactoryInterface $decoratedFactory, + ?PropertyAccessorInterface $propertyAccessor = null, + ) { $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); } diff --git a/Extension/Core/DataTransformer/BooleanToStringTransformer.php b/Extension/Core/DataTransformer/BooleanToStringTransformer.php index e91bdb4dbf..7ef84bb448 100644 --- a/Extension/Core/DataTransformer/BooleanToStringTransformer.php +++ b/Extension/Core/DataTransformer/BooleanToStringTransformer.php @@ -25,17 +25,13 @@ */ class BooleanToStringTransformer implements DataTransformerInterface { - private string $trueValue; - - private array $falseValues; - /** * @param string $trueValue The value emitted upon transform if the input is true */ - public function __construct(string $trueValue, array $falseValues = [null]) - { - $this->trueValue = $trueValue; - $this->falseValues = $falseValues; + public function __construct( + private string $trueValue, + private array $falseValues = [null], + ) { if (\in_array($this->trueValue, $this->falseValues, true)) { throw new InvalidArgumentException('The specified "true" value is contained in the false-values.'); } diff --git a/Extension/Core/Type/ChoiceType.php b/Extension/Core/Type/ChoiceType.php index 36ebe6c840..0042d75805 100644 --- a/Extension/Core/Type/ChoiceType.php +++ b/Extension/Core/Type/ChoiceType.php @@ -51,16 +51,16 @@ class ChoiceType extends AbstractType { private ChoiceListFactoryInterface $choiceListFactory; - private ?TranslatorInterface $translator; - public function __construct(?ChoiceListFactoryInterface $choiceListFactory = null, ?TranslatorInterface $translator = null) - { + public function __construct( + ?ChoiceListFactoryInterface $choiceListFactory = null, + private ?TranslatorInterface $translator = null, + ) { $this->choiceListFactory = $choiceListFactory ?? new CachingFactoryDecorator( new PropertyAccessDecorator( new DefaultChoiceListFactory() ) ); - $this->translator = $translator; } public function buildForm(FormBuilderInterface $builder, array $options): void From 7b9c1292dbcd0f47e741fc4bb7c6e95a930458d5 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 26 Jul 2024 13:12:13 +0200 Subject: [PATCH 27/70] [Form] Deprecate VersionAwareTest trait --- CHANGELOG.md | 5 +++++ Tests/Extension/Core/Type/BaseTypeTestCase.php | 16 ---------------- Tests/VersionAwareTest.php | 8 ++++++++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0420af3413..631041da40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.2 +--- + + * Deprecate the `VersionAwareTest` trait, use feature detection instead + 7.1 --- diff --git a/Tests/Extension/Core/Type/BaseTypeTestCase.php b/Tests/Extension/Core/Type/BaseTypeTestCase.php index 5238e2fd88..14b602a4b4 100644 --- a/Tests/Extension/Core/Type/BaseTypeTestCase.php +++ b/Tests/Extension/Core/Type/BaseTypeTestCase.php @@ -114,8 +114,6 @@ public function testDefaultTranslationDomain() public function testPassLabelTranslationParametersToView() { - $this->requiresFeatureSet(403); - $view = $this->factory->create($this->getTestedType(), null, array_merge($this->getTestOptions(), [ 'label_translation_parameters' => ['%param%' => 'value'], ])) @@ -126,8 +124,6 @@ public function testPassLabelTranslationParametersToView() public function testPassAttrTranslationParametersToView() { - $this->requiresFeatureSet(403); - $view = $this->factory->create($this->getTestedType(), null, array_merge($this->getTestOptions(), [ 'attr_translation_parameters' => ['%param%' => 'value'], ])) @@ -138,8 +134,6 @@ public function testPassAttrTranslationParametersToView() public function testInheritLabelTranslationParametersFromParent() { - $this->requiresFeatureSet(403); - $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'label_translation_parameters' => ['%param%' => 'value'], @@ -153,8 +147,6 @@ public function testInheritLabelTranslationParametersFromParent() public function testInheritAttrTranslationParametersFromParent() { - $this->requiresFeatureSet(403); - $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'attr_translation_parameters' => ['%param%' => 'value'], @@ -168,8 +160,6 @@ public function testInheritAttrTranslationParametersFromParent() public function testPreferOwnLabelTranslationParameters() { - $this->requiresFeatureSet(403); - $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'label_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], @@ -185,8 +175,6 @@ public function testPreferOwnLabelTranslationParameters() public function testPreferOwnAttrTranslationParameters() { - $this->requiresFeatureSet(403); - $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'attr_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], @@ -202,8 +190,6 @@ public function testPreferOwnAttrTranslationParameters() public function testDefaultLabelTranslationParameters() { - $this->requiresFeatureSet(403); - $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) ->add('child', $this->getTestedType(), $this->getTestOptions()) ->getForm() @@ -214,8 +200,6 @@ public function testDefaultLabelTranslationParameters() public function testDefaultAttrTranslationParameters() { - $this->requiresFeatureSet(403); - $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) ->add('child', $this->getTestedType(), $this->getTestOptions()) ->getForm() diff --git a/Tests/VersionAwareTest.php b/Tests/VersionAwareTest.php index 90e0d10af6..530c174739 100644 --- a/Tests/VersionAwareTest.php +++ b/Tests/VersionAwareTest.php @@ -11,12 +11,20 @@ namespace Symfony\Component\Form\Tests; +/** + * @deprecated since Symfony 7.2, use feature detection instead. + */ trait VersionAwareTest { protected static int $supportedFeatureSetVersion = 404; + /** + * @deprecated since Symfony 7.2, use feature detection instead. + */ protected function requiresFeatureSet(int $requiredFeatureSetVersion) { + trigger_deprecation('symfony/form', '7.2', 'The "%s" trait is deprecated, use feature detection instead.', VersionAwareTest::class); + if ($requiredFeatureSetVersion > static::$supportedFeatureSetVersion) { $this->markTestSkipped(\sprintf('Test requires features from symfony/form %.2f but only version %.2f is supported.', $requiredFeatureSetVersion / 100, static::$supportedFeatureSetVersion / 100)); } From b2a3f779d67f476600f6e45524fb9d0e03bf5aac Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 31 Jul 2024 16:13:26 +0200 Subject: [PATCH 28/70] Remove unused code and unnecessary `else` branches --- .../Core/DataTransformer/DateIntervalToArrayTransformer.php | 3 +-- .../DataTransformer/NumberToLocalizedStringTransformer.php | 4 +--- .../DataTransformer/PercentToLocalizedStringTransformer.php | 4 +--- Extension/Core/Type/ChoiceType.php | 4 ++-- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php b/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php index 0475b55bfd..18679a9103 100644 --- a/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php +++ b/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php @@ -93,9 +93,8 @@ public function transform(mixed $dateInterval): array } } $result['invert'] = '-' === $result['invert']; - $result = array_intersect_key($result, array_flip($this->fields)); - return $result; + return array_intersect_key($result, array_flip($this->fields)); } /** diff --git a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index 2a6d146f90..dc108de796 100644 --- a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -64,9 +64,7 @@ public function transform(mixed $value): string } // Convert non-breaking and narrow non-breaking spaces to normal ones - $value = str_replace(["\xc2\xa0", "\xe2\x80\xaf"], ' ', $value); - - return $value; + return str_replace(["\xc2\xa0", "\xe2\x80\xaf"], ' ', $value); } /** diff --git a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php index 8ae5e4c968..3b103b49b3 100644 --- a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php @@ -210,8 +210,6 @@ private function round(int|float $number): int|float \NumberFormatter::ROUND_HALFDOWN => round($number, 0, \PHP_ROUND_HALF_DOWN), }; - $number = 1 === $roundingCoef ? (int) $number : $number / $roundingCoef; - - return $number; + return 1 === $roundingCoef ? (int) $number : $number / $roundingCoef; } } diff --git a/Extension/Core/Type/ChoiceType.php b/Extension/Core/Type/ChoiceType.php index 0042d75805..d0a1b6e06f 100644 --- a/Extension/Core/Type/ChoiceType.php +++ b/Extension/Core/Type/ChoiceType.php @@ -141,9 +141,9 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $knownValues[$child->getName()] = $value; unset($unknownValues[$value]); continue; - } else { - $knownValues[$child->getName()] = null; } + + $knownValues[$child->getName()] = null; } } else { foreach ($choiceList->getChoicesForValues($data) as $key => $choice) { From 669faf533c2e714e769f3c9dfdc175237e5fae6d Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 5 Aug 2024 09:12:25 +0200 Subject: [PATCH 29/70] Fix multiple CS errors --- Tests/Extension/DataCollector/FormDataExtractorTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/Extension/DataCollector/FormDataExtractorTest.php b/Tests/Extension/DataCollector/FormDataExtractorTest.php index b8a1fee374..29f9359df8 100644 --- a/Tests/Extension/DataCollector/FormDataExtractorTest.php +++ b/Tests/Extension/DataCollector/FormDataExtractorTest.php @@ -362,8 +362,7 @@ public function testExtractSubmittedDataStoresErrorCause() ] EODUMP; } - $this->assertDumpMatchesFormat($expectedFormat - , + $this->assertDumpMatchesFormat($expectedFormat, $this->dataExtractor->extractSubmittedData($form) ); } From 02f1d9fd95ab79ad84428b7d4e9658a054bba334 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 5 Aug 2024 10:28:33 +0200 Subject: [PATCH 30/70] fix handling empty data in ValueToDuplicatesTransformer The transformer receives the data of child forms that have already been through the transformation schema. If no custom view transformer was used on that child form the empty would already have been changed to null. Thus, receiving an empty string here means that the child form explicitly asked for it and the value must not be exchanged with null. --- .../ValueToDuplicatesTransformer.php | 2 +- .../ValueToDuplicatesTransformerTest.php | 2 +- .../Extension/Core/Type/RepeatedTypeTest.php | 31 +++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php b/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php index 5249e3b364..8dd5acb616 100644 --- a/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php +++ b/Extension/Core/DataTransformer/ValueToDuplicatesTransformer.php @@ -62,7 +62,7 @@ public function reverseTransform($array) $emptyKeys = []; foreach ($this->keys as $key) { - if (isset($array[$key]) && '' !== $array[$key] && false !== $array[$key] && [] !== $array[$key]) { + if (isset($array[$key]) && false !== $array[$key] && [] !== $array[$key]) { if ($array[$key] !== $result) { throw new TransformationFailedException('All values in the array should be the same.'); } diff --git a/Tests/Extension/Core/DataTransformer/ValueToDuplicatesTransformerTest.php b/Tests/Extension/Core/DataTransformer/ValueToDuplicatesTransformerTest.php index fdfd983576..462472da98 100644 --- a/Tests/Extension/Core/DataTransformer/ValueToDuplicatesTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/ValueToDuplicatesTransformerTest.php @@ -70,7 +70,7 @@ public function testReverseTransformCompletelyEmpty() 'c' => '', ]; - $this->assertNull($this->transformer->reverseTransform($input)); + $this->assertSame('', $this->transformer->reverseTransform($input)); } public function testReverseTransformCompletelyNull() diff --git a/Tests/Extension/Core/Type/RepeatedTypeTest.php b/Tests/Extension/Core/Type/RepeatedTypeTest.php index b2a295b276..ca0de12233 100644 --- a/Tests/Extension/Core/Type/RepeatedTypeTest.php +++ b/Tests/Extension/Core/Type/RepeatedTypeTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Form; use Symfony\Component\Form\Tests\Fixtures\NotMappedType; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; @@ -191,6 +192,36 @@ public function testSetOptionsPerChildAndOverwrite() $this->assertTrue($form['second']->isRequired()); } + /** + * @dataProvider emptyDataProvider + */ + public function testSubmitNullForTextTypeWithEmptyDataOptionSetToEmptyString($emptyData, $submittedData, $expected) + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'type' => TextType::class, + 'options' => [ + 'empty_data' => $emptyData, + ] + ]); + $form->submit($submittedData); + + $this->assertSame($expected, $form->getData()); + } + + public static function emptyDataProvider() + { + yield ['', null, '']; + yield ['', ['first' => null, 'second' => null], '']; + yield ['', ['first' => '', 'second' => null], '']; + yield ['', ['first' => null, 'second' => ''], '']; + yield ['', ['first' => '', 'second' => ''], '']; + yield [null, null, null]; + yield [null, ['first' => null, 'second' => null], null]; + yield [null, ['first' => '', 'second' => null], null]; + yield [null, ['first' => null, 'second' => ''], null]; + yield [null, ['first' => '', 'second' => ''], null]; + } + public function testSubmitUnequal() { $input = ['first' => 'foo', 'second' => 'bar']; From 1824d39c04d9ea22231c23a5955c95b1c96bd592 Mon Sep 17 00:00:00 2001 From: Roy de Vos Burchart Date: Thu, 1 Aug 2024 17:21:17 +0200 Subject: [PATCH 31/70] Code style change in `@PER-CS2.0` affecting `@Symfony` (parentheses for anonymous classes) --- Tests/AbstractRequestHandlerTestCase.php | 2 +- Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/AbstractRequestHandlerTestCase.php b/Tests/AbstractRequestHandlerTestCase.php index d050edb410..f80efffb71 100644 --- a/Tests/AbstractRequestHandlerTestCase.php +++ b/Tests/AbstractRequestHandlerTestCase.php @@ -39,7 +39,7 @@ abstract class AbstractRequestHandlerTestCase extends TestCase protected function setUp(): void { - $this->serverParams = new class() extends ServerParams { + $this->serverParams = new class extends ServerParams { public ?int $contentLength = null; public string $postMaxSize = ''; diff --git a/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php b/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php index f82fdc2f99..2b1b239e58 100644 --- a/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php +++ b/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php @@ -728,7 +728,7 @@ public function testPassTranslatableMessageAsLabelDoesntCastItToString() public function testPassTranslatableInterfaceAsLabelDoesntCastItToString() { - $message = new class() implements TranslatableInterface { + $message = new class implements TranslatableInterface { public function trans(TranslatorInterface $translator, ?string $locale = null): string { return 'my_message'; From dc6e7486029b86f5023ea81476fc5419b43366c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Sun, 28 Jul 2024 21:52:06 +0200 Subject: [PATCH 32/70] [Form] NumberType: Fix parsing of numbers in exponential notation with negative exponent --- .../NumberToLocalizedStringTransformer.php | 3 ++- ...NumberToLocalizedStringTransformerTest.php | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index f06fd80a11..d407e88586 100644 --- a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -143,7 +143,8 @@ public function reverseTransform($value) $value = str_replace(',', $decSep, $value); } - if (str_contains($value, $decSep)) { + //If the value is in exponential notation with a negative exponent, we end up with a float value too + if (str_contains($value, $decSep) || false !== stripos($value, 'e-')) { $type = \NumberFormatter::TYPE_DOUBLE; } else { $type = \PHP_INT_SIZE === 8 diff --git a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index 9c2e3bcae3..47b97ce530 100644 --- a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -632,4 +632,31 @@ public function testReverseTransformSmallInt() $this->assertSame(1.0, $transformer->reverseTransform('1')); } + + /** + * @dataProvider eNotationProvider + */ + public function testReverseTransformENotation($output, $input) + { + \Locale::setDefault('en'); + + $transformer = new NumberToLocalizedStringTransformer(); + + $this->assertSame($output, $transformer->reverseTransform($input)); + } + + public static function eNotationProvider(): array + { + return [ + [0.001, '1E-3'], + [0.001, '1.0E-3'], + [0.001, '1e-3'], + [0.001, '1.0e-03'], + [1000.0, '1E3'], + [1000.0, '1.0E3'], + [1000.0, '1e3'], + [1000.0, '1.0e3'], + [1232.0, '1.232e3'], + ]; + } } From 6a4471250f8899f86b6202a11fb4a3eb1cce9949 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 29 Jul 2024 09:33:48 +0200 Subject: [PATCH 33/70] Remove useless code --- Extension/Core/Type/TimeType.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Extension/Core/Type/TimeType.php b/Extension/Core/Type/TimeType.php index ad559760d1..d799210665 100644 --- a/Extension/Core/Type/TimeType.php +++ b/Extension/Core/Type/TimeType.php @@ -60,7 +60,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void if ('single_text' === $options['widget']) { $builder->addEventListener(FormEvents::PRE_SUBMIT, static function (FormEvent $e) use ($options) { - /** @var PreSubmitEvent $event */ $data = $e->getData(); if ($data && preg_match('/^(?P\d{2}):(?P\d{2})(?::(?P\d{2})(?:\.\d+)?)?$/', $data, $matches)) { if ($options['with_seconds']) { From 0b589850148240bb0d5647284e5cc1538f30e930 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 9 Aug 2024 16:59:37 +0200 Subject: [PATCH 34/70] skip tests requiring the intl extension if it's not installed --- .../DataTransformer/NumberToLocalizedStringTransformerTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index 47b97ce530..f5246e2222 100644 --- a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -638,6 +638,8 @@ public function testReverseTransformSmallInt() */ public function testReverseTransformENotation($output, $input) { + IntlTestHelper::requireFullIntl($this); + \Locale::setDefault('en'); $transformer = new NumberToLocalizedStringTransformer(); From e6f725489b96dde6b8d51702574186aa6152cacf Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 9 Aug 2024 10:02:21 +0200 Subject: [PATCH 35/70] [Form] Replace class-string by `::class` for `BaseTypeTestCase::TESTED_TYPE` --- Tests/Extension/Core/Type/BirthdayTypeTest.php | 3 ++- Tests/Extension/Core/Type/ButtonTypeTest.php | 3 ++- Tests/Extension/Core/Type/CheckboxTypeTest.php | 3 ++- Tests/Extension/Core/Type/ChoiceTypeTest.php | 3 ++- Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php | 3 ++- Tests/Extension/Core/Type/CollectionTypeTest.php | 3 ++- Tests/Extension/Core/Type/CountryTypeTest.php | 3 ++- Tests/Extension/Core/Type/CurrencyTypeTest.php | 3 ++- Tests/Extension/Core/Type/DateTimeTypeTest.php | 3 ++- Tests/Extension/Core/Type/DateTypeTest.php | 3 ++- Tests/Extension/Core/Type/FileTypeTest.php | 3 ++- Tests/Extension/Core/Type/FormTypeTest.php | 2 +- Tests/Extension/Core/Type/IntegerTypeTest.php | 3 ++- Tests/Extension/Core/Type/LanguageTypeTest.php | 3 ++- Tests/Extension/Core/Type/LocaleTypeTest.php | 3 ++- Tests/Extension/Core/Type/MoneyTypeTest.php | 3 ++- Tests/Extension/Core/Type/NumberTypeTest.php | 3 ++- Tests/Extension/Core/Type/PasswordTypeTest.php | 4 +++- Tests/Extension/Core/Type/RepeatedTypeTest.php | 3 ++- Tests/Extension/Core/Type/SubmitTypeTest.php | 3 ++- Tests/Extension/Core/Type/TextTypeTest.php | 4 +++- Tests/Extension/Core/Type/TimeTypeTest.php | 3 ++- Tests/Extension/Core/Type/TimezoneTypeTest.php | 3 ++- Tests/Extension/Core/Type/UrlTypeTest.php | 3 ++- Tests/Extension/Core/Type/WeekTypeTest.php | 3 ++- 25 files changed, 51 insertions(+), 25 deletions(-) diff --git a/Tests/Extension/Core/Type/BirthdayTypeTest.php b/Tests/Extension/Core/Type/BirthdayTypeTest.php index 0484571411..53e5c959ce 100644 --- a/Tests/Extension/Core/Type/BirthdayTypeTest.php +++ b/Tests/Extension/Core/Type/BirthdayTypeTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\BirthdayType; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; /** @@ -18,7 +19,7 @@ */ class BirthdayTypeTest extends DateTypeTest { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\BirthdayType'; + public const TESTED_TYPE = BirthdayType::class; public function testSetInvalidYearsOption() { diff --git a/Tests/Extension/Core/Type/ButtonTypeTest.php b/Tests/Extension/Core/Type/ButtonTypeTest.php index 0125631c58..4825015d27 100644 --- a/Tests/Extension/Core/Type/ButtonTypeTest.php +++ b/Tests/Extension/Core/Type/ButtonTypeTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Form\Button; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\LogicException; +use Symfony\Component\Form\Extension\Core\Type\ButtonType; use Symfony\Component\Form\Extension\Core\Type\FormType; /** @@ -21,7 +22,7 @@ */ class ButtonTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\ButtonType'; + public const TESTED_TYPE = ButtonType::class; public function testCreateButtonInstances() { diff --git a/Tests/Extension/Core/Type/CheckboxTypeTest.php b/Tests/Extension/Core/Type/CheckboxTypeTest.php index 62312e28dc..69fd0fd601 100644 --- a/Tests/Extension/Core/Type/CheckboxTypeTest.php +++ b/Tests/Extension/Core/Type/CheckboxTypeTest.php @@ -12,11 +12,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; class CheckboxTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\CheckboxType'; + public const TESTED_TYPE = CheckboxType::class; public function testDataIsFalseByDefault() { diff --git a/Tests/Extension/Core/Type/ChoiceTypeTest.php b/Tests/Extension/Core/Type/ChoiceTypeTest.php index c4f18734f8..948d682fc9 100644 --- a/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -15,12 +15,13 @@ use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; use Symfony\Component\Form\ChoiceList\View\ChoiceView; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; class ChoiceTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\ChoiceType'; + public const TESTED_TYPE = ChoiceType::class; private array $choices = [ 'Bernhard' => 'a', diff --git a/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php b/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php index af58e2ecfa..f60c6664c6 100644 --- a/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php +++ b/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php @@ -12,12 +12,13 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\Extension\Core\CoreExtension; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Contracts\Translation\TranslatorInterface; class ChoiceTypeTranslationTest extends TypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\ChoiceType'; + public const TESTED_TYPE = ChoiceType::class; private array $choices = [ 'Bernhard' => 'a', diff --git a/Tests/Extension/Core/Type/CollectionTypeTest.php b/Tests/Extension/Core/Type/CollectionTypeTest.php index 79134db993..95e1d9ca70 100644 --- a/Tests/Extension/Core/Type/CollectionTypeTest.php +++ b/Tests/Extension/Core/Type/CollectionTypeTest.php @@ -13,6 +13,7 @@ use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Form; use Symfony\Component\Form\Tests\Fixtures\Author; use Symfony\Component\Form\Tests\Fixtures\AuthorType; @@ -20,7 +21,7 @@ class CollectionTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\CollectionType'; + public const TESTED_TYPE = CollectionType::class; public function testContainsNoChildByDefault() { diff --git a/Tests/Extension/Core/Type/CountryTypeTest.php b/Tests/Extension/Core/Type/CountryTypeTest.php index 57146e1ecf..44073ef7b9 100644 --- a/Tests/Extension/Core/Type/CountryTypeTest.php +++ b/Tests/Extension/Core/Type/CountryTypeTest.php @@ -12,11 +12,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Extension\Core\Type\CountryType; use Symfony\Component\Intl\Util\IntlTestHelper; class CountryTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\CountryType'; + public const TESTED_TYPE = CountryType::class; protected function setUp(): void { diff --git a/Tests/Extension/Core/Type/CurrencyTypeTest.php b/Tests/Extension/Core/Type/CurrencyTypeTest.php index 51aaf6b372..3e8a53dfb2 100644 --- a/Tests/Extension/Core/Type/CurrencyTypeTest.php +++ b/Tests/Extension/Core/Type/CurrencyTypeTest.php @@ -12,11 +12,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Extension\Core\Type\CurrencyType; use Symfony\Component\Intl\Util\IntlTestHelper; class CurrencyTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\CurrencyType'; + public const TESTED_TYPE = CurrencyType::class; protected function setUp(): void { diff --git a/Tests/Extension/Core/Type/DateTimeTypeTest.php b/Tests/Extension/Core/Type/DateTimeTypeTest.php index a402a70f9f..5067bb05e7 100644 --- a/Tests/Extension/Core/Type/DateTimeTypeTest.php +++ b/Tests/Extension/Core/Type/DateTimeTypeTest.php @@ -12,12 +12,13 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\Exception\LogicException; +use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; class DateTimeTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\DateTimeType'; + public const TESTED_TYPE = DateTimeType::class; private string $defaultLocale; diff --git a/Tests/Extension/Core/Type/DateTypeTest.php b/Tests/Extension/Core/Type/DateTypeTest.php index dfbae93309..4b6a302f35 100644 --- a/Tests/Extension/Core/Type/DateTypeTest.php +++ b/Tests/Extension/Core/Type/DateTypeTest.php @@ -13,6 +13,7 @@ use Symfony\Component\Form\ChoiceList\View\ChoiceView; use Symfony\Component\Form\Exception\LogicException; +use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\Intl\Intl; @@ -21,7 +22,7 @@ class DateTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\DateType'; + public const TESTED_TYPE = DateType::class; private string $defaultTimezone; private string $defaultLocale; diff --git a/Tests/Extension/Core/Type/FileTypeTest.php b/Tests/Extension/Core/Type/FileTypeTest.php index 9c3a8efd0a..85907b6959 100644 --- a/Tests/Extension/Core/Type/FileTypeTest.php +++ b/Tests/Extension/Core/Type/FileTypeTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\Extension\Core\CoreExtension; +use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler; use Symfony\Component\Form\NativeRequestHandler; use Symfony\Component\Form\RequestHandlerInterface; @@ -21,7 +22,7 @@ class FileTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\FileType'; + public const TESTED_TYPE = FileType::class; protected function getExtensions(): array { diff --git a/Tests/Extension/Core/Type/FormTypeTest.php b/Tests/Extension/Core/Type/FormTypeTest.php index fe838885ed..fe19f3b120 100644 --- a/Tests/Extension/Core/Type/FormTypeTest.php +++ b/Tests/Extension/Core/Type/FormTypeTest.php @@ -64,7 +64,7 @@ public function setReferenceCopy($reference) class FormTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\FormType'; + public const TESTED_TYPE = FormType::class; public function testCreateFormInstances() { diff --git a/Tests/Extension/Core/Type/IntegerTypeTest.php b/Tests/Extension/Core/Type/IntegerTypeTest.php index 1e143b342f..ff33c17c63 100644 --- a/Tests/Extension/Core/Type/IntegerTypeTest.php +++ b/Tests/Extension/Core/Type/IntegerTypeTest.php @@ -11,11 +11,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Intl\Util\IntlTestHelper; class IntegerTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\IntegerType'; + public const TESTED_TYPE = IntegerType::class; private string $previousLocale; diff --git a/Tests/Extension/Core/Type/LanguageTypeTest.php b/Tests/Extension/Core/Type/LanguageTypeTest.php index e214e0afd4..8eb085112f 100644 --- a/Tests/Extension/Core/Type/LanguageTypeTest.php +++ b/Tests/Extension/Core/Type/LanguageTypeTest.php @@ -13,11 +13,12 @@ use Symfony\Component\Form\ChoiceList\View\ChoiceView; use Symfony\Component\Form\Exception\LogicException; +use Symfony\Component\Form\Extension\Core\Type\LanguageType; use Symfony\Component\Intl\Util\IntlTestHelper; class LanguageTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\LanguageType'; + public const TESTED_TYPE = LanguageType::class; protected function setUp(): void { diff --git a/Tests/Extension/Core/Type/LocaleTypeTest.php b/Tests/Extension/Core/Type/LocaleTypeTest.php index 8486b6656b..a2a820b390 100644 --- a/Tests/Extension/Core/Type/LocaleTypeTest.php +++ b/Tests/Extension/Core/Type/LocaleTypeTest.php @@ -12,11 +12,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Extension\Core\Type\LocaleType; use Symfony\Component\Intl\Util\IntlTestHelper; class LocaleTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\LocaleType'; + public const TESTED_TYPE = LocaleType::class; protected function setUp(): void { diff --git a/Tests/Extension/Core/Type/MoneyTypeTest.php b/Tests/Extension/Core/Type/MoneyTypeTest.php index 58e33af19b..302f09c22a 100644 --- a/Tests/Extension/Core/Type/MoneyTypeTest.php +++ b/Tests/Extension/Core/Type/MoneyTypeTest.php @@ -11,11 +11,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\MoneyType; use Symfony\Component\Intl\Util\IntlTestHelper; class MoneyTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\MoneyType'; + public const TESTED_TYPE = MoneyType::class; private string $defaultLocale; diff --git a/Tests/Extension/Core/Type/NumberTypeTest.php b/Tests/Extension/Core/Type/NumberTypeTest.php index 9efe052219..e744563d1a 100644 --- a/Tests/Extension/Core/Type/NumberTypeTest.php +++ b/Tests/Extension/Core/Type/NumberTypeTest.php @@ -13,11 +13,12 @@ use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Intl\Util\IntlTestHelper; class NumberTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\NumberType'; + public const TESTED_TYPE = NumberType::class; private string $defaultLocale; diff --git a/Tests/Extension/Core/Type/PasswordTypeTest.php b/Tests/Extension/Core/Type/PasswordTypeTest.php index 8d428a26a5..945437bcbd 100644 --- a/Tests/Extension/Core/Type/PasswordTypeTest.php +++ b/Tests/Extension/Core/Type/PasswordTypeTest.php @@ -11,9 +11,11 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; + class PasswordTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\PasswordType'; + public const TESTED_TYPE = PasswordType::class; public function testEmptyIfNotSubmitted() { diff --git a/Tests/Extension/Core/Type/RepeatedTypeTest.php b/Tests/Extension/Core/Type/RepeatedTypeTest.php index 06b9151fbe..62d1019009 100644 --- a/Tests/Extension/Core/Type/RepeatedTypeTest.php +++ b/Tests/Extension/Core/Type/RepeatedTypeTest.php @@ -11,13 +11,14 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\Form; use Symfony\Component\Form\Tests\Fixtures\NotMappedType; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; class RepeatedTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\RepeatedType'; + public const TESTED_TYPE = RepeatedType::class; protected Form $form; diff --git a/Tests/Extension/Core/Type/SubmitTypeTest.php b/Tests/Extension/Core/Type/SubmitTypeTest.php index 8a16175d76..af5ab8400b 100644 --- a/Tests/Extension/Core/Type/SubmitTypeTest.php +++ b/Tests/Extension/Core/Type/SubmitTypeTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\SubmitButton; /** @@ -18,7 +19,7 @@ */ class SubmitTypeTest extends ButtonTypeTest { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\SubmitType'; + public const TESTED_TYPE = SubmitType::class; public function testCreateSubmitButtonInstances() { diff --git a/Tests/Extension/Core/Type/TextTypeTest.php b/Tests/Extension/Core/Type/TextTypeTest.php index a28dfa9afa..4832151684 100644 --- a/Tests/Extension/Core/Type/TextTypeTest.php +++ b/Tests/Extension/Core/Type/TextTypeTest.php @@ -11,9 +11,11 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\TextType; + class TextTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\TextType'; + public const TESTED_TYPE = TextType::class; public function testSubmitNull($expected = null, $norm = null, $view = null) { diff --git a/Tests/Extension/Core/Type/TimeTypeTest.php b/Tests/Extension/Core/Type/TimeTypeTest.php index 155657038f..8a2baf1b4c 100644 --- a/Tests/Extension/Core/Type/TimeTypeTest.php +++ b/Tests/Extension/Core/Type/TimeTypeTest.php @@ -14,13 +14,14 @@ use Symfony\Component\Form\ChoiceList\View\ChoiceView; use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Exception\LogicException; +use Symfony\Component\Form\Extension\Core\Type\TimeType; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; class TimeTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\TimeType'; + public const TESTED_TYPE = TimeType::class; public function testSubmitDateTime() { diff --git a/Tests/Extension/Core/Type/TimezoneTypeTest.php b/Tests/Extension/Core/Type/TimezoneTypeTest.php index 9966b40438..4f23439746 100644 --- a/Tests/Extension/Core/Type/TimezoneTypeTest.php +++ b/Tests/Extension/Core/Type/TimezoneTypeTest.php @@ -13,11 +13,12 @@ use Symfony\Component\Form\ChoiceList\View\ChoiceView; use Symfony\Component\Form\Exception\LogicException; +use Symfony\Component\Form\Extension\Core\Type\TimezoneType; use Symfony\Component\Intl\Util\IntlTestHelper; class TimezoneTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\TimezoneType'; + public const TESTED_TYPE = TimezoneType::class; public function testTimezonesAreSelectable() { diff --git a/Tests/Extension/Core/Type/UrlTypeTest.php b/Tests/Extension/Core/Type/UrlTypeTest.php index 243d15297c..a0d335647d 100644 --- a/Tests/Extension/Core/Type/UrlTypeTest.php +++ b/Tests/Extension/Core/Type/UrlTypeTest.php @@ -12,13 +12,14 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Bridge\PhpUnit\ExpectUserDeprecationMessageTrait; +use Symfony\Component\Form\Extension\Core\Type\UrlType; use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException; class UrlTypeTest extends TextTypeTest { use ExpectUserDeprecationMessageTrait; - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\UrlType'; + public const TESTED_TYPE = UrlType::class; /** * @group legacy diff --git a/Tests/Extension/Core/Type/WeekTypeTest.php b/Tests/Extension/Core/Type/WeekTypeTest.php index a69b96a38a..b4d58fd95c 100644 --- a/Tests/Extension/Core/Type/WeekTypeTest.php +++ b/Tests/Extension/Core/Type/WeekTypeTest.php @@ -11,11 +11,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; +use Symfony\Component\Form\Extension\Core\Type\WeekType; use Symfony\Component\Form\FormError; class WeekTypeTest extends BaseTypeTestCase { - public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\WeekType'; + public const TESTED_TYPE = WeekType::class; public function testSubmitArray() { From ad5e8613911580583e554c3b1a79a63e1cefebfc Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 9 Aug 2024 09:46:47 +0200 Subject: [PATCH 36/70] [Form] Add support for the `calendar` option in `DateType` --- CHANGELOG.md | 1 + .../DateTimeToLocalizedStringTransformer.php | 14 ++--- Extension/Core/Type/DateType.php | 6 ++- ...teTimeToLocalizedStringTransformerTest.php | 54 +++++++++++++++++++ Tests/Extension/Core/Type/DateTypeTest.php | 34 ++++++++++++ 5 files changed, 101 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 631041da40..6ad9ab93f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Deprecate the `VersionAwareTest` trait, use feature detection instead + * Add support for the `calendar` option in `DateType` 7.1 --- diff --git a/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index a93803cd8b..5e93d289d2 100644 --- a/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -30,12 +30,12 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer /** * @see BaseDateTimeTransformer::formats for available format options * - * @param string|null $inputTimezone The name of the input timezone - * @param string|null $outputTimezone The name of the output timezone - * @param int|null $dateFormat The date format - * @param int|null $timeFormat The time format - * @param int $calendar One of the \IntlDateFormatter calendar constants - * @param string|null $pattern A pattern to pass to \IntlDateFormatter + * @param string|null $inputTimezone The name of the input timezone + * @param string|null $outputTimezone The name of the output timezone + * @param int|null $dateFormat The date format + * @param int|null $timeFormat The time format + * @param int|\IntlCalendar $calendar One of the \IntlDateFormatter calendar constants or an \IntlCalendar instance + * @param string|null $pattern A pattern to pass to \IntlDateFormatter * * @throws UnexpectedTypeException If a format is not supported or if a timezone is not a string */ @@ -44,7 +44,7 @@ public function __construct( ?string $outputTimezone = null, ?int $dateFormat = null, ?int $timeFormat = null, - private int $calendar = \IntlDateFormatter::GREGORIAN, + private int|\IntlCalendar $calendar = \IntlDateFormatter::GREGORIAN, private ?string $pattern = null, ) { parent::__construct($inputTimezone, $outputTimezone); diff --git a/Extension/Core/Type/DateType.php b/Extension/Core/Type/DateType.php index 773a51cbdd..d30946d7c9 100644 --- a/Extension/Core/Type/DateType.php +++ b/Extension/Core/Type/DateType.php @@ -49,7 +49,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void { $dateFormat = \is_int($options['format']) ? $options['format'] : self::DEFAULT_FORMAT; $timeFormat = \IntlDateFormatter::NONE; - $calendar = \IntlDateFormatter::GREGORIAN; + $calendar = $options['calendar'] ?? \IntlDateFormatter::GREGORIAN; $pattern = \is_string($options['format']) ? $options['format'] : ''; if (!\in_array($dateFormat, self::ACCEPTED_FORMATS, true)) { @@ -281,6 +281,7 @@ public function configureOptions(OptionsResolver $resolver): void 'format' => $format, 'model_timezone' => null, 'view_timezone' => null, + 'calendar' => null, 'placeholder' => $placeholderDefault, 'html5' => true, // Don't modify \DateTime classes by reference, we treat @@ -320,6 +321,9 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('months', 'array'); $resolver->setAllowedTypes('days', 'array'); $resolver->setAllowedTypes('input_format', 'string'); + $resolver->setAllowedTypes('calendar', ['null', \IntlCalendar::class]); + + $resolver->setInfo('calendar', 'The calendar to use for formatting and parsing the date. The value should be one of the \IntlDateFormatter calendar constants or an instance of the \IntlCalendar to use.'); $resolver->setNormalizer('html5', static function (Options $options, $html5) { if ($html5 && 'single_text' === $options['widget'] && self::HTML5_FORMAT !== $options['format']) { diff --git a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index c7918ae8b1..0cf8b22f6c 100644 --- a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -392,6 +392,60 @@ public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel() } } + public function testTransformDateTimeWithCustomCalendar() + { + $dateTime = new \DateTimeImmutable('2024-03-31'); + + $weekBeginsOnSunday = \IntlCalendar::createInstance(); + $weekBeginsOnSunday->setFirstDayOfWeek(\IntlCalendar::DOW_SUNDAY); + + $this->assertSame( + '2024-03-31 2024w14', + (new DateTimeToLocalizedStringTransformer(calendar: $weekBeginsOnSunday, pattern: "y-MM-dd y'w'w"))->transform($dateTime), + ); + + $weekBeginsOnMonday = \IntlCalendar::createInstance(); + $weekBeginsOnMonday->setFirstDayOfWeek(\IntlCalendar::DOW_MONDAY); + + $this->assertSame( + '2024-03-31 2024w13', + (new DateTimeToLocalizedStringTransformer(calendar: $weekBeginsOnMonday, pattern: "y-MM-dd y'w'w"))->transform($dateTime), + ); + } + + public function testReverseTransformDateTimeWithCustomCalendar() + { + $weekBeginsOnSunday = \IntlCalendar::createInstance(); + $weekBeginsOnSunday->setFirstDayOfWeek(\IntlCalendar::DOW_SUNDAY); + + $this->assertSame( + '2024-03-31', + (new DateTimeToLocalizedStringTransformer(calendar: $weekBeginsOnSunday, pattern: "y-MM-dd y'w'w")) + ->reverseTransform('2024-03-31 2024w14') + ->format('Y-m-d'), + ); + + $weekBeginsOnMonday = \IntlCalendar::createInstance(); + $weekBeginsOnMonday->setFirstDayOfWeek(\IntlCalendar::DOW_MONDAY); + + $this->assertSame( + '2024-03-31', + (new DateTimeToLocalizedStringTransformer(calendar: $weekBeginsOnMonday, pattern: "y-MM-dd y'w'w")) + ->reverseTransform('2024-03-31 2024w13') + ->format('Y-m-d'), + ); + } + + public function testDefaultCalendarIsGregorian() + { + $now = new \DateTimeImmutable(); + + $this->assertSame( + (new DateTimeToLocalizedStringTransformer(calendar: \IntlDateFormatter::GREGORIAN, pattern: "y-MM-dd y'w'w"))->transform($now), + (new DateTimeToLocalizedStringTransformer(pattern: "y-MM-dd y'w'w"))->transform($now), + ); + } + protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer { return new DateTimeToLocalizedStringTransformer($inputTimezone, $outputTimezone); diff --git a/Tests/Extension/Core/Type/DateTypeTest.php b/Tests/Extension/Core/Type/DateTypeTest.php index dfbae93309..61787512ae 100644 --- a/Tests/Extension/Core/Type/DateTypeTest.php +++ b/Tests/Extension/Core/Type/DateTypeTest.php @@ -1156,6 +1156,40 @@ public function testDateTimeImmutableInputTimezoneNotMatchingModelTimezone() ]); } + public function testSubmitWithCustomCalendarOption() + { + // Creates a new form using the "roc" (Republic Of China) calendar. This calendar starts in 1912, the year 2024 in + // the Gregorian calendar is the year 113 in the "roc" calendar. + $form = $this->factory->create(static::TESTED_TYPE, options: [ + 'format' => 'y-MM-dd', + 'html5' => false, + 'input' => 'array', + 'calendar' => \IntlCalendar::createInstance(locale: 'zh_TW@calendar=roc'), + ]); + $form->submit('113-03-31'); + + $this->assertSame('2024', $form->getData()['year'], 'The year should be converted to the default locale (en)'); + $this->assertSame('31', $form->getData()['day']); + $this->assertSame('3', $form->getData()['month']); + + $this->assertSame('113-03-31', $form->getViewData()); + } + + public function testSetDataWithCustomCalendarOption() + { + // Creates a new form using the "roc" (Republic Of China) calendar. This calendar starts in 1912, the year 2024 in + // the Gregorian calendar is the year 113 in the "roc" calendar. + $form = $this->factory->create(static::TESTED_TYPE, options: [ + 'format' => 'y-MM-dd', + 'html5' => false, + 'input' => 'array', + 'calendar' => \IntlCalendar::createInstance(locale: 'zh_TW@calendar=roc'), + ]); + $form->setData(['year' => '2024', 'month' => '3', 'day' => '31']); + + $this->assertSame('113-03-31', $form->getViewData()); + } + protected function getTestOptions(): array { return ['widget' => 'choice']; From a3ffc5a7d21538b4ac371d45d2a7a6a0761c1f7b Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 22 Aug 2024 09:26:39 +0200 Subject: [PATCH 37/70] [Form] Fix info for the `calendar` option of the `DateType` form type --- Extension/Core/Type/DateType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/Core/Type/DateType.php b/Extension/Core/Type/DateType.php index d30946d7c9..41dcf570c0 100644 --- a/Extension/Core/Type/DateType.php +++ b/Extension/Core/Type/DateType.php @@ -323,7 +323,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('input_format', 'string'); $resolver->setAllowedTypes('calendar', ['null', \IntlCalendar::class]); - $resolver->setInfo('calendar', 'The calendar to use for formatting and parsing the date. The value should be one of the \IntlDateFormatter calendar constants or an instance of the \IntlCalendar to use.'); + $resolver->setInfo('calendar', 'The calendar to use for formatting and parsing the date. The value should be an instance of \IntlCalendar. By default, the Gregorian calendar with the default locale is used.'); $resolver->setNormalizer('html5', static function (Options $options, $html5) { if ($html5 && 'single_text' === $options['widget'] && self::HTML5_FORMAT !== $options['format']) { From 7168ea22c680b88305c22183a5278cb07039b786 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 22 Aug 2024 10:42:25 +0200 Subject: [PATCH 38/70] [Form] Remove stalled PHP bug mentions --- .../DateTimeToLocalizedStringTransformer.php | 13 +++++-------- Extension/Core/Type/DateType.php | 8 +------- .../DateTimeToLocalizedStringTransformerTest.php | 9 +++++++++ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index 5e93d289d2..426c4bf89d 100644 --- a/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Extension\Core\DataTransformer; +use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Exception\UnexpectedTypeException; @@ -60,6 +61,10 @@ public function __construct( throw new UnexpectedTypeException($timeFormat, implode('", "', self::$formats)); } + if (\is_int($calendar) && !\in_array($calendar, [\IntlDateFormatter::GREGORIAN, \IntlDateFormatter::TRADITIONAL], true)) { + throw new InvalidArgumentException('The "calendar" option should be either an \IntlDateFormatter constant or an \IntlCalendar instance.'); + } + $this->dateFormat = $dateFormat; $this->timeFormat = $timeFormat; } @@ -157,8 +162,6 @@ public function reverseTransform(mixed $value): ?\DateTime * Returns a preconfigured IntlDateFormatter instance. * * @param bool $ignoreTimezone Use UTC regardless of the configured timezone - * - * @throws TransformationFailedException in case the date formatter cannot be constructed */ protected function getIntlDateFormatter(bool $ignoreTimezone = false): \IntlDateFormatter { @@ -170,12 +173,6 @@ protected function getIntlDateFormatter(bool $ignoreTimezone = false): \IntlDate $pattern = $this->pattern; $intlDateFormatter = new \IntlDateFormatter(\Locale::getDefault(), $dateFormat, $timeFormat, $timezone, $calendar, $pattern ?? ''); - - // new \intlDateFormatter may return null instead of false in case of failure, see https://bugs.php.net/66323 - if (!$intlDateFormatter) { - throw new TransformationFailedException(intl_get_error_message(), intl_get_error_code()); - } - $intlDateFormatter->setLenient(false); return $intlDateFormatter; diff --git a/Extension/Core/Type/DateType.php b/Extension/Core/Type/DateType.php index 41dcf570c0..54f24b89a0 100644 --- a/Extension/Core/Type/DateType.php +++ b/Extension/Core/Type/DateType.php @@ -120,17 +120,11 @@ public function buildForm(FormBuilderInterface $builder, array $options): void \Locale::getDefault(), $dateFormat, $timeFormat, - // see https://bugs.php.net/66323 - class_exists(\IntlTimeZone::class, false) ? \IntlTimeZone::createDefault() : null, + null, $calendar, $pattern ); - // new \IntlDateFormatter may return null instead of false in case of failure, see https://bugs.php.net/66323 - if (!$formatter) { - throw new InvalidOptionsException(intl_get_error_message(), intl_get_error_code()); - } - $formatter->setLenient(false); if ('choice' === $options['widget']) { diff --git a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 0cf8b22f6c..a14e4a44eb 100644 --- a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; +use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer; @@ -446,6 +447,14 @@ public function testDefaultCalendarIsGregorian() ); } + public function testInvalidCalendar() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "calendar" option should be either an \IntlDateFormatter constant or an \IntlCalendar instance.'); + + new DateTimeToLocalizedStringTransformer(calendar: 123456); + } + protected function createDateTimeTransformer(?string $inputTimezone = null, ?string $outputTimezone = null): BaseDateTimeTransformer { return new DateTimeToLocalizedStringTransformer($inputTimezone, $outputTimezone); From 964d2ea563193b98618310b18d3a0374a20d7698 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 22 Aug 2024 13:58:26 +0200 Subject: [PATCH 39/70] skip tests requiring the intl extension if it's not installed --- Tests/Extension/Core/Type/DateTypeTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Tests/Extension/Core/Type/DateTypeTest.php b/Tests/Extension/Core/Type/DateTypeTest.php index f7f7d925c7..5f4f896b5d 100644 --- a/Tests/Extension/Core/Type/DateTypeTest.php +++ b/Tests/Extension/Core/Type/DateTypeTest.php @@ -1159,6 +1159,8 @@ public function testDateTimeImmutableInputTimezoneNotMatchingModelTimezone() public function testSubmitWithCustomCalendarOption() { + IntlTestHelper::requireFullIntl($this); + // Creates a new form using the "roc" (Republic Of China) calendar. This calendar starts in 1912, the year 2024 in // the Gregorian calendar is the year 113 in the "roc" calendar. $form = $this->factory->create(static::TESTED_TYPE, options: [ @@ -1178,6 +1180,8 @@ public function testSubmitWithCustomCalendarOption() public function testSetDataWithCustomCalendarOption() { + IntlTestHelper::requireFullIntl($this); + // Creates a new form using the "roc" (Republic Of China) calendar. This calendar starts in 1912, the year 2024 in // the Gregorian calendar is the year 113 in the "roc" calendar. $form = $this->factory->create(static::TESTED_TYPE, options: [ From 64b30ef5a6bb466d7bcc9e4b31d4e7f26b9b8432 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Wed, 18 Oct 2023 17:16:44 -0400 Subject: [PATCH 40/70] add LazyChoiceLoader and choice_lazy option --- CHANGELOG.md | 1 + ChoiceList/Loader/LazyChoiceLoader.php | 54 +++++++++ Extension/Core/Type/ChoiceType.php | 19 +++ .../Loader/LazyChoiceLoaderTest.php | 50 ++++++++ Tests/Extension/Core/Type/ChoiceTypeTest.php | 108 ++++++++++++++++++ .../Descriptor/resolved_form_type_1.json | 1 + .../Descriptor/resolved_form_type_1.txt | 32 +++--- 7 files changed, 249 insertions(+), 16 deletions(-) create mode 100644 ChoiceList/Loader/LazyChoiceLoader.php create mode 100644 Tests/ChoiceList/Loader/LazyChoiceLoaderTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ad9ab93f1..1cef486963 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Deprecate the `VersionAwareTest` trait, use feature detection instead * Add support for the `calendar` option in `DateType` + * Add `LazyChoiceLoader` and `choice_lazy` option in `ChoiceType` for loading and rendering choices on demand 7.1 --- diff --git a/ChoiceList/Loader/LazyChoiceLoader.php b/ChoiceList/Loader/LazyChoiceLoader.php new file mode 100644 index 0000000000..03451be365 --- /dev/null +++ b/ChoiceList/Loader/LazyChoiceLoader.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\ChoiceList\Loader; + +use Symfony\Component\Form\ChoiceList\ArrayChoiceList; +use Symfony\Component\Form\ChoiceList\ChoiceListInterface; + +/** + * A choice loader that loads its choices and values lazily, only when necessary. + * + * @author Yonel Ceruto + */ +class LazyChoiceLoader implements ChoiceLoaderInterface +{ + private ?ChoiceListInterface $choiceList = null; + + public function __construct( + private readonly ChoiceLoaderInterface $loader, + ) { + } + + public function loadChoiceList(?callable $value = null): ChoiceListInterface + { + return $this->choiceList ??= new ArrayChoiceList([], $value); + } + + public function loadChoicesForValues(array $values, ?callable $value = null): array + { + $choices = $this->loader->loadChoicesForValues($values, $value); + $this->choiceList = new ArrayChoiceList($choices, $value); + + return $choices; + } + + public function loadValuesForChoices(array $choices, ?callable $value = null): array + { + $values = $this->loader->loadValuesForChoices($choices, $value); + + if ($this->choiceList?->getValuesForChoices($choices) !== $values) { + $this->loadChoicesForValues($values, $value); + } + + return $values; + } +} diff --git a/Extension/Core/Type/ChoiceType.php b/Extension/Core/Type/ChoiceType.php index d0a1b6e06f..35a3175924 100644 --- a/Extension/Core/Type/ChoiceType.php +++ b/Extension/Core/Type/ChoiceType.php @@ -27,10 +27,12 @@ use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; +use Symfony\Component\Form\ChoiceList\Loader\LazyChoiceLoader; use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; use Symfony\Component\Form\ChoiceList\View\ChoiceListView; use Symfony\Component\Form\ChoiceList\View\ChoiceView; use Symfony\Component\Form\Event\PreSubmitEvent; +use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\DataMapper\CheckboxListMapper; use Symfony\Component\Form\Extension\Core\DataMapper\RadioListMapper; @@ -333,11 +335,24 @@ public function configureOptions(OptionsResolver $resolver): void return $choiceTranslationDomain; }; + $choiceLoaderNormalizer = static function (Options $options, ?ChoiceLoaderInterface $choiceLoader) { + if (!$options['choice_lazy']) { + return $choiceLoader; + } + + if (null === $choiceLoader) { + throw new LogicException('The "choice_lazy" option can only be used if the "choice_loader" option is set.'); + } + + return new LazyChoiceLoader($choiceLoader); + }; + $resolver->setDefaults([ 'multiple' => false, 'expanded' => false, 'choices' => [], 'choice_filter' => null, + 'choice_lazy' => false, 'choice_loader' => null, 'choice_label' => null, 'choice_name' => null, @@ -365,9 +380,11 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setNormalizer('placeholder', $placeholderNormalizer); $resolver->setNormalizer('choice_translation_domain', $choiceTranslationDomainNormalizer); + $resolver->setNormalizer('choice_loader', $choiceLoaderNormalizer); $resolver->setAllowedTypes('choices', ['null', 'array', \Traversable::class]); $resolver->setAllowedTypes('choice_translation_domain', ['null', 'bool', 'string']); + $resolver->setAllowedTypes('choice_lazy', 'bool'); $resolver->setAllowedTypes('choice_loader', ['null', ChoiceLoaderInterface::class, ChoiceLoader::class]); $resolver->setAllowedTypes('choice_filter', ['null', 'callable', 'string', PropertyPath::class, ChoiceFilter::class]); $resolver->setAllowedTypes('choice_label', ['null', 'bool', 'callable', 'string', PropertyPath::class, ChoiceLabel::class]); @@ -381,6 +398,8 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('separator_html', ['bool']); $resolver->setAllowedTypes('duplicate_preferred_choices', 'bool'); $resolver->setAllowedTypes('group_by', ['null', 'callable', 'string', PropertyPath::class, GroupBy::class]); + + $resolver->setInfo('choice_lazy', 'Load choices on demand. When set to true, only the selected choices are loaded and rendered.'); } public function getBlockPrefix(): string diff --git a/Tests/ChoiceList/Loader/LazyChoiceLoaderTest.php b/Tests/ChoiceList/Loader/LazyChoiceLoaderTest.php new file mode 100644 index 0000000000..0c1bcf3c22 --- /dev/null +++ b/Tests/ChoiceList/Loader/LazyChoiceLoaderTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\ChoiceList\Loader; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\ChoiceList\Loader\LazyChoiceLoader; +use Symfony\Component\Form\Tests\Fixtures\ArrayChoiceLoader; + +class LazyChoiceLoaderTest extends TestCase +{ + private LazyChoiceLoader $loader; + + protected function setUp(): void + { + $this->loader = new LazyChoiceLoader(new ArrayChoiceLoader(['A', 'B', 'C'])); + } + + public function testInitialEmptyChoiceListLoading() + { + $this->assertSame([], $this->loader->loadChoiceList()->getChoices()); + } + + public function testOnDemandChoiceListAfterLoadingValuesForChoices() + { + $this->loader->loadValuesForChoices(['A']); + $this->assertSame(['A' => 'A'], $this->loader->loadChoiceList()->getChoices()); + } + + public function testOnDemandChoiceListAfterLoadingChoicesForValues() + { + $this->loader->loadChoicesForValues(['B']); + $this->assertSame(['B' => 'B'], $this->loader->loadChoiceList()->getChoices()); + } + + public function testOnDemandChoiceList() + { + $this->loader->loadValuesForChoices(['A']); + $this->loader->loadChoicesForValues(['B']); + $this->assertSame(['B' => 'B'], $this->loader->loadChoiceList()->getChoices()); + } +} diff --git a/Tests/Extension/Core/Type/ChoiceTypeTest.php b/Tests/Extension/Core/Type/ChoiceTypeTest.php index 948d682fc9..28810bbc7e 100644 --- a/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader; use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\FormInterface; @@ -2277,4 +2278,111 @@ public function testWithSameLoaderAndDifferentChoiceValueCallbacks() $this->assertSame('20', $view['choice_two']->vars['choices'][1]->value); $this->assertSame('30', $view['choice_two']->vars['choices'][2]->value); } + + public function testChoiceLazyThrowsWhenChoiceLoaderIsNotSet() + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('The "choice_lazy" option can only be used if the "choice_loader" option is set.'); + + $this->factory->create(static::TESTED_TYPE, null, [ + 'choice_lazy' => true, + ]); + } + + public function testChoiceLazyLoadsAndRendersNothingWhenNoDataSet() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'choice_loader' => new CallbackChoiceLoader(fn () => ['a' => 'A', 'b' => 'B']), + 'choice_lazy' => true, + ]); + + $this->assertNull($form->getData()); + + $view = $form->createView(); + $this->assertArrayHasKey('choices', $view->vars); + $this->assertSame([], $view->vars['choices']); + } + + public function testChoiceLazyLoadsAndRendersOnlyDataSetViaDefault() + { + $form = $this->factory->create(static::TESTED_TYPE, 'A', [ + 'choice_loader' => new CallbackChoiceLoader(fn () => ['a' => 'A', 'b' => 'B']), + 'choice_lazy' => true, + ]); + + $this->assertSame('A', $form->getData()); + + $view = $form->createView(); + $this->assertArrayHasKey('choices', $view->vars); + $this->assertCount(1, $view->vars['choices']); + $this->assertSame('A', $view->vars['choices'][0]->value); + } + + public function testChoiceLazyLoadsAndRendersOnlyDataSetViaSubmit() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'choice_loader' => new CallbackChoiceLoader(fn () => ['a' => 'A', 'b' => 'B']), + 'choice_lazy' => true, + ]); + + $form->submit('B'); + $this->assertSame('B', $form->getData()); + + $view = $form->createView(); + $this->assertArrayHasKey('choices', $view->vars); + $this->assertCount(1, $view->vars['choices']); + $this->assertSame('B', $view->vars['choices'][0]->value); + } + + public function testChoiceLazyErrorWhenInvalidSubmitData() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'choice_loader' => new CallbackChoiceLoader(fn () => ['a' => 'A', 'b' => 'B']), + 'choice_lazy' => true, + ]); + + $form->submit('invalid'); + $this->assertNull($form->getData()); + + $view = $form->createView(); + $this->assertArrayHasKey('choices', $view->vars); + $this->assertCount(0, $view->vars['choices']); + $this->assertCount(1, $form->getErrors()); + $this->assertSame('ERROR: The selected choice is invalid.', trim((string) $form->getErrors())); + } + + public function testChoiceLazyMultipleWithDefaultData() + { + $form = $this->factory->create(static::TESTED_TYPE, ['A', 'B'], [ + 'choice_loader' => new CallbackChoiceLoader(fn () => ['a' => 'A', 'b' => 'B', 'c' => 'C']), + 'choice_lazy' => true, + 'multiple' => true, + ]); + + $this->assertSame(['A', 'B'], $form->getData()); + + $view = $form->createView(); + $this->assertArrayHasKey('choices', $view->vars); + $this->assertCount(2, $view->vars['choices']); + $this->assertSame('A', $view->vars['choices'][0]->value); + $this->assertSame('B', $view->vars['choices'][1]->value); + } + + public function testChoiceLazyMultipleWithSubmittedData() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'choice_loader' => new CallbackChoiceLoader(fn () => ['a' => 'A', 'b' => 'B', 'c' => 'C']), + 'choice_lazy' => true, + 'multiple' => true, + ]); + + $form->submit(['B', 'C']); + $this->assertSame(['B', 'C'], $form->getData()); + + $view = $form->createView(); + $this->assertArrayHasKey('choices', $view->vars); + $this->assertCount(2, $view->vars['choices']); + $this->assertSame('B', $view->vars['choices'][0]->value); + $this->assertSame('C', $view->vars['choices'][1]->value); + } } diff --git a/Tests/Fixtures/Descriptor/resolved_form_type_1.json b/Tests/Fixtures/Descriptor/resolved_form_type_1.json index e071ec712f..5590018c09 100644 --- a/Tests/Fixtures/Descriptor/resolved_form_type_1.json +++ b/Tests/Fixtures/Descriptor/resolved_form_type_1.json @@ -6,6 +6,7 @@ "choice_attr", "choice_filter", "choice_label", + "choice_lazy", "choice_loader", "choice_name", "choice_translation_domain", diff --git a/Tests/Fixtures/Descriptor/resolved_form_type_1.txt b/Tests/Fixtures/Descriptor/resolved_form_type_1.txt index 005bfd3e96..93c6b66d98 100644 --- a/Tests/Fixtures/Descriptor/resolved_form_type_1.txt +++ b/Tests/Fixtures/Descriptor/resolved_form_type_1.txt @@ -8,22 +8,22 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice") choice_attr FormType FormType FormTypeCsrfExtension choice_filter -------------------- ------------------------------ ----------------------- choice_label compound action csrf_field_name - choice_loader data_class allow_file_upload csrf_message - choice_name empty_data attr csrf_protection - choice_translation_domain error_bubbling attr_translation_parameters csrf_token_id - choice_translation_parameters invalid_message auto_initialize csrf_token_manager - choice_value trim block_name - choices block_prefix - duplicate_preferred_choices by_reference - expanded data - group_by disabled - multiple form_attr - placeholder getter - placeholder_attr help - preferred_choices help_attr - separator help_html - separator_html help_translation_parameters - inherit_data + choice_lazy data_class allow_file_upload csrf_message + choice_loader empty_data attr csrf_protection + choice_name error_bubbling attr_translation_parameters csrf_token_id + choice_translation_domain invalid_message auto_initialize csrf_token_manager + choice_translation_parameters trim block_name + choice_value block_prefix + choices by_reference + duplicate_preferred_choices data + expanded disabled + group_by form_attr + multiple getter + placeholder help + placeholder_attr help_attr + preferred_choices help_html + separator help_translation_parameters + separator_html inherit_data invalid_message_parameters is_empty_callback label From afc4cf934134f84769a08d68ed319fbfb76422a1 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sat, 31 Aug 2024 00:31:12 +0200 Subject: [PATCH 41/70] CS: re-apply `trailing_comma_in_multiline` --- Tests/Extension/Core/Type/RepeatedTypeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Extension/Core/Type/RepeatedTypeTest.php b/Tests/Extension/Core/Type/RepeatedTypeTest.php index b6b74f1aa1..2d19a0613d 100644 --- a/Tests/Extension/Core/Type/RepeatedTypeTest.php +++ b/Tests/Extension/Core/Type/RepeatedTypeTest.php @@ -199,7 +199,7 @@ public function testSubmitNullForTextTypeWithEmptyDataOptionSetToEmptyString($em 'type' => TextType::class, 'options' => [ 'empty_data' => $emptyData, - ] + ], ]); $form->submit($submittedData); From a3372639a2ac5b02e2b464457cb8306d9e585510 Mon Sep 17 00:00:00 2001 From: Yi-Jyun Pan Date: Sun, 1 Sep 2024 03:22:14 +0800 Subject: [PATCH 42/70] [Validator] Improve `zh_TW` translation --- Resources/translations/validators.zh_TW.xlf | 38 ++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Resources/translations/validators.zh_TW.xlf b/Resources/translations/validators.zh_TW.xlf index 831759783e..0a76ab7a7b 100644 --- a/Resources/translations/validators.zh_TW.xlf +++ b/Resources/translations/validators.zh_TW.xlf @@ -4,31 +4,31 @@ This form should not contain extra fields. - 該表單中不可有額外字段。 + 此表單不應包含其他欄位。 The uploaded file was too large. Please try to upload a smaller file. - 上傳文件太大, 請重新嘗試上傳一個較小的文件。 + 上傳的檔案過大。請嘗試上傳較小的檔案。 The CSRF token is invalid. Please try to resubmit the form. - CSRF 驗證符無效, 請重新提交。 + CSRF token 無效。請重新提交表單。 This value is not a valid HTML5 color. - 該數值不是個有效的 HTML5 顏色。 + 這個數值不是有效的 HTML5 顏色。 Please enter a valid birthdate. - 請輸入有效的生日日期。 + 請輸入有效的出生日期。 The selected choice is invalid. - 所選的選項無效。 + 選取的選項無效。 The collection is invalid. - 集合無效。 + 這個集合無效。 Please select a valid color. @@ -44,11 +44,11 @@ Please choose a valid date interval. - 請選擇有效的日期間隔。 + 請選擇有效的日期區間。 Please enter a valid date and time. - 請輸入有效的日期與時間。 + 請輸入有效的日期和時間。 Please enter a valid date. @@ -56,11 +56,11 @@ Please select a valid file. - 請選擇有效的文件。 + 請選擇有效的檔案。 The hidden field is invalid. - 隱藏字段無效。 + 隱藏欄位無效。 Please enter an integer. @@ -72,11 +72,11 @@ Please select a valid locale. - 請選擇有效的語言環境。 + 請選擇有效的語系。 Please enter a valid money amount. - 請輸入正確的金額。 + 請輸入有效的金額。 Please enter a number. @@ -88,11 +88,11 @@ Please enter a percentage value. - 請輸入百分比值。 + 請輸入百分比數值。 The values do not match. - 數值不匹配。 + 數值不相符。 Please enter a valid time. @@ -104,19 +104,19 @@ Please enter a valid URL. - 請輸入有效的網址。 + 請輸入有效的 URL。 Please enter a valid search term. - 請輸入有效的搜索詞。 + 請輸入有效的搜尋關鍵字。 Please provide a valid phone number. - 請提供有效的手機號碼。 + 請提供有效的電話號碼。 The checkbox has an invalid value. - 無效的選框值。 + 核取方塊上有無效的值。 Please enter a valid email address. From 4f3d91f8a7626e3cab9e3d2952321df10013a6eb Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 20 Sep 2024 09:50:07 +0200 Subject: [PATCH 43/70] Mutate remaining data providers to static ones --- Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php b/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php index 893af48593..cdad28b5d1 100644 --- a/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php +++ b/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php @@ -586,7 +586,7 @@ public static function provideDistinguishedChoices() ]; } - public function provideSameKeyChoices() + public static function provideSameKeyChoices() { // Only test types here that can be used as array keys return [ @@ -597,7 +597,7 @@ public function provideSameKeyChoices() ]; } - public function provideDistinguishedKeyChoices() + public static function provideDistinguishedKeyChoices() { // Only test types here that can be used as array keys return [ From 81c5c3281ae822a13f1271d261954ef28feee6cd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 23 Sep 2024 12:51:56 +0200 Subject: [PATCH 44/70] do not use the Test suffix for non test classes --- Test/FormPerformanceTestCase.php | 4 ++-- Tests/Extension/Core/Type/BaseTypeTestCase.php | 4 ++-- Tests/{VersionAwareTest.php => VersionAwareTestTrait.php} | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename Tests/{VersionAwareTest.php => VersionAwareTestTrait.php} (95%) diff --git a/Test/FormPerformanceTestCase.php b/Test/FormPerformanceTestCase.php index 1d631a2fde..12217e44b1 100644 --- a/Test/FormPerformanceTestCase.php +++ b/Test/FormPerformanceTestCase.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Test; -use Symfony\Component\Form\Tests\VersionAwareTest; +use Symfony\Component\Form\Tests\VersionAwareTestTrait; /** * Base class for performance tests. @@ -23,7 +23,7 @@ */ abstract class FormPerformanceTestCase extends FormIntegrationTestCase { - use VersionAwareTest; + use VersionAwareTestTrait; protected int $maxRunningTime = 0; diff --git a/Tests/Extension/Core/Type/BaseTypeTestCase.php b/Tests/Extension/Core/Type/BaseTypeTestCase.php index 14b602a4b4..6ba9c68588 100644 --- a/Tests/Extension/Core/Type/BaseTypeTestCase.php +++ b/Tests/Extension/Core/Type/BaseTypeTestCase.php @@ -12,14 +12,14 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\Test\TypeTestCase; -use Symfony\Component\Form\Tests\VersionAwareTest; +use Symfony\Component\Form\Tests\VersionAwareTestTrait; /** * @author Bernhard Schussek */ abstract class BaseTypeTestCase extends TypeTestCase { - use VersionAwareTest; + use VersionAwareTestTrait; public const TESTED_TYPE = ''; diff --git a/Tests/VersionAwareTest.php b/Tests/VersionAwareTestTrait.php similarity index 95% rename from Tests/VersionAwareTest.php rename to Tests/VersionAwareTestTrait.php index 530c174739..62e98934e3 100644 --- a/Tests/VersionAwareTest.php +++ b/Tests/VersionAwareTestTrait.php @@ -14,7 +14,7 @@ /** * @deprecated since Symfony 7.2, use feature detection instead. */ -trait VersionAwareTest +trait VersionAwareTestTrait { protected static int $supportedFeatureSetVersion = 404; @@ -23,7 +23,7 @@ trait VersionAwareTest */ protected function requiresFeatureSet(int $requiredFeatureSetVersion) { - trigger_deprecation('symfony/form', '7.2', 'The "%s" trait is deprecated, use feature detection instead.', VersionAwareTest::class); + trigger_deprecation('symfony/form', '7.2', 'The "%s" trait is deprecated, use feature detection instead.', VersionAwareTestTrait::class); if ($requiredFeatureSetVersion > static::$supportedFeatureSetVersion) { $this->markTestSkipped(\sprintf('Test requires features from symfony/form %.2f but only version %.2f is supported.', $requiredFeatureSetVersion / 100, static::$supportedFeatureSetVersion / 100)); From c85e835399b759bd42991fd59f8afb8dc9775982 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 23 Sep 2024 11:18:25 +0200 Subject: [PATCH 45/70] do not override the final runTest() method --- Test/FormPerformanceTestCase.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Test/FormPerformanceTestCase.php b/Test/FormPerformanceTestCase.php index 1d631a2fde..eafdf6c5f7 100644 --- a/Test/FormPerformanceTestCase.php +++ b/Test/FormPerformanceTestCase.php @@ -25,19 +25,25 @@ abstract class FormPerformanceTestCase extends FormIntegrationTestCase { use VersionAwareTest; + private float $startTime; protected int $maxRunningTime = 0; - protected function runTest(): mixed + protected function setUp(): void { - $s = microtime(true); - $result = parent::runTest(); - $time = microtime(true) - $s; + parent::setUp(); + + $this->startTime = microtime(true); + } + + protected function assertPostConditions(): void + { + parent::assertPostConditions(); + + $time = microtime(true) - $this->startTime; if (0 != $this->maxRunningTime && $time > $this->maxRunningTime) { $this->fail(\sprintf('expected running time: <= %s but was: %s', $this->maxRunningTime, $time)); } - - return $result; } /** From 9c44ae8084df0ed829f0de020b7a4d8bdc80afa4 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 24 Sep 2024 13:28:07 +0200 Subject: [PATCH 46/70] Remove useless parent method calls in tests --- Tests/ChoiceList/AbstractChoiceListTestCase.php | 2 -- .../DateTimeToLocalizedStringTransformerTest.php | 2 -- .../Core/DataTransformer/DateTimeToRfc3339TransformerTest.php | 2 -- Tests/Extension/Core/Type/MoneyTypeTest.php | 2 -- Tests/Extension/Core/Type/NumberTypeTest.php | 2 -- Tests/Extension/Core/Type/PercentTypeTest.php | 2 -- Tests/NativeRequestHandlerTest.php | 2 -- 7 files changed, 14 deletions(-) diff --git a/Tests/ChoiceList/AbstractChoiceListTestCase.php b/Tests/ChoiceList/AbstractChoiceListTestCase.php index 0b0cb8e79f..5ddae56141 100644 --- a/Tests/ChoiceList/AbstractChoiceListTestCase.php +++ b/Tests/ChoiceList/AbstractChoiceListTestCase.php @@ -39,8 +39,6 @@ abstract class AbstractChoiceListTestCase extends TestCase protected function setUp(): void { - parent::setUp(); - $this->list = $this->createChoiceList(); $choices = $this->getChoices(); diff --git a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index a14e4a44eb..e8527b2201 100644 --- a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -31,8 +31,6 @@ class DateTimeToLocalizedStringTransformerTest extends BaseDateTimeTransformerTe protected function setUp(): void { - parent::setUp(); - // Normalize intl. configuration settings. if (\extension_loaded('intl')) { $this->initialTestCaseUseException = ini_set('intl.use_exceptions', 0); diff --git a/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php b/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php index 6a4d77039f..c69ba31be9 100644 --- a/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php @@ -25,8 +25,6 @@ class DateTimeToRfc3339TransformerTest extends BaseDateTimeTransformerTestCase protected function setUp(): void { - parent::setUp(); - $this->dateTime = new \DateTime('2010-02-03 04:05:06 UTC'); $this->dateTimeWithoutSeconds = new \DateTime('2010-02-03 04:05:00 UTC'); } diff --git a/Tests/Extension/Core/Type/MoneyTypeTest.php b/Tests/Extension/Core/Type/MoneyTypeTest.php index 302f09c22a..f9112ffcac 100644 --- a/Tests/Extension/Core/Type/MoneyTypeTest.php +++ b/Tests/Extension/Core/Type/MoneyTypeTest.php @@ -33,8 +33,6 @@ protected function setUp(): void protected function tearDown(): void { - parent::tearDown(); - \Locale::setDefault($this->defaultLocale); } diff --git a/Tests/Extension/Core/Type/NumberTypeTest.php b/Tests/Extension/Core/Type/NumberTypeTest.php index e744563d1a..95ccdfea9f 100644 --- a/Tests/Extension/Core/Type/NumberTypeTest.php +++ b/Tests/Extension/Core/Type/NumberTypeTest.php @@ -35,8 +35,6 @@ protected function setUp(): void protected function tearDown(): void { - parent::tearDown(); - \Locale::setDefault($this->defaultLocale); } diff --git a/Tests/Extension/Core/Type/PercentTypeTest.php b/Tests/Extension/Core/Type/PercentTypeTest.php index 76595d79be..120aab2f31 100644 --- a/Tests/Extension/Core/Type/PercentTypeTest.php +++ b/Tests/Extension/Core/Type/PercentTypeTest.php @@ -34,8 +34,6 @@ protected function setUp(): void protected function tearDown(): void { - parent::tearDown(); - \Locale::setDefault($this->defaultLocale); } diff --git a/Tests/NativeRequestHandlerTest.php b/Tests/NativeRequestHandlerTest.php index 3770e12199..6ff64bc657 100644 --- a/Tests/NativeRequestHandlerTest.php +++ b/Tests/NativeRequestHandlerTest.php @@ -41,8 +41,6 @@ protected function setUp(): void protected function tearDown(): void { - parent::tearDown(); - $_GET = []; $_POST = []; $_FILES = []; From 4bea7a84f366a3d0ab81651bab4c5366fe974169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 23 Sep 2024 11:24:18 +0200 Subject: [PATCH 47/70] Add PR template and auto-close PR on subtree split repositories --- .gitattributes | 3 +-- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++++++ .github/workflows/close-pull-request.yml | 20 ++++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/close-pull-request.yml diff --git a/.gitattributes b/.gitattributes index 84c7add058..14c3c35940 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ /Tests export-ignore /phpunit.xml.dist export-ignore -/.gitattributes export-ignore -/.gitignore export-ignore +/.git* export-ignore diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..4689c4dad4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ +Please do not submit any Pull Requests here. They will be closed. +--- + +Please submit your PR here instead: +https://github.com/symfony/symfony + +This repository is what we call a "subtree split": a read-only subset of that main repository. +We're looking forward to your PR there! diff --git a/.github/workflows/close-pull-request.yml b/.github/workflows/close-pull-request.yml new file mode 100644 index 0000000000..e55b47817e --- /dev/null +++ b/.github/workflows/close-pull-request.yml @@ -0,0 +1,20 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened] + +jobs: + run: + runs-on: ubuntu-latest + steps: + - uses: superbrothers/close-pull-request@v3 + with: + comment: | + Thanks for your Pull Request! We love contributions. + + However, you should instead open your PR on the main repository: + https://github.com/symfony/symfony + + This repository is what we call a "subtree split": a read-only subset of that main repository. + We're looking forward to your PR there! From bdf4a90b78d7a40f2fc077e435174f7d6f1ce128 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 26 Sep 2024 10:09:09 +0200 Subject: [PATCH 48/70] Remove unused imports --- Extension/Core/Type/TimeType.php | 1 - Tests/Extension/DataCollector/FormDataCollectorTest.php | 1 - 2 files changed, 2 deletions(-) diff --git a/Extension/Core/Type/TimeType.php b/Extension/Core/Type/TimeType.php index d799210665..35549b0419 100644 --- a/Extension/Core/Type/TimeType.php +++ b/Extension/Core/Type/TimeType.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Event\PreSubmitEvent; use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer; diff --git a/Tests/Extension/DataCollector/FormDataCollectorTest.php b/Tests/Extension/DataCollector/FormDataCollectorTest.php index 0517b26c3b..4090fc97bf 100644 --- a/Tests/Extension/DataCollector/FormDataCollectorTest.php +++ b/Tests/Extension/DataCollector/FormDataCollectorTest.php @@ -18,7 +18,6 @@ use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\DataCollector\FormDataCollector; use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor; -use Symfony\Component\Form\Form; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormInterface; From 5818e1437bfd9efc084c0a9bd4117c3ebf29149d Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Sat, 28 Sep 2024 13:16:28 +0200 Subject: [PATCH 49/70] [TwigBridge] Remove `VersionAwareTest` from `AbstractLayoutTestCase` --- Test/FormPerformanceTestCase.php | 1 - Tests/Extension/Core/Type/BaseTypeTestCase.php | 18 ------------------ 2 files changed, 19 deletions(-) diff --git a/Test/FormPerformanceTestCase.php b/Test/FormPerformanceTestCase.php index 3c6ba1145a..702f37b7a4 100644 --- a/Test/FormPerformanceTestCase.php +++ b/Test/FormPerformanceTestCase.php @@ -25,7 +25,6 @@ abstract class FormPerformanceTestCase extends FormIntegrationTestCase { use RunTestTrait; - use VersionAwareTest; /** * @var int diff --git a/Tests/Extension/Core/Type/BaseTypeTestCase.php b/Tests/Extension/Core/Type/BaseTypeTestCase.php index 5238e2fd88..32ab611168 100644 --- a/Tests/Extension/Core/Type/BaseTypeTestCase.php +++ b/Tests/Extension/Core/Type/BaseTypeTestCase.php @@ -19,8 +19,6 @@ */ abstract class BaseTypeTestCase extends TypeTestCase { - use VersionAwareTest; - public const TESTED_TYPE = ''; public function testPassDisabledAsOption() @@ -114,8 +112,6 @@ public function testDefaultTranslationDomain() public function testPassLabelTranslationParametersToView() { - $this->requiresFeatureSet(403); - $view = $this->factory->create($this->getTestedType(), null, array_merge($this->getTestOptions(), [ 'label_translation_parameters' => ['%param%' => 'value'], ])) @@ -126,8 +122,6 @@ public function testPassLabelTranslationParametersToView() public function testPassAttrTranslationParametersToView() { - $this->requiresFeatureSet(403); - $view = $this->factory->create($this->getTestedType(), null, array_merge($this->getTestOptions(), [ 'attr_translation_parameters' => ['%param%' => 'value'], ])) @@ -138,8 +132,6 @@ public function testPassAttrTranslationParametersToView() public function testInheritLabelTranslationParametersFromParent() { - $this->requiresFeatureSet(403); - $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'label_translation_parameters' => ['%param%' => 'value'], @@ -153,8 +145,6 @@ public function testInheritLabelTranslationParametersFromParent() public function testInheritAttrTranslationParametersFromParent() { - $this->requiresFeatureSet(403); - $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'attr_translation_parameters' => ['%param%' => 'value'], @@ -168,8 +158,6 @@ public function testInheritAttrTranslationParametersFromParent() public function testPreferOwnLabelTranslationParameters() { - $this->requiresFeatureSet(403); - $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'label_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], @@ -185,8 +173,6 @@ public function testPreferOwnLabelTranslationParameters() public function testPreferOwnAttrTranslationParameters() { - $this->requiresFeatureSet(403); - $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'attr_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], @@ -202,8 +188,6 @@ public function testPreferOwnAttrTranslationParameters() public function testDefaultLabelTranslationParameters() { - $this->requiresFeatureSet(403); - $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) ->add('child', $this->getTestedType(), $this->getTestOptions()) ->getForm() @@ -214,8 +198,6 @@ public function testDefaultLabelTranslationParameters() public function testDefaultAttrTranslationParameters() { - $this->requiresFeatureSet(403); - $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) ->add('child', $this->getTestedType(), $this->getTestOptions()) ->getForm() From 92e1f531edb70a1530920ad932a8fb4b680204b5 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 30 Sep 2024 21:28:44 +0200 Subject: [PATCH 50/70] [DoctrineBridge] Fix risky test warnings --- Test/FormPerformanceTestCase.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Test/FormPerformanceTestCase.php b/Test/FormPerformanceTestCase.php index 8c0284ebf5..e4329150a2 100644 --- a/Test/FormPerformanceTestCase.php +++ b/Test/FormPerformanceTestCase.php @@ -45,6 +45,8 @@ private function doRunTest() $this->fail(sprintf('expected running time: <= %s but was: %s', $this->maxRunningTime, $time)); } + $this->expectNotToPerformAssertions(); + return $result; } From 0df8534ea695de4db1ba76b6a0a060b66d75e25f Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 2 Oct 2024 10:47:28 +0200 Subject: [PATCH 51/70] Make `@var` occurrences consistent --- Extension/Validator/ValidatorExtension.php | 2 +- FormBuilder.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Extension/Validator/ValidatorExtension.php b/Extension/Validator/ValidatorExtension.php index 522a769629..2c534481cd 100644 --- a/Extension/Validator/ValidatorExtension.php +++ b/Extension/Validator/ValidatorExtension.php @@ -40,7 +40,7 @@ public function __construct( // the DIC, where the XML file is loaded automatically. Thus the following // code must be kept synchronized with validation.xml - /* @var $metadata ClassMetadata */ + /* @var ClassMetadata $metadata */ $metadata->addConstraint(new Form()); $metadata->addConstraint(new Traverse(false)); } diff --git a/FormBuilder.php b/FormBuilder.php index 2bfd92a688..f34c2f76eb 100644 --- a/FormBuilder.php +++ b/FormBuilder.php @@ -142,7 +142,7 @@ public function count(): int public function getFormConfig(): FormConfigInterface { - /** @var $config self */ + /** @var self $config */ $config = parent::getFormConfig(); $config->children = []; From 5771ce9d999dcb43627b68e7344d51a5e20bf48f Mon Sep 17 00:00:00 2001 From: Bram Leeda Date: Thu, 3 Oct 2024 20:27:26 +0200 Subject: [PATCH 52/70] [Form] Support intl.use_exceptions/error_level in NumberToLocalizedStringTransformer --- .../NumberToLocalizedStringTransformer.php | 8 ++- .../PercentToLocalizedStringTransformer.php | 10 ++- ...teTimeToLocalizedStringTransformerTest.php | 23 +++---- ...NumberToLocalizedStringTransformerTest.php | 64 +++++++++++++++++++ ...ercentToLocalizedStringTransformerTest.php | 64 +++++++++++++++++++ 5 files changed, 151 insertions(+), 18 deletions(-) diff --git a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index d407e88586..bd9f796e17 100644 --- a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -152,10 +152,14 @@ public function reverseTransform($value) : \NumberFormatter::TYPE_INT32; } - $result = $formatter->parse($value, $type, $position); + try { + $result = @$formatter->parse($value, $type, $position); + } catch (\IntlException $e) { + throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); + } if (intl_is_failure($formatter->getErrorCode())) { - throw new TransformationFailedException($formatter->getErrorMessage()); + throw new TransformationFailedException($formatter->getErrorMessage(), $formatter->getErrorCode()); } if ($result >= \PHP_INT_MAX || $result <= -\PHP_INT_MAX) { diff --git a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php index fdeed2231c..b716e436ee 100644 --- a/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/PercentToLocalizedStringTransformer.php @@ -139,11 +139,15 @@ public function reverseTransform($value) $type = \PHP_INT_SIZE === 8 ? \NumberFormatter::TYPE_INT64 : \NumberFormatter::TYPE_INT32; } - // replace normal spaces so that the formatter can read them - $result = $formatter->parse(str_replace(' ', "\xc2\xa0", $value), $type, $position); + try { + // replace normal spaces so that the formatter can read them + $result = @$formatter->parse(str_replace(' ', "\xc2\xa0", $value), $type, $position); + } catch (\IntlException $e) { + throw new TransformationFailedException($e->getMessage(), 0, $e); + } if (intl_is_failure($formatter->getErrorCode())) { - throw new TransformationFailedException($formatter->getErrorMessage()); + throw new TransformationFailedException($formatter->getErrorMessage(), $formatter->getErrorCode()); } if (self::FRACTIONAL == $this->type) { diff --git a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 8a37707e7c..21f5c5079c 100644 --- a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -56,7 +56,7 @@ protected function tearDown(): void if (\extension_loaded('intl')) { ini_set('intl.use_exceptions', $this->initialTestCaseUseException); - ini_set('intl.error_level', $this->initialTestCaseUseException); + ini_set('intl.error_level', $this->initialTestCaseErrorLevel); } } @@ -341,12 +341,11 @@ public function testReverseTransformFiveDigitYearsWithTimestamp() $transformer->reverseTransform('20107-03-21 12:34:56'); } + /** + * @requires extension intl + */ public function testReverseTransformWrapsIntlErrorsWithErrorLevel() { - if (!\extension_loaded('intl')) { - $this->markTestSkipped('intl extension is not loaded'); - } - $errorLevel = ini_set('intl.error_level', \E_WARNING); try { @@ -358,12 +357,11 @@ public function testReverseTransformWrapsIntlErrorsWithErrorLevel() } } + /** + * @requires extension intl + */ public function testReverseTransformWrapsIntlErrorsWithExceptions() { - if (!\extension_loaded('intl')) { - $this->markTestSkipped('intl extension is not loaded'); - } - $initialUseExceptions = ini_set('intl.use_exceptions', 1); try { @@ -375,12 +373,11 @@ public function testReverseTransformWrapsIntlErrorsWithExceptions() } } + /** + * @requires extension intl + */ public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel() { - if (!\extension_loaded('intl')) { - $this->markTestSkipped('intl extension is not loaded'); - } - $initialUseExceptions = ini_set('intl.use_exceptions', 1); $initialErrorLevel = ini_set('intl.error_level', \E_WARNING); diff --git a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index f5246e2222..f40d447f44 100644 --- a/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -20,8 +20,17 @@ class NumberToLocalizedStringTransformerTest extends TestCase { private $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(); \Locale::setDefault('en'); } @@ -29,6 +38,11 @@ protected function setUp(): void protected function tearDown(): void { \Locale::setDefault($this->defaultLocale); + + if (\extension_loaded('intl')) { + ini_set('intl.use_exceptions', $this->initialTestCaseUseException); + ini_set('intl.error_level', $this->initialTestCaseErrorLevel); + } } public static function provideTransformations() @@ -647,6 +661,56 @@ public function testReverseTransformENotation($output, $input) $this->assertSame($output, $transformer->reverseTransform($input)); } + /** + * @requires extension intl + */ + public function testReverseTransformWrapsIntlErrorsWithErrorLevel() + { + $errorLevel = ini_set('intl.error_level', \E_WARNING); + + try { + $this->expectException(TransformationFailedException::class); + $transformer = new NumberToLocalizedStringTransformer(); + $transformer->reverseTransform('invalid_number'); + } finally { + ini_set('intl.error_level', $errorLevel); + } + } + + /** + * @requires extension intl + */ + public function testReverseTransformWrapsIntlErrorsWithExceptions() + { + $initialUseExceptions = ini_set('intl.use_exceptions', 1); + + try { + $this->expectException(TransformationFailedException::class); + $transformer = new NumberToLocalizedStringTransformer(); + $transformer->reverseTransform('invalid_number'); + } finally { + ini_set('intl.use_exceptions', $initialUseExceptions); + } + } + + /** + * @requires extension intl + */ + public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel() + { + $initialUseExceptions = ini_set('intl.use_exceptions', 1); + $initialErrorLevel = ini_set('intl.error_level', \E_WARNING); + + try { + $this->expectException(TransformationFailedException::class); + $transformer = new NumberToLocalizedStringTransformer(); + $transformer->reverseTransform('invalid_number'); + } finally { + ini_set('intl.use_exceptions', $initialUseExceptions); + ini_set('intl.error_level', $initialErrorLevel); + } + } + public static function eNotationProvider(): array { return [ diff --git a/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php index 6afa4c35d8..161aa81caf 100644 --- a/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php @@ -23,8 +23,17 @@ class PercentToLocalizedStringTransformerTest extends TestCase private $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(); \Locale::setDefault('en'); } @@ -32,6 +41,11 @@ protected function setUp(): void protected function tearDown(): void { \Locale::setDefault($this->defaultLocale); + + if (\extension_loaded('intl')) { + ini_set('intl.use_exceptions', $this->initialTestCaseUseException); + ini_set('intl.error_level', $this->initialTestCaseErrorLevel); + } } public function testTransform() @@ -483,6 +497,56 @@ public function testReverseTransformForHtml5FormatWithScale() $this->assertEquals(0.1234, $transformer->reverseTransform('12.34')); } + + /** + * @requires extension intl + */ + public function testReverseTransformWrapsIntlErrorsWithErrorLevel() + { + $errorLevel = ini_set('intl.error_level', \E_WARNING); + + try { + $this->expectException(TransformationFailedException::class); + $transformer = new PercentToLocalizedStringTransformer(null, null, \NumberFormatter::ROUND_HALFUP); + $transformer->reverseTransform('invalid_number'); + } finally { + ini_set('intl.error_level', $errorLevel); + } + } + + /** + * @requires extension intl + */ + public function testReverseTransformWrapsIntlErrorsWithExceptions() + { + $initialUseExceptions = ini_set('intl.use_exceptions', 1); + + try { + $this->expectException(TransformationFailedException::class); + $transformer = new PercentToLocalizedStringTransformer(null, null, \NumberFormatter::ROUND_HALFUP); + $transformer->reverseTransform('invalid_number'); + } finally { + ini_set('intl.use_exceptions', $initialUseExceptions); + } + } + + /** + * @requires extension intl + */ + public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel() + { + $initialUseExceptions = ini_set('intl.use_exceptions', 1); + $initialErrorLevel = ini_set('intl.error_level', \E_WARNING); + + try { + $this->expectException(TransformationFailedException::class); + $transformer = new PercentToLocalizedStringTransformer(null, null, \NumberFormatter::ROUND_HALFUP); + $transformer->reverseTransform('invalid_number'); + } finally { + ini_set('intl.use_exceptions', $initialUseExceptions); + ini_set('intl.error_level', $initialErrorLevel); + } + } } class PercentToLocalizedStringTransformerWithoutGrouping extends PercentToLocalizedStringTransformer From 64116e00ea52c0e7f82d91ae55edf2b8fdbfb997 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sun, 6 Oct 2024 18:45:39 +0200 Subject: [PATCH 53/70] CS: clean some whitespaces/indentation --- .../Core/DataTransformer/NumberToLocalizedStringTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index 127688e249..7911b47bd1 100644 --- a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -102,7 +102,7 @@ public function reverseTransform(mixed $value): int|float|null $value = str_replace(',', $decSep, $value); } - //If the value is in exponential notation with a negative exponent, we end up with a float value too + // If the value is in exponential notation with a negative exponent, we end up with a float value too if (str_contains($value, $decSep) || false !== stripos($value, 'e-')) { $type = \NumberFormatter::TYPE_DOUBLE; } else { From c1974a723cdee8a273cb49ce13fada5c1667706a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 8 Oct 2024 09:23:06 +0200 Subject: [PATCH 54/70] minor #58472 CS: clean some whitespaces/indentation (keradus) This PR was squashed before being merged into the 7.2 branch. Discussion ---------- CS: clean some whitespaces/indentation | Q | A | ------------- | --- | Branch? | 7.2 | Bug fix? | no | New feature? | no | Deprecations? | no | Issues | Fix CS | License | MIT Commits ------- d0f63b8afa1 CS: clean some whitespaces/indentation --- .../Core/DataTransformer/NumberToLocalizedStringTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index bd9f796e17..653f1c445f 100644 --- a/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -143,7 +143,7 @@ public function reverseTransform($value) $value = str_replace(',', $decSep, $value); } - //If the value is in exponential notation with a negative exponent, we end up with a float value too + // If the value is in exponential notation with a negative exponent, we end up with a float value too if (str_contains($value, $decSep) || false !== stripos($value, 'e-')) { $type = \NumberFormatter::TYPE_DOUBLE; } else { From d4cb9a2447b46f16256bb2b327434d80a35b10b6 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 8 Oct 2024 14:54:29 +0200 Subject: [PATCH 55/70] [Form] Remove unnecessary imports --- Test/FormPerformanceTestCase.php | 1 - Tests/Extension/Core/Type/BaseTypeTestCase.php | 1 - 2 files changed, 2 deletions(-) diff --git a/Test/FormPerformanceTestCase.php b/Test/FormPerformanceTestCase.php index 702f37b7a4..21e6ed7da8 100644 --- a/Test/FormPerformanceTestCase.php +++ b/Test/FormPerformanceTestCase.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Form\Test; use Symfony\Component\Form\Test\Traits\RunTestTrait; -use Symfony\Component\Form\Tests\VersionAwareTest; /** * Base class for performance tests. diff --git a/Tests/Extension/Core/Type/BaseTypeTestCase.php b/Tests/Extension/Core/Type/BaseTypeTestCase.php index 32ab611168..8293ec31bd 100644 --- a/Tests/Extension/Core/Type/BaseTypeTestCase.php +++ b/Tests/Extension/Core/Type/BaseTypeTestCase.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\Test\TypeTestCase; -use Symfony\Component\Form\Tests\VersionAwareTest; /** * @author Bernhard Schussek From 6a49eed7c6fc1ab8b4f8916c500468ac1b5046c3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 26 Aug 2024 16:50:35 +0200 Subject: [PATCH 56/70] [Security] Implement stateless headers/cookies-based CSRF protection --- Extension/Csrf/Type/FormTypeCsrfExtension.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Extension/Csrf/Type/FormTypeCsrfExtension.php b/Extension/Csrf/Type/FormTypeCsrfExtension.php index 0ad4daeb3c..10367ae5ff 100644 --- a/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -19,6 +19,7 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\Util\ServerParams; +use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Contracts\Translation\TranslatorInterface; @@ -35,6 +36,8 @@ public function __construct( private ?TranslatorInterface $translator = null, private ?string $translationDomain = null, private ?ServerParams $serverParams = null, + private array $fieldAttr = [], + private ?string $defaultTokenId = null, ) { } @@ -73,6 +76,7 @@ public function finishView(FormView $view, FormInterface $form, array $options): $csrfForm = $factory->createNamed($options['csrf_field_name'], HiddenType::class, $data, [ 'block_prefix' => 'csrf_token', 'mapped' => false, + 'attr' => $this->fieldAttr + ['autocomplete' => 'off'], ]); $view->children[$options['csrf_field_name']] = $csrfForm->createView($view); @@ -81,13 +85,24 @@ public function finishView(FormView $view, FormInterface $form, array $options): public function configureOptions(OptionsResolver $resolver): void { + if ($defaultTokenId = $this->defaultTokenId) { + $defaultTokenManager = $this->defaultTokenManager; + $defaultTokenId = static fn (Options $options) => $options['csrf_token_manager'] === $defaultTokenManager ? $defaultTokenId : null; + } + $resolver->setDefaults([ 'csrf_protection' => $this->defaultEnabled, 'csrf_field_name' => $this->defaultFieldName, 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.', 'csrf_token_manager' => $this->defaultTokenManager, - 'csrf_token_id' => null, + 'csrf_token_id' => $defaultTokenId, ]); + + $resolver->setAllowedTypes('csrf_protection', 'bool'); + $resolver->setAllowedTypes('csrf_field_name', 'string'); + $resolver->setAllowedTypes('csrf_message', 'string'); + $resolver->setAllowedTypes('csrf_token_manager', CsrfTokenManagerInterface::class); + $resolver->setAllowedTypes('csrf_token_id', ['null', 'string']); } public static function getExtendedTypes(): iterable From 896c5f267eeb0cee02dd5ce196c6581c7b07575c Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Thu, 20 Jul 2023 12:22:19 +0200 Subject: [PATCH 57/70] [Form] Use `form.post_set_data` in `ResizeFormListener` --- CHANGELOG.md | 2 + .../Core/EventListener/ResizeFormListener.php | 48 ++- .../EventListener/DataCollectorListener.php | 4 +- .../EventListener/ResizeFormListenerTest.php | 293 +++++++++++------- 4 files changed, 233 insertions(+), 114 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cef486963..3b1fabfd17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ CHANGELOG * Deprecate the `VersionAwareTest` trait, use feature detection instead * Add support for the `calendar` option in `DateType` * Add `LazyChoiceLoader` and `choice_lazy` option in `ChoiceType` for loading and rendering choices on demand + * Use `form.post_set_data` instead of `form.pre_set_data` in `ResizeFormListener` + * Change the priority of `DataCollectorListener` from 255 to -255 7.1 --- diff --git a/Extension/Core/EventListener/ResizeFormListener.php b/Extension/Core/EventListener/ResizeFormListener.php index d67efab31e..299f919373 100644 --- a/Extension/Core/EventListener/ResizeFormListener.php +++ b/Extension/Core/EventListener/ResizeFormListener.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Extension\Core\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Form\Event\PostSetDataEvent; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; @@ -27,6 +28,9 @@ class ResizeFormListener implements EventSubscriberInterface protected array $prototypeOptions; private \Closure|bool $deleteEmpty; + // BC, to be removed in 8.0 + private bool $overridden = true; + private bool $usePreSetData = false; public function __construct( private string $type, @@ -44,15 +48,57 @@ public function __construct( public static function getSubscribedEvents(): array { return [ - FormEvents::PRE_SET_DATA => 'preSetData', + FormEvents::PRE_SET_DATA => 'preSetData', // deprecated + FormEvents::POST_SET_DATA => ['postSetData', 255], // as early as possible FormEvents::PRE_SUBMIT => 'preSubmit', // (MergeCollectionListener, MergeDoctrineCollectionListener) FormEvents::SUBMIT => ['onSubmit', 50], ]; } + /** + * @deprecated Since Symfony 7.2, use {@see postSetData()} instead. + */ public function preSetData(FormEvent $event): void { + if (__CLASS__ === static::class + || __CLASS__ === (new \ReflectionClass($this))->getMethod('preSetData')->getDeclaringClass()->name + ) { + // not a child class, or child class does not overload PRE_SET_DATA + return; + } + + trigger_deprecation('symfony/form', '7.2', 'Calling "%s()" is deprecated, use "%s::postSetData()" instead.', __METHOD__, __CLASS__); + // parent::preSetData() has been called + $this->overridden = false; + try { + $this->postSetData($event); + } finally { + $this->usePreSetData = true; + } + } + + /** + * Remove FormEvent type hint in 8.0. + * + * @final since Symfony 7.2 + */ + public function postSetData(FormEvent|PostSetDataEvent $event): void + { + if (__CLASS__ !== static::class) { + if ($this->overridden) { + trigger_deprecation('symfony/form', '7.2', 'Calling "%s::preSetData()" is deprecated, use "%s::postSetData()" instead.', static::class, __CLASS__); + // parent::preSetData() has not been called, noop + + return; + } + + if ($this->usePreSetData) { + // nothing else to do + return; + } + } + $form = $event->getForm(); $data = $event->getData() ?? []; diff --git a/Extension/DataCollector/EventListener/DataCollectorListener.php b/Extension/DataCollector/EventListener/DataCollectorListener.php index 02cffbeffe..c541efec25 100644 --- a/Extension/DataCollector/EventListener/DataCollectorListener.php +++ b/Extension/DataCollector/EventListener/DataCollectorListener.php @@ -32,8 +32,8 @@ public function __construct( public static function getSubscribedEvents(): array { return [ - // High priority in order to be called as soon as possible - FormEvents::POST_SET_DATA => ['postSetData', 255], + // Low priority in order to be called as late as possible + FormEvents::POST_SET_DATA => ['postSetData', -255], // Low priority in order to be called as late as possible FormEvents::POST_SUBMIT => ['postSubmit', -255], ]; diff --git a/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php b/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php index f63a5c1548..934460c8f9 100644 --- a/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php +++ b/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php @@ -14,28 +14,28 @@ use Doctrine\Common\Collections\ArrayCollection; use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\DataMapper\DataMapper; use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormFactoryBuilder; use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\Form\FormInterface; class ResizeFormListenerTest extends TestCase { private FormFactoryInterface $factory; - private FormInterface $form; + private FormBuilderInterface $builder; protected function setUp(): void { $this->factory = (new FormFactoryBuilder())->getFormFactory(); - $this->form = $this->getBuilder() + $this->builder = $this->getBuilder() ->setCompound(true) - ->setDataMapper(new DataMapper()) - ->getForm(); + ->setDataMapper(new DataMapper()); } protected function getBuilder($name = 'name') @@ -43,142 +43,221 @@ protected function getBuilder($name = 'name') return new FormBuilder($name, null, new EventDispatcher(), $this->factory); } - protected function getForm($name = 'name') + /** + * @group legacy + */ + public function testPreSetDataResizesForm() { - return $this->getBuilder($name)->getForm(); + $this->builder->add($this->getBuilder('0')); + $this->builder->add($this->getBuilder('1')); + $this->builder->addEventSubscriber(new class(TextType::class, ['attr' => ['maxlength' => 10]], false, false) extends ResizeFormListener { + public function preSetData(FormEvent $event): void + { + parent::preSetData($event); + } + }); + + $form = $this->builder->getForm(); + + $this->assertTrue($form->has('0')); + + // initialize the form + $form->setData([1 => 'string', 2 => 'string']); + + $this->assertFalse($form->has('0')); + $this->assertTrue($form->has('1')); + $this->assertTrue($form->has('2')); + + $this->assertSame('string', $form->get('1')->getData()); + $this->assertSame('string', $form->get('2')->getData()); } - public function testPreSetDataResizesForm() + public function testPostSetDataResizesForm() { - $this->form->add($this->getForm('0')); - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('0')); + $this->builder->add($this->getBuilder('1')); + $this->builder->addEventSubscriber(new ResizeFormListener(TextType::class, ['attr' => ['maxlength' => 10]], false, false)); - $data = [1 => 'string', 2 => 'string']; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener(TextType::class, ['attr' => ['maxlength' => 10]], false, false); - $listener->preSetData($event); + $form = $this->builder->getForm(); + + $this->assertTrue($form->has('0')); - $this->assertFalse($this->form->has('0')); - $this->assertTrue($this->form->has('1')); - $this->assertTrue($this->form->has('2')); + // initialize the form + $form->setData([1 => 'string', 2 => 'string']); + + $this->assertFalse($form->has('0')); + $this->assertTrue($form->has('1')); + $this->assertTrue($form->has('2')); + + $this->assertSame('string', $form->get('1')->getData()); + $this->assertSame('string', $form->get('2')->getData()); } + /** + * @group legacy + */ public function testPreSetDataRequiresArrayOrTraversable() { $this->expectException(UnexpectedTypeException::class); $data = 'no array or traversable'; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, false); + $event = new FormEvent($this->builder->getForm(), $data); + $listener = new class(TextType::class, [], false, false) extends ResizeFormListener { + public function preSetData(FormEvent $event): void + { + parent::preSetData($event); + } + }; $listener->preSetData($event); } + public function testPostSetDataRequiresArrayOrTraversable() + { + $this->expectException(UnexpectedTypeException::class); + $data = 'no array or traversable'; + $event = new FormEvent($this->builder->getForm(), $data); + $listener = new ResizeFormListener(TextType::class, [], false, false); + $listener->postSetData($event); + } + + /** + * @group legacy + */ public function testPreSetDataDealsWithNullData() { $data = null; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener(TextType::class, [], false, false); + $event = new FormEvent($this->builder->getForm(), $data); + $listener = new class(TextType::class, [], false, false) extends ResizeFormListener { + public function preSetData(FormEvent $event): void + { + parent::preSetData($event); + } + }; $listener->preSetData($event); - $this->assertSame(0, $this->form->count()); + $this->assertSame(0, $this->builder->count()); + } + + public function testPostSetDataDealsWithNullData() + { + $data = null; + $event = new FormEvent($this->builder->getForm(), $data); + $listener = new ResizeFormListener(TextType::class, [], false, false); + $listener->postSetData($event); + + $this->assertSame(0, $this->builder->count()); } public function testPreSubmitResizesUpIfAllowAdd() { - $this->form->add($this->getForm('0')); + $this->builder->add($this->getBuilder('0')); + $this->builder->addEventSubscriber(new ResizeFormListener(TextType::class, ['attr' => ['maxlength' => 10]], true, false)); - $data = [0 => 'string', 1 => 'string']; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener(TextType::class, ['attr' => ['maxlength' => 10]], true, false); - $listener->preSubmit($event); + $form = $this->builder->getForm(); + + $this->assertTrue($form->has('0')); + $this->assertFalse($form->has('1')); - $this->assertTrue($this->form->has('0')); - $this->assertTrue($this->form->has('1')); + $form->submit([0 => 'string', 1 => 'string']); + + $this->assertTrue($form->has('0')); + $this->assertTrue($form->has('1')); } public function testPreSubmitResizesDownIfAllowDelete() { - $this->form->add($this->getForm('0')); - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('0')); + $this->builder->add($this->getBuilder('1')); + $this->builder->addEventSubscriber(new ResizeFormListener(TextType::class, [], false, true)); - $data = [0 => 'string']; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true); - $listener->preSubmit($event); + $form = $this->builder->getForm(); + // initialize the form + $form->setData([0 => 'string', 1 => 'string']); + + $this->assertTrue($form->has('0')); + $this->assertTrue($form->has('1')); - $this->assertTrue($this->form->has('0')); - $this->assertFalse($this->form->has('1')); + $form->submit([0 => 'string']); + + $this->assertTrue($form->has('0')); + $this->assertFalse($form->has('1')); } // fix for https://github.com/symfony/symfony/pull/493 public function testPreSubmitRemovesZeroKeys() { - $this->form->add($this->getForm('0')); + $this->builder->add($this->getBuilder('0')); $data = []; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true); + $form = $this->builder->getForm(); + $event = new FormEvent($form, $data); + $listener = new ResizeFormListener(TextType::class, [], false, true); $listener->preSubmit($event); - $this->assertFalse($this->form->has('0')); + $this->assertFalse($form->has('0')); } public function testPreSubmitDoesNothingIfNotAllowAddNorAllowDelete() { - $this->form->add($this->getForm('0')); - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('0')); + $this->builder->add($this->getBuilder('1')); $data = [0 => 'string', 2 => 'string']; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, false); + $form = $this->builder->getForm(); + $event = new FormEvent($form, $data); + $listener = new ResizeFormListener(TextType::class, [], false, false); $listener->preSubmit($event); - $this->assertTrue($this->form->has('0')); - $this->assertTrue($this->form->has('1')); - $this->assertFalse($this->form->has('2')); + $this->assertTrue($form->has('0')); + $this->assertTrue($form->has('1')); + $this->assertFalse($form->has('2')); } public function testPreSubmitDealsWithNoArrayOrTraversable() { $data = 'no array or traversable'; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, false); + $form = $this->builder->getForm(); + $event = new FormEvent($form, $data); + $listener = new ResizeFormListener(TextType::class, [], false, false); $listener->preSubmit($event); - $this->assertFalse($this->form->has('1')); + $this->assertFalse($form->has('1')); } public function testPreSubmitDealsWithNullData() { - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('1')); $data = null; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true); + $form = $this->builder->getForm(); + $event = new FormEvent($form, $data); + $listener = new ResizeFormListener(TextType::class, [], false, true); $listener->preSubmit($event); - $this->assertFalse($this->form->has('1')); + $this->assertFalse($form->has('1')); } // fixes https://github.com/symfony/symfony/pull/40 public function testPreSubmitDealsWithEmptyData() { - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('1')); $data = ''; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true); + $form = $this->builder->getForm(); + $event = new FormEvent($form, $data); + $listener = new ResizeFormListener(TextType::class, [], false, true); $listener->preSubmit($event); - $this->assertFalse($this->form->has('1')); + $this->assertFalse($form->has('1')); } public function testOnSubmitNormDataRemovesEntriesMissingInTheFormIfAllowDelete() { - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('1')); $data = [0 => 'first', 1 => 'second', 2 => 'third']; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true); + $form = $this->builder->getForm(); + $event = new FormEvent($form, $data); + $listener = new ResizeFormListener(TextType::class, [], false, true); $listener->onSubmit($event); $this->assertEquals([1 => 'second'], $event->getData()); @@ -186,11 +265,12 @@ public function testOnSubmitNormDataRemovesEntriesMissingInTheFormIfAllowDelete( public function testOnSubmitNormDataDoesNothingIfNotAllowDelete() { - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('1')); $data = [0 => 'first', 1 => 'second', 2 => 'third']; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, false); + $form = $this->builder->getForm(); + $event = new FormEvent($form, $data); + $listener = new ResizeFormListener(TextType::class, [], false, false); $listener->onSubmit($event); $this->assertEquals($data, $event->getData()); @@ -200,18 +280,18 @@ public function testOnSubmitNormDataRequiresArrayOrTraversable() { $this->expectException(UnexpectedTypeException::class); $data = 'no array or traversable'; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, false); + $event = new FormEvent($this->builder->getForm(), $data); + $listener = new ResizeFormListener(TextType::class, [], false, false); $listener->onSubmit($event); } public function testOnSubmitNormDataDealsWithNullData() { - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('1')); $data = null; - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true); + $event = new FormEvent($this->builder->getForm(), $data); + $listener = new ResizeFormListener(TextType::class, [], false, true); $listener->onSubmit($event); $this->assertEquals([], $event->getData()); @@ -219,11 +299,11 @@ public function testOnSubmitNormDataDealsWithNullData() public function testOnSubmitDealsWithObjectBackedIteratorAggregate() { - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('1')); $data = new \ArrayObject([0 => 'first', 1 => 'second', 2 => 'third']); - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true); + $event = new FormEvent($this->builder->getForm(), $data); + $listener = new ResizeFormListener(TextType::class, [], false, true); $listener->onSubmit($event); $this->assertArrayNotHasKey(0, $event->getData()); @@ -232,11 +312,11 @@ public function testOnSubmitDealsWithObjectBackedIteratorAggregate() public function testOnSubmitDealsWithArrayBackedIteratorAggregate() { - $this->form->add($this->getForm('1')); + $this->builder->add($this->getBuilder('1')); $data = new ArrayCollection([0 => 'first', 1 => 'second', 2 => 'third']); - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true); + $event = new FormEvent($this->builder->getForm(), $data); + $listener = new ResizeFormListener(TextType::class, [], false, true); $listener->onSubmit($event); $this->assertArrayNotHasKey(0, $event->getData()); @@ -245,46 +325,37 @@ public function testOnSubmitDealsWithArrayBackedIteratorAggregate() public function testOnSubmitDeleteEmptyNotCompoundEntriesIfAllowDelete() { - $this->form->setData(['0' => 'first', '1' => 'second']); - $this->form->add($this->getForm('0')); - $this->form->add($this->getForm('1')); - - $data = [0 => 'first', 1 => '']; - foreach ($data as $child => $dat) { - $this->form->get($child)->submit($dat); - } - $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, true, true); - $listener->onSubmit($event); + $this->builder->setData(['0' => 'first', '1' => 'second']); + $this->builder->add($this->getBuilder('0')); + $this->builder->add($this->getBuilder('1')); + $this->builder->addEventSubscriber(new ResizeFormListener(TextType::class, [], false, true, true)); - $this->assertEquals([0 => 'first'], $event->getData()); + $form = $this->builder->getForm(); + + $form->submit([0 => 'first', 1 => '']); + + $this->assertEquals([0 => 'first'], $form->getData()); } public function testOnSubmitDeleteEmptyCompoundEntriesIfAllowDelete() { - $this->form->setData(['0' => ['name' => 'John'], '1' => ['name' => 'Jane']]); - $form1 = $this->getBuilder('0') - ->setCompound(true) - ->setDataMapper(new DataMapper()) - ->getForm(); - $form1->add($this->getForm('name')); - $form2 = $this->getBuilder('1') - ->setCompound(true) - ->setDataMapper(new DataMapper()) - ->getForm(); - $form2->add($this->getForm('name')); - $this->form->add($form1); - $this->form->add($form2); - - $data = ['0' => ['name' => 'John'], '1' => ['name' => '']]; - foreach ($data as $child => $dat) { - $this->form->get($child)->submit($dat); - } - $event = new FormEvent($this->form, $data); - $callback = fn ($data) => null === $data['name']; - $listener = new ResizeFormListener('text', [], false, true, $callback); - $listener->onSubmit($event); + $this->builder->setData(['0' => ['name' => 'John'], '1' => ['name' => 'Jane']]); + $this->builder->add('0', NestedType::class); + $this->builder->add('1', NestedType::class); + $callback = fn ($data) => empty($data['name']); + $this->builder->addEventSubscriber(new ResizeFormListener(NestedType::class, [], false, true, $callback)); + + $form = $this->builder->getForm(); + $form->submit(['0' => ['name' => 'John'], '1' => ['name' => '']]); - $this->assertEquals(['0' => ['name' => 'John']], $event->getData()); + $this->assertEquals(['0' => ['name' => 'John']], $form->getData()); + } +} + +class NestedType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder->add('name'); } } From 04cf304af17de3da89851040b6dc6386e4cade86 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 14 Oct 2024 20:03:05 +0200 Subject: [PATCH 58/70] Reduce common control flows --- Extension/DataCollector/FormDataExtractor.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Extension/DataCollector/FormDataExtractor.php b/Extension/DataCollector/FormDataExtractor.php index 158cf32109..f56fe911fa 100644 --- a/Extension/DataCollector/FormDataExtractor.php +++ b/Extension/DataCollector/FormDataExtractor.php @@ -103,15 +103,13 @@ public function extractSubmittedData(FormInterface $form): array continue; } + $errorData['trace'][] = $cause; if ($cause instanceof \Exception) { - $errorData['trace'][] = $cause; $cause = $cause->getPrevious(); continue; } - $errorData['trace'][] = $cause; - break; } From 73c00ef4ced12b43647a37c184f05650c636a539 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 18 Oct 2024 16:04:52 +0200 Subject: [PATCH 59/70] Remove always true/false occurrences --- .../Core/DataTransformer/DateIntervalToArrayTransformer.php | 2 +- Extension/Core/Type/DateType.php | 4 +--- Extension/Core/Type/TimeType.php | 4 +--- Extension/Core/Type/WeekType.php | 4 +--- Extension/Validator/Constraints/FormValidator.php | 2 +- 5 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php b/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php index 18679a9103..8591db1910 100644 --- a/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php +++ b/Extension/Core/DataTransformer/DateIntervalToArrayTransformer.php @@ -139,7 +139,7 @@ public function reverseTransform(mixed $value): ?\DateInterval 'P%sY%sM%sWT%sH%sM%sS', empty($value['years']) ? '0' : $value['years'], empty($value['months']) ? '0' : $value['months'], - empty($value['weeks']) ? '0' : $value['weeks'], + $value['weeks'], empty($value['hours']) ? '0' : $value['hours'], empty($value['minutes']) ? '0' : $value['minutes'], empty($value['seconds']) ? '0' : $value['seconds'] diff --git a/Extension/Core/Type/DateType.php b/Extension/Core/Type/DateType.php index 54f24b89a0..e4aee6e8de 100644 --- a/Extension/Core/Type/DateType.php +++ b/Extension/Core/Type/DateType.php @@ -249,10 +249,8 @@ public function configureOptions(OptionsResolver $resolver): void $choiceTranslationDomainNormalizer = static function (Options $options, $choiceTranslationDomain) { if (\is_array($choiceTranslationDomain)) { - $default = false; - return array_replace( - ['year' => $default, 'month' => $default, 'day' => $default], + ['year' => false, 'month' => false, 'day' => false], $choiceTranslationDomain ); } diff --git a/Extension/Core/Type/TimeType.php b/Extension/Core/Type/TimeType.php index 35549b0419..92cf42d963 100644 --- a/Extension/Core/Type/TimeType.php +++ b/Extension/Core/Type/TimeType.php @@ -274,10 +274,8 @@ public function configureOptions(OptionsResolver $resolver): void $choiceTranslationDomainNormalizer = static function (Options $options, $choiceTranslationDomain) { if (\is_array($choiceTranslationDomain)) { - $default = false; - return array_replace( - ['hour' => $default, 'minute' => $default, 'second' => $default], + ['hour' => false, 'minute' => false, 'second' => false], $choiceTranslationDomain ); } diff --git a/Extension/Core/Type/WeekType.php b/Extension/Core/Type/WeekType.php index ec5cc93037..aea4a6c564 100644 --- a/Extension/Core/Type/WeekType.php +++ b/Extension/Core/Type/WeekType.php @@ -113,10 +113,8 @@ public function configureOptions(OptionsResolver $resolver): void $choiceTranslationDomainNormalizer = static function (Options $options, $choiceTranslationDomain) { if (\is_array($choiceTranslationDomain)) { - $default = false; - return array_replace( - ['year' => $default, 'week' => $default], + ['year' => false, 'week' => false], $choiceTranslationDomain ); } diff --git a/Extension/Validator/Constraints/FormValidator.php b/Extension/Validator/Constraints/FormValidator.php index 703bac1484..8f4ec60f24 100644 --- a/Extension/Validator/Constraints/FormValidator.php +++ b/Extension/Validator/Constraints/FormValidator.php @@ -56,7 +56,7 @@ public function validate(mixed $form, Constraint $formConstraint): void // Validate the data against its own constraints $validateDataGraph = $form->isRoot() && (\is_object($data) || \is_array($data)) - && (($groups && \is_array($groups)) || ($groups instanceof GroupSequence && $groups->groups)) + && (\is_array($groups) || ($groups instanceof GroupSequence && $groups->groups)) ; // Validate the data against the constraints defined in the form From 264cff30f52f12149aff92bbc23e78160a45c2f3 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 27 Nov 2024 12:55:00 +0100 Subject: [PATCH 60/70] [Form] Allow integer for the `calendar` option of `DateType` --- Extension/Core/Type/DateType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/Core/Type/DateType.php b/Extension/Core/Type/DateType.php index e4aee6e8de..36b430e144 100644 --- a/Extension/Core/Type/DateType.php +++ b/Extension/Core/Type/DateType.php @@ -313,7 +313,7 @@ public function configureOptions(OptionsResolver $resolver): void $resolver->setAllowedTypes('months', 'array'); $resolver->setAllowedTypes('days', 'array'); $resolver->setAllowedTypes('input_format', 'string'); - $resolver->setAllowedTypes('calendar', ['null', \IntlCalendar::class]); + $resolver->setAllowedTypes('calendar', ['null', 'int', \IntlCalendar::class]); $resolver->setInfo('calendar', 'The calendar to use for formatting and parsing the date. The value should be an instance of \IntlCalendar. By default, the Gregorian calendar with the default locale is used.'); From 092a89345db25f8e4fc1804a4d3f184766e36e69 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 24 Dec 2024 13:01:45 +0100 Subject: [PATCH 61/70] do not render hidden CSRF token forms with autocomplete set to off --- Extension/Csrf/Type/FormTypeCsrfExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/Csrf/Type/FormTypeCsrfExtension.php b/Extension/Csrf/Type/FormTypeCsrfExtension.php index 10367ae5ff..1cb2b03426 100644 --- a/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -76,7 +76,7 @@ public function finishView(FormView $view, FormInterface $form, array $options): $csrfForm = $factory->createNamed($options['csrf_field_name'], HiddenType::class, $data, [ 'block_prefix' => 'csrf_token', 'mapped' => false, - 'attr' => $this->fieldAttr + ['autocomplete' => 'off'], + 'attr' => $this->fieldAttr, ]); $view->children[$options['csrf_field_name']] = $csrfForm->createView($view); From 7209804c018b88cc2b0beabe38eef91b83f1d69a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 7 Feb 2025 19:13:17 +0100 Subject: [PATCH 62/70] [Form][FrameworkBundle] Use auto-configuration to make the default CSRF token id apply only to the app; not to bundles --- DependencyInjection/FormPass.php | 13 ++++++++++++ Extension/Csrf/Type/FormTypeCsrfExtension.php | 16 +++++++++++---- Tests/DependencyInjection/FormPassTest.php | 20 +++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/FormPass.php b/DependencyInjection/FormPass.php index 1d2b2a87e5..bec1782d40 100644 --- a/DependencyInjection/FormPass.php +++ b/DependencyInjection/FormPass.php @@ -47,6 +47,7 @@ private function processFormTypes(ContainerBuilder $container): Reference // Get service locator argument $servicesMap = []; $namespaces = ['Symfony\Component\Form\Extension\Core\Type' => true]; + $csrfTokenIds = []; // Builds an array with fully-qualified type class names as keys and service IDs as values foreach ($container->findTaggedServiceIds('form.type', true) as $serviceId => $tag) { @@ -54,6 +55,10 @@ private function processFormTypes(ContainerBuilder $container): Reference $serviceDefinition = $container->getDefinition($serviceId); $servicesMap[$formType = $serviceDefinition->getClass()] = new Reference($serviceId); $namespaces[substr($formType, 0, strrpos($formType, '\\'))] = true; + + if (isset($tag[0]['csrf_token_id'])) { + $csrfTokenIds[$formType] = $tag[0]['csrf_token_id']; + } } if ($container->hasDefinition('console.command.form_debug')) { @@ -62,6 +67,14 @@ private function processFormTypes(ContainerBuilder $container): Reference $commandDefinition->setArgument(2, array_keys($servicesMap)); } + if ($csrfTokenIds && $container->hasDefinition('form.type_extension.csrf')) { + $csrfExtension = $container->getDefinition('form.type_extension.csrf'); + + if (8 <= \count($csrfExtension->getArguments())) { + $csrfExtension->replaceArgument(7, $csrfTokenIds); + } + } + return ServiceLocatorTagPass::register($container, $servicesMap); } diff --git a/Extension/Csrf/Type/FormTypeCsrfExtension.php b/Extension/Csrf/Type/FormTypeCsrfExtension.php index 1cb2b03426..a12b9a41ee 100644 --- a/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -37,7 +37,7 @@ public function __construct( private ?string $translationDomain = null, private ?ServerParams $serverParams = null, private array $fieldAttr = [], - private ?string $defaultTokenId = null, + private string|array|null $defaultTokenId = null, ) { } @@ -50,11 +50,17 @@ public function buildForm(FormBuilderInterface $builder, array $options): void return; } + $csrfTokenId = $options['csrf_token_id'] + ?: $this->defaultTokenId[$builder->getType()->getInnerType()::class] + ?? $builder->getName() + ?: $builder->getType()->getInnerType()::class; + $builder->setAttribute('csrf_token_id', $csrfTokenId); + $builder ->addEventSubscriber(new CsrfValidationListener( $options['csrf_field_name'], $options['csrf_token_manager'], - $options['csrf_token_id'] ?: ($builder->getName() ?: $builder->getType()->getInnerType()::class), + $csrfTokenId, $options['csrf_message'], $this->translator, $this->translationDomain, @@ -70,7 +76,7 @@ public function finishView(FormView $view, FormInterface $form, array $options): { if ($options['csrf_protection'] && !$view->parent && $options['compound']) { $factory = $form->getConfig()->getFormFactory(); - $tokenId = $options['csrf_token_id'] ?: ($form->getName() ?: $form->getConfig()->getType()->getInnerType()::class); + $tokenId = $form->getConfig()->getAttribute('csrf_token_id'); $data = (string) $options['csrf_token_manager']->getToken($tokenId); $csrfForm = $factory->createNamed($options['csrf_field_name'], HiddenType::class, $data, [ @@ -85,9 +91,11 @@ public function finishView(FormView $view, FormInterface $form, array $options): public function configureOptions(OptionsResolver $resolver): void { - if ($defaultTokenId = $this->defaultTokenId) { + if (\is_string($defaultTokenId = $this->defaultTokenId) && $defaultTokenId) { $defaultTokenManager = $this->defaultTokenManager; $defaultTokenId = static fn (Options $options) => $options['csrf_token_manager'] === $defaultTokenManager ? $defaultTokenId : null; + } else { + $defaultTokenId = null; } $resolver->setDefaults([ diff --git a/Tests/DependencyInjection/FormPassTest.php b/Tests/DependencyInjection/FormPassTest.php index e9a7b50346..f0ccd3f095 100644 --- a/Tests/DependencyInjection/FormPassTest.php +++ b/Tests/DependencyInjection/FormPassTest.php @@ -21,6 +21,7 @@ use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Command\DebugCommand; use Symfony\Component\Form\DependencyInjection\FormPass; +use Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension; use Symfony\Component\Form\FormRegistry; /** @@ -95,6 +96,25 @@ public function testAddTaggedTypesToDebugCommand() ); } + public function testAddTaggedTypesToCsrfTypeExtension() + { + $container = $this->createContainerBuilder(); + + $container->register('form.registry', FormRegistry::class); + $container->register('form.type_extension.csrf', FormTypeCsrfExtension::class) + ->setArguments([null, true, '_token', null, 'validator.translation_domain', null, [], null]) + ->setPublic(true); + + $container->setDefinition('form.extension', $this->createExtensionDefinition()); + $container->register('my.type1', __CLASS__.'_Type1')->addTag('form.type', ['csrf_token_id' => 'the_token_id']); + $container->register('my.type2', __CLASS__.'_Type2')->addTag('form.type'); + + $container->compile(); + + $csrfDefinition = $container->getDefinition('form.type_extension.csrf'); + $this->assertSame([__CLASS__.'_Type1' => 'the_token_id'], $csrfDefinition->getArgument(7)); + } + /** * @dataProvider addTaggedTypeExtensionsDataProvider */ From e982e148bdaa5e0d70087237ef059528cd8be6d9 Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Mon, 17 Mar 2025 01:07:55 -0300 Subject: [PATCH 63/70] fix translation in spanish --- Resources/translations/validators.es.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/translations/validators.es.xlf b/Resources/translations/validators.es.xlf index 301e2b33f7..a9989737c3 100644 --- a/Resources/translations/validators.es.xlf +++ b/Resources/translations/validators.es.xlf @@ -52,7 +52,7 @@ Please enter a valid date. - Por favor, ingrese una fecha valida. + Por favor, ingrese una fecha válida. Please select a valid file. From 3929e2a60a828f39df6765fb49d224cc629fa529 Mon Sep 17 00:00:00 2001 From: Alexander Hofbauer Date: Wed, 26 Mar 2025 17:02:02 +0100 Subject: [PATCH 64/70] [Form] Use duplicate_preferred_choices to set value of ChoiceType When the preferred choices are not duplicated an option has to be selected in the group of preferred choices. Closes #58561 --- Extension/Core/Type/ChoiceType.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Extension/Core/Type/ChoiceType.php b/Extension/Core/Type/ChoiceType.php index 35dcf1b1b9..32bc677667 100644 --- a/Extension/Core/Type/ChoiceType.php +++ b/Extension/Core/Type/ChoiceType.php @@ -281,6 +281,8 @@ public function buildView(FormView $view, FormInterface $form, array $options) */ public function finishView(FormView $view, FormInterface $form, array $options) { + $view->vars['duplicate_preferred_choices'] = $options['duplicate_preferred_choices']; + if ($options['expanded']) { // Radio buttons should have the same name as the parent $childName = $view->vars['full_name']; From 58471f52a058d64b5d128c26695191039b6199b5 Mon Sep 17 00:00:00 2001 From: Tom Hart <1374434+TomHart@users.noreply.github.com> Date: Fri, 4 Apr 2025 10:13:44 +0100 Subject: [PATCH 65/70] Update validators.pt.xlf --- Resources/translations/validators.pt.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/translations/validators.pt.xlf b/Resources/translations/validators.pt.xlf index 755108f357..673e79f420 100644 --- a/Resources/translations/validators.pt.xlf +++ b/Resources/translations/validators.pt.xlf @@ -24,7 +24,7 @@ The selected choice is invalid. - A escolha seleccionada é inválida. + A escolha selecionada é inválida. The collection is invalid. From c87b96dcb7e22673c389f5d06a8a2bb916cc26c4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 8 Apr 2025 16:34:28 +0200 Subject: [PATCH 66/70] skip test if the installed ICU version is too modern --- .../DateTimeToLocalizedStringTransformerTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 189c409f4d..91b3cf213b 100644 --- a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer; use Symfony\Component\Form\Tests\Extension\Core\DataTransformer\Traits\DateTimeEqualsTrait; +use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Util\IntlTestHelper; class DateTimeToLocalizedStringTransformerTest extends BaseDateTimeTransformerTestCase @@ -236,6 +237,10 @@ public function testReverseTransformFullTime() public function testReverseTransformFromDifferentLocale() { + if (version_compare(Intl::getIcuVersion(), '71.1', '>')) { + $this->markTestSkipped('ICU version 71.1 or lower is required.'); + }; + \Locale::setDefault('en_US'); $transformer = new DateTimeToLocalizedStringTransformer('UTC', 'UTC'); From 48c8d9bb1f891a84904f1e7f53e876697776fdfc Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 27 Apr 2025 15:26:02 +0200 Subject: [PATCH 67/70] Remove unneeded use statements --- Extension/Core/Type/TimeType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Extension/Core/Type/TimeType.php b/Extension/Core/Type/TimeType.php index 512a830bb2..4bd1a9433c 100644 --- a/Extension/Core/Type/TimeType.php +++ b/Extension/Core/Type/TimeType.php @@ -12,13 +12,13 @@ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Event\PreSubmitEvent; use Symfony\Component\Form\Exception\InvalidConfigurationException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; -use Symfony\Component\Form\Event\PreSubmitEvent; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; From de5c3d7dbb5538aba1476ed34f0197e501c06a39 Mon Sep 17 00:00:00 2001 From: wkania Date: Sun, 27 Apr 2025 15:58:34 +0200 Subject: [PATCH 68/70] Unnecessary cast, return, semicolon and comma --- .../DateTimeToLocalizedStringTransformerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 91b3cf213b..6cbf6b9377 100644 --- a/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -239,7 +239,7 @@ public function testReverseTransformFromDifferentLocale() { if (version_compare(Intl::getIcuVersion(), '71.1', '>')) { $this->markTestSkipped('ICU version 71.1 or lower is required.'); - }; + } \Locale::setDefault('en_US'); From 02275ed54317b830fc54f7be68bb2f1172cdfc43 Mon Sep 17 00:00:00 2001 From: wkania Date: Sun, 27 Apr 2025 16:24:15 +0200 Subject: [PATCH 69/70] Fix overwriting an array element --- Extension/Core/Type/WeekType.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Extension/Core/Type/WeekType.php b/Extension/Core/Type/WeekType.php index 8027a41a99..778cc2aeb0 100644 --- a/Extension/Core/Type/WeekType.php +++ b/Extension/Core/Type/WeekType.php @@ -42,7 +42,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) } else { $yearOptions = $weekOptions = [ 'error_bubbling' => true, - 'empty_data' => '', ]; // when the form is compound the entries of the array are ignored in favor of children data // so we need to handle the cascade setting here From aed57cbb5ffe9fe169cf48c7fdcb2d482670ae5e Mon Sep 17 00:00:00 2001 From: wkania Date: Sun, 27 Apr 2025 18:08:38 +0200 Subject: [PATCH 70/70] Fix return type is non-nullable --- Tests/Fixtures/TestExtension.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Fixtures/TestExtension.php b/Tests/Fixtures/TestExtension.php index 44725a69c7..2704ee5303 100644 --- a/Tests/Fixtures/TestExtension.php +++ b/Tests/Fixtures/TestExtension.php @@ -34,7 +34,7 @@ public function addType(FormTypeInterface $type) public function getType($name): FormTypeInterface { - return $this->types[$name] ?? null; + return $this->types[$name]; } public function hasType($name): bool