From 0ee9933fd7fdc984f020cb5fe9792e43c39676f5 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sun, 26 Nov 2023 10:27:26 +0100 Subject: [PATCH 01/19] [Validator] Made tests forward-compatible with ICU 72.1 --- .../Tests/ConstraintValidatorTest.php | 18 ++--- .../Constraints/EqualToValidatorTest.php | 11 +-- .../GreaterThanOrEqualValidatorTest.php | 11 +-- .../Constraints/GreaterThanValidatorTest.php | 17 +++-- .../Constraints/IdenticalToValidatorTest.php | 9 ++- .../LessThanOrEqualValidatorTest.php | 11 +-- .../Constraints/LessThanValidatorTest.php | 17 +++-- .../Constraints/NotEqualToValidatorTest.php | 11 +-- .../NotIdenticalToValidatorTest.php | 11 +-- .../Tests/Constraints/RangeValidatorTest.php | 70 +++++++++---------- .../Validator/Tests/IcuCompatibilityTrait.php | 30 ++++++++ 11 files changed, 135 insertions(+), 81 deletions(-) create mode 100644 src/Symfony/Component/Validator/Tests/IcuCompatibilityTrait.php diff --git a/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php b/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php index 7fb4a91c6cdd4..e5ec479141eda 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php @@ -18,17 +18,19 @@ class ConstraintValidatorTest extends TestCase { + use IcuCompatibilityTrait; + /** * @dataProvider formatValueProvider */ - public function testFormatValue($expected, $value, $format = 0) + public function testFormatValue(string $expected, $value, int $format = 0) { \Locale::setDefault('en'); $this->assertSame($expected, (new TestFormatValueConstraintValidator())->formatValueProxy($value, $format)); } - public static function formatValueProvider() + public static function formatValueProvider(): array { $defaultTimezone = date_default_timezone_get(); date_default_timezone_set('Europe/Moscow'); // GMT+3 @@ -43,10 +45,10 @@ public static function formatValueProvider() ['object', $toString = new TestToStringObject()], ['ccc', $toString, ConstraintValidator::OBJECT_TO_STRING], ['object', $dateTime = new \DateTimeImmutable('1971-02-02T08:00:00UTC')], - [class_exists(\IntlDateFormatter::class) ? 'Oct 4, 2019, 11:02 AM' : '2019-10-04 11:02:03', new \DateTimeImmutable('2019-10-04T11:02:03+09:00'), ConstraintValidator::PRETTY_DATE], - [class_exists(\IntlDateFormatter::class) ? 'Feb 2, 1971, 8:00 AM' : '1971-02-02 08:00:00', $dateTime, ConstraintValidator::PRETTY_DATE], - [class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 6:00 AM' : '1970-01-01 06:00:00', new \DateTimeImmutable('1970-01-01T06:00:00Z'), ConstraintValidator::PRETTY_DATE], - [class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 3:00 PM' : '1970-01-01 15:00:00', (new \DateTimeImmutable('1970-01-01T23:00:00'))->setTimezone(new \DateTimeZone('America/New_York')), ConstraintValidator::PRETTY_DATE], + [class_exists(\IntlDateFormatter::class) ? static::normalizeIcuSpaces("Oct 4, 2019, 11:02\u{202F}AM") : '2019-10-04 11:02:03', new \DateTimeImmutable('2019-10-04T11:02:03+09:00'), ConstraintValidator::PRETTY_DATE], + [class_exists(\IntlDateFormatter::class) ? static::normalizeIcuSpaces("Feb 2, 1971, 8:00\u{202F}AM") : '1971-02-02 08:00:00', $dateTime, ConstraintValidator::PRETTY_DATE], + [class_exists(\IntlDateFormatter::class) ? static::normalizeIcuSpaces("Jan 1, 1970, 6:00\u{202F}AM") : '1970-01-01 06:00:00', new \DateTimeImmutable('1970-01-01T06:00:00Z'), ConstraintValidator::PRETTY_DATE], + [class_exists(\IntlDateFormatter::class) ? static::normalizeIcuSpaces("Jan 1, 1970, 3:00\u{202F}PM") : '1970-01-01 15:00:00', (new \DateTimeImmutable('1970-01-01T23:00:00'))->setTimezone(new \DateTimeZone('America/New_York')), ConstraintValidator::PRETTY_DATE], ]; if (\PHP_VERSION_ID >= 80100) { @@ -61,11 +63,11 @@ public static function formatValueProvider() final class TestFormatValueConstraintValidator extends ConstraintValidator { - public function validate($value, Constraint $constraint) + public function validate($value, Constraint $constraint): void { } - public function formatValueProxy($value, $format) + public function formatValueProxy($value, int $format): string { return $this->formatValue($value, $format); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php index 628bd2534ff28..c55757902a750 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php @@ -14,12 +14,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\EqualTo; use Symfony\Component\Validator\Constraints\EqualToValidator; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; /** * @author Daniel Holmes */ class EqualToValidatorTest extends AbstractComparisonValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new EqualToValidator(); @@ -70,14 +73,14 @@ public static function provideInvalidComparisons(): array return [ [1, '1', 2, '2', 'int'], ['22', '"22"', '333', '"333"', 'string'], - [new \DateTime('2001-01-01'), 'Jan 1, 2001, 12:00 AM', new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2001-01-01'), 'Jan 1, 2001, 12:00 AM', '2000-01-01', 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2001-01-01 UTC'), 'Jan 1, 2001, 12:00 AM', '2000-01-01 UTC', 'Jan 1, 2000, 12:00 AM', 'DateTime'], + [new \DateTime('2001-01-01'), self::normalizeIcuSpaces("Jan 1, 2001, 12:00\u{202F}AM"), new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2001-01-01'), self::normalizeIcuSpaces("Jan 1, 2001, 12:00\u{202F}AM"), '2000-01-01', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2001-01-01 UTC'), self::normalizeIcuSpaces("Jan 1, 2001, 12:00\u{202F}AM"), '2000-01-01 UTC', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], [new ComparisonTest_Class(4), '4', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], ]; } - public static function provideComparisonsToNullValueAtPropertyPath() + public static function provideComparisonsToNullValueAtPropertyPath(): array { return [ [5, '5', false], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php index fd3622e870125..367c670f0fe5a 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php @@ -14,12 +14,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\GreaterThanOrEqual; use Symfony\Component\Validator\Constraints\GreaterThanOrEqualValidator; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; /** * @author Daniel Holmes */ class GreaterThanOrEqualValidatorTest extends AbstractComparisonValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new GreaterThanOrEqualValidator(); @@ -73,14 +76,14 @@ public static function provideInvalidComparisons(): array { return [ [1, '1', 2, '2', 'int'], - [new \DateTime('2000/01/01'), 'Jan 1, 2000, 12:00 AM', new \DateTime('2005/01/01'), 'Jan 1, 2005, 12:00 AM', 'DateTime'], - [new \DateTime('2000/01/01'), 'Jan 1, 2000, 12:00 AM', '2005/01/01', 'Jan 1, 2005, 12:00 AM', 'DateTime'], - [new \DateTime('2000/01/01 UTC'), 'Jan 1, 2000, 12:00 AM', '2005/01/01 UTC', 'Jan 1, 2005, 12:00 AM', 'DateTime'], + [new \DateTime('2000/01/01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), new \DateTime('2005/01/01'), self::normalizeIcuSpaces("Jan 1, 2005, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000/01/01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2005/01/01', self::normalizeIcuSpaces("Jan 1, 2005, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000/01/01 UTC'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2005/01/01 UTC', self::normalizeIcuSpaces("Jan 1, 2005, 12:00\u{202F}AM"), 'DateTime'], ['b', '"b"', 'c', '"c"', 'string'], ]; } - public static function provideComparisonsToNullValueAtPropertyPath() + public static function provideComparisonsToNullValueAtPropertyPath(): array { return [ [5, '5', true], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php index 5f68e6fe2723c..1816788b84e5c 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php @@ -14,12 +14,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\GreaterThan; use Symfony\Component\Validator\Constraints\GreaterThanValidator; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; /** * @author Daniel Holmes */ class GreaterThanValidatorTest extends AbstractComparisonValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new GreaterThanValidator(); @@ -69,12 +72,12 @@ public static function provideInvalidComparisons(): array return [ [1, '1', 2, '2', 'int'], [2, '2', 2, '2', 'int'], - [new \DateTime('2000/01/01'), 'Jan 1, 2000, 12:00 AM', new \DateTime('2005/01/01'), 'Jan 1, 2005, 12:00 AM', 'DateTime'], - [new \DateTime('2000/01/01'), 'Jan 1, 2000, 12:00 AM', new \DateTime('2000/01/01'), 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2000/01/01'), 'Jan 1, 2000, 12:00 AM', '2005/01/01', 'Jan 1, 2005, 12:00 AM', 'DateTime'], - [new \DateTime('2000/01/01'), 'Jan 1, 2000, 12:00 AM', '2000/01/01', 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2000/01/01 UTC'), 'Jan 1, 2000, 12:00 AM', '2005/01/01 UTC', 'Jan 1, 2005, 12:00 AM', 'DateTime'], - [new \DateTime('2000/01/01 UTC'), 'Jan 1, 2000, 12:00 AM', '2000/01/01 UTC', 'Jan 1, 2000, 12:00 AM', 'DateTime'], + [new \DateTime('2000/01/01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), new \DateTime('2005/01/01'), self::normalizeIcuSpaces("Jan 1, 2005, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000/01/01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), new \DateTime('2000/01/01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000/01/01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2005/01/01', self::normalizeIcuSpaces("Jan 1, 2005, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000/01/01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2000/01/01', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000/01/01 UTC'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2005/01/01 UTC', self::normalizeIcuSpaces("Jan 1, 2005, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000/01/01 UTC'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2000/01/01 UTC', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], [new ComparisonTest_Class(4), '4', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], [new ComparisonTest_Class(5), '5', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], ['22', '"22"', '333', '"333"', 'string'], @@ -82,7 +85,7 @@ public static function provideInvalidComparisons(): array ]; } - public static function provideComparisonsToNullValueAtPropertyPath() + public static function provideComparisonsToNullValueAtPropertyPath(): array { return [ [5, '5', true], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php index f9cc83b515b40..165e31823f530 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php @@ -14,12 +14,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\IdenticalTo; use Symfony\Component\Validator\Constraints\IdenticalToValidator; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; /** * @author Daniel Holmes */ class IdenticalToValidatorTest extends AbstractComparisonValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new IdenticalToValidator(); @@ -90,13 +93,13 @@ public static function provideInvalidComparisons(): array [1, '1', 2, '2', 'int'], [2, '2', '2', '"2"', 'string'], ['22', '"22"', '333', '"333"', 'string'], - [new \DateTime('2001-01-01'), 'Jan 1, 2001, 12:00 AM', new \DateTime('2001-01-01'), 'Jan 1, 2001, 12:00 AM', 'DateTime'], - [new \DateTime('2001-01-01'), 'Jan 1, 2001, 12:00 AM', new \DateTime('1999-01-01'), 'Jan 1, 1999, 12:00 AM', 'DateTime'], + [new \DateTime('2001-01-01'), self::normalizeIcuSpaces("Jan 1, 2001, 12:00\u{202F}AM"), new \DateTime('2001-01-01'), self::normalizeIcuSpaces("Jan 1, 2001, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2001-01-01'), self::normalizeIcuSpaces("Jan 1, 2001, 12:00\u{202F}AM"), new \DateTime('1999-01-01'), self::normalizeIcuSpaces("Jan 1, 1999, 12:00\u{202F}AM"), 'DateTime'], [new ComparisonTest_Class(4), '4', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], ]; } - public static function provideComparisonsToNullValueAtPropertyPath() + public static function provideComparisonsToNullValueAtPropertyPath(): array { return [ [5, '5', false], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php index 6072f6f2275e9..2526987ec3daa 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php @@ -14,12 +14,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\LessThanOrEqual; use Symfony\Component\Validator\Constraints\LessThanOrEqualValidator; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; /** * @author Daniel Holmes */ class LessThanOrEqualValidatorTest extends AbstractComparisonValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new LessThanOrEqualValidator(); @@ -75,15 +78,15 @@ public static function provideInvalidComparisons(): array { return [ [2, '2', 1, '1', 'int'], - [new \DateTime('2010-01-01'), 'Jan 1, 2010, 12:00 AM', new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2010-01-01'), 'Jan 1, 2010, 12:00 AM', '2000-01-01', 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2010-01-01 UTC'), 'Jan 1, 2010, 12:00 AM', '2000-01-01 UTC', 'Jan 1, 2000, 12:00 AM', 'DateTime'], + [new \DateTime('2010-01-01'), self::normalizeIcuSpaces("Jan 1, 2010, 12:00\u{202F}AM"), new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2010-01-01'), self::normalizeIcuSpaces("Jan 1, 2010, 12:00\u{202F}AM"), '2000-01-01', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2010-01-01 UTC'), self::normalizeIcuSpaces("Jan 1, 2010, 12:00\u{202F}AM"), '2000-01-01 UTC', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], [new ComparisonTest_Class(5), '5', new ComparisonTest_Class(4), '4', __NAMESPACE__.'\ComparisonTest_Class'], ['c', '"c"', 'b', '"b"', 'string'], ]; } - public static function provideComparisonsToNullValueAtPropertyPath() + public static function provideComparisonsToNullValueAtPropertyPath(): array { return [ [5, '5', true], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php index acc815a04530b..e8106b6cb01ef 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php @@ -14,12 +14,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\LessThan; use Symfony\Component\Validator\Constraints\LessThanValidator; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; /** * @author Daniel Holmes */ class LessThanValidatorTest extends AbstractComparisonValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new LessThanValidator(); @@ -69,19 +72,19 @@ public static function provideInvalidComparisons(): array return [ [3, '3', 2, '2', 'int'], [2, '2', 2, '2', 'int'], - [new \DateTime('2010-01-01'), 'Jan 1, 2010, 12:00 AM', new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2010-01-01'), 'Jan 1, 2010, 12:00 AM', '2000-01-01', 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', '2000-01-01', 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2010-01-01 UTC'), 'Jan 1, 2010, 12:00 AM', '2000-01-01 UTC', 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2000-01-01 UTC'), 'Jan 1, 2000, 12:00 AM', '2000-01-01 UTC', 'Jan 1, 2000, 12:00 AM', 'DateTime'], + [new \DateTime('2010-01-01'), self::normalizeIcuSpaces("Jan 1, 2010, 12:00\u{202F}AM"), new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2010-01-01'), self::normalizeIcuSpaces("Jan 1, 2010, 12:00\u{202F}AM"), '2000-01-01', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2000-01-01', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2010-01-01 UTC'), self::normalizeIcuSpaces("Jan 1, 2010, 12:00\u{202F}AM"), '2000-01-01 UTC', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000-01-01 UTC'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2000-01-01 UTC', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], [new ComparisonTest_Class(5), '5', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], [new ComparisonTest_Class(6), '6', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], ['333', '"333"', '22', '"22"', 'string'], ]; } - public static function provideComparisonsToNullValueAtPropertyPath() + public static function provideComparisonsToNullValueAtPropertyPath(): array { return [ [5, '5', true], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php index 465458b07c0d4..65d4329efedd1 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php @@ -14,12 +14,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\NotEqualTo; use Symfony\Component\Validator\Constraints\NotEqualToValidator; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; /** * @author Daniel Holmes */ class NotEqualToValidatorTest extends AbstractComparisonValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new NotEqualToValidator(); @@ -70,14 +73,14 @@ public static function provideInvalidComparisons(): array [3, '3', 3, '3', 'int'], ['2', '"2"', 2, '2', 'int'], ['a', '"a"', 'a', '"a"', 'string'], - [new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2000-01-01'), 'Jan 1, 2000, 12:00 AM', '2000-01-01', 'Jan 1, 2000, 12:00 AM', 'DateTime'], - [new \DateTime('2000-01-01 UTC'), 'Jan 1, 2000, 12:00 AM', '2000-01-01 UTC', 'Jan 1, 2000, 12:00 AM', 'DateTime'], + [new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000-01-01'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2000-01-01', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], + [new \DateTime('2000-01-01 UTC'), self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), '2000-01-01 UTC', self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], [new ComparisonTest_Class(5), '5', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], ]; } - public static function provideComparisonsToNullValueAtPropertyPath() + public static function provideComparisonsToNullValueAtPropertyPath(): array { return [ [5, '5', true], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php index 49cff99122d9d..a67aa8cb98cfb 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php @@ -14,12 +14,15 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\NotIdenticalTo; use Symfony\Component\Validator\Constraints\NotIdenticalToValidator; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; /** * @author Daniel Holmes */ class NotIdenticalToValidatorTest extends AbstractComparisonValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new NotIdenticalToValidator(); @@ -86,17 +89,15 @@ public static function provideInvalidComparisons(): array $date = new \DateTime('2000-01-01'); $object = new ComparisonTest_Class(2); - $comparisons = [ + return [ [3, '3', 3, '3', 'int'], ['a', '"a"', 'a', '"a"', 'string'], - [$date, 'Jan 1, 2000, 12:00 AM', $date, 'Jan 1, 2000, 12:00 AM', 'DateTime'], + [$date, self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), $date, self::normalizeIcuSpaces("Jan 1, 2000, 12:00\u{202F}AM"), 'DateTime'], [$object, '2', $object, '2', __NAMESPACE__.'\ComparisonTest_Class'], ]; - - return $comparisons; } - public static function provideComparisonsToNullValueAtPropertyPath() + public static function provideComparisonsToNullValueAtPropertyPath(): array { return [ [5, '5', true], diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php index 2f7da24176cfb..83a2a3d596048 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RangeValidatorTest.php @@ -16,9 +16,12 @@ use Symfony\Component\Validator\Constraints\RangeValidator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; +use Symfony\Component\Validator\Tests\IcuCompatibilityTrait; class RangeValidatorTest extends ConstraintValidatorTestCase { + use IcuCompatibilityTrait; + protected function createValidator() { return new RangeValidator(); @@ -31,7 +34,7 @@ public function testNullIsValid() $this->assertNoViolation(); } - public static function getTenToTwenty() + public static function getTenToTwenty(): array { return [ [10.00001], @@ -55,7 +58,7 @@ public static function getLessThanTen() ]; } - public static function getMoreThanTwenty() + public static function getMoreThanTwenty(): array { return [ [20.000001, '20.000001'], @@ -291,7 +294,7 @@ public function testInvalidValuesCombinedMinNamed($value, $formattedValue) ->assertRaised(); } - public static function getTenthToTwentiethMarch2014() + public static function getTenthToTwentiethMarch2014(): array { // The provider runs before setUp(), so we need to manually fix // the default timezone @@ -302,18 +305,17 @@ public static function getTenthToTwentiethMarch2014() [new \DateTime('March 10, 2014')], [new \DateTime('March 15, 2014')], [new \DateTime('March 20, 2014')], + [new \DateTimeImmutable('March 10, 2014')], + [new \DateTimeImmutable('March 15, 2014')], + [new \DateTimeImmutable('March 20, 2014')], ]; - $tests[] = [new \DateTimeImmutable('March 10, 2014')]; - $tests[] = [new \DateTimeImmutable('March 15, 2014')]; - $tests[] = [new \DateTimeImmutable('March 20, 2014')]; - date_default_timezone_set($timezone); return $tests; } - public static function getSoonerThanTenthMarch2014() + public static function getSoonerThanTenthMarch2014(): array { // The provider runs before setUp(), so we need to manually fix // the default timezone @@ -321,19 +323,18 @@ public static function getSoonerThanTenthMarch2014() date_default_timezone_set('UTC'); $tests = [ - [new \DateTime('March 20, 2013'), 'Mar 20, 2013, 12:00 AM'], - [new \DateTime('March 9, 2014'), 'Mar 9, 2014, 12:00 AM'], + [new \DateTime('March 20, 2013'), self::normalizeIcuSpaces("Mar 20, 2013, 12:00\u{202F}AM")], + [new \DateTime('March 9, 2014'), self::normalizeIcuSpaces("Mar 9, 2014, 12:00\u{202F}AM")], + [new \DateTimeImmutable('March 20, 2013'), self::normalizeIcuSpaces("Mar 20, 2013, 12:00\u{202F}AM")], + [new \DateTimeImmutable('March 9, 2014'), self::normalizeIcuSpaces("Mar 9, 2014, 12:00\u{202F}AM")], ]; - $tests[] = [new \DateTimeImmutable('March 20, 2013'), 'Mar 20, 2013, 12:00 AM']; - $tests[] = [new \DateTimeImmutable('March 9, 2014'), 'Mar 9, 2014, 12:00 AM']; - date_default_timezone_set($timezone); return $tests; } - public static function getLaterThanTwentiethMarch2014() + public static function getLaterThanTwentiethMarch2014(): array { // The provider runs before setUp(), so we need to manually fix // the default timezone @@ -341,13 +342,12 @@ public static function getLaterThanTwentiethMarch2014() date_default_timezone_set('UTC'); $tests = [ - [new \DateTime('March 21, 2014'), 'Mar 21, 2014, 12:00 AM'], - [new \DateTime('March 9, 2015'), 'Mar 9, 2015, 12:00 AM'], + [new \DateTime('March 21, 2014'), self::normalizeIcuSpaces("Mar 21, 2014, 12:00\u{202F}AM")], + [new \DateTime('March 9, 2015'), self::normalizeIcuSpaces("Mar 9, 2015, 12:00\u{202F}AM")], + [new \DateTimeImmutable('March 21, 2014'), self::normalizeIcuSpaces("Mar 21, 2014, 12:00\u{202F}AM")], + [new \DateTimeImmutable('March 9, 2015'), self::normalizeIcuSpaces("Mar 9, 2015, 12:00\u{202F}AM")], ]; - $tests[] = [new \DateTimeImmutable('March 21, 2014'), 'Mar 21, 2014, 12:00 AM']; - $tests[] = [new \DateTimeImmutable('March 9, 2015'), 'Mar 9, 2015, 12:00 AM']; - date_default_timezone_set($timezone); return $tests; @@ -389,7 +389,7 @@ public function testValidDatesMinMax($value) /** * @dataProvider getSoonerThanTenthMarch2014 */ - public function testInvalidDatesMin($value, $dateTimeAsString) + public function testInvalidDatesMin(\DateTimeInterface $value, string $dateTimeAsString) { // Conversion of dates to string differs between ICU versions // Make sure we have the correct version loaded @@ -404,7 +404,7 @@ public function testInvalidDatesMin($value, $dateTimeAsString) $this->buildViolation('myMessage') ->setParameter('{{ value }}', $dateTimeAsString) - ->setParameter('{{ limit }}', 'Mar 10, 2014, 12:00 AM') + ->setParameter('{{ limit }}', self::normalizeIcuSpaces("Mar 10, 2014, 12:00\u{202F}AM")) ->setCode(Range::TOO_LOW_ERROR) ->assertRaised(); } @@ -412,7 +412,7 @@ public function testInvalidDatesMin($value, $dateTimeAsString) /** * @dataProvider getLaterThanTwentiethMarch2014 */ - public function testInvalidDatesMax($value, $dateTimeAsString) + public function testInvalidDatesMax(\DateTimeInterface $value, string $dateTimeAsString) { // Conversion of dates to string differs between ICU versions // Make sure we have the correct version loaded @@ -427,7 +427,7 @@ public function testInvalidDatesMax($value, $dateTimeAsString) $this->buildViolation('myMessage') ->setParameter('{{ value }}', $dateTimeAsString) - ->setParameter('{{ limit }}', 'Mar 20, 2014, 12:00 AM') + ->setParameter('{{ limit }}', self::normalizeIcuSpaces("Mar 20, 2014, 12:00\u{202F}AM")) ->setCode(Range::TOO_HIGH_ERROR) ->assertRaised(); } @@ -435,7 +435,7 @@ public function testInvalidDatesMax($value, $dateTimeAsString) /** * @dataProvider getLaterThanTwentiethMarch2014 */ - public function testInvalidDatesCombinedMax($value, $dateTimeAsString) + public function testInvalidDatesCombinedMax(\DateTimeInterface $value, string $dateTimeAsString) { // Conversion of dates to string differs between ICU versions // Make sure we have the correct version loaded @@ -451,8 +451,8 @@ public function testInvalidDatesCombinedMax($value, $dateTimeAsString) $this->buildViolation('myNotInRangeMessage') ->setParameter('{{ value }}', $dateTimeAsString) - ->setParameter('{{ min }}', 'Mar 10, 2014, 12:00 AM') - ->setParameter('{{ max }}', 'Mar 20, 2014, 12:00 AM') + ->setParameter('{{ min }}', self::normalizeIcuSpaces("Mar 10, 2014, 12:00\u{202F}AM")) + ->setParameter('{{ max }}', self::normalizeIcuSpaces("Mar 20, 2014, 12:00\u{202F}AM")) ->setCode(Range::NOT_IN_RANGE_ERROR) ->assertRaised(); } @@ -476,13 +476,13 @@ public function testInvalidDatesCombinedMin($value, $dateTimeAsString) $this->buildViolation('myNotInRangeMessage') ->setParameter('{{ value }}', $dateTimeAsString) - ->setParameter('{{ min }}', 'Mar 10, 2014, 12:00 AM') - ->setParameter('{{ max }}', 'Mar 20, 2014, 12:00 AM') + ->setParameter('{{ min }}', self::normalizeIcuSpaces("Mar 10, 2014, 12:00\u{202F}AM")) + ->setParameter('{{ max }}', self::normalizeIcuSpaces("Mar 20, 2014, 12:00\u{202F}AM")) ->setCode(Range::NOT_IN_RANGE_ERROR) ->assertRaised(); } - public function getInvalidValues() + public function getInvalidValues(): array { return [ [9.999999], @@ -952,7 +952,7 @@ public function testInvalidDatesMinPropertyPath($value, $dateTimeAsString) $this->buildViolation('myMessage') ->setParameter('{{ value }}', $dateTimeAsString) - ->setParameter('{{ limit }}', 'Mar 10, 2014, 12:00 AM') + ->setParameter('{{ limit }}', self::normalizeIcuSpaces("Mar 10, 2014, 12:00\u{202F}AM")) ->setParameter('{{ min_limit_path }}', 'value') ->setCode(Range::TOO_LOW_ERROR) ->assertRaised(); @@ -978,7 +978,7 @@ public function testInvalidDatesMaxPropertyPath($value, $dateTimeAsString) $this->buildViolation('myMessage') ->setParameter('{{ value }}', $dateTimeAsString) - ->setParameter('{{ limit }}', 'Mar 20, 2014, 12:00 AM') + ->setParameter('{{ limit }}', self::normalizeIcuSpaces("Mar 20, 2014, 12:00\u{202F}AM")) ->setParameter('{{ max_limit_path }}', 'value') ->setCode(Range::TOO_HIGH_ERROR) ->assertRaised(); @@ -1005,8 +1005,8 @@ public function testInvalidDatesCombinedMaxPropertyPath($value, $dateTimeAsStrin $this->buildViolation('myNotInRangeMessage') ->setParameter('{{ value }}', $dateTimeAsString) - ->setParameter('{{ min }}', 'Mar 10, 2014, 12:00 AM') - ->setParameter('{{ max }}', 'Mar 20, 2014, 12:00 AM') + ->setParameter('{{ min }}', self::normalizeIcuSpaces("Mar 10, 2014, 12:00\u{202F}AM")) + ->setParameter('{{ max }}', self::normalizeIcuSpaces("Mar 20, 2014, 12:00\u{202F}AM")) ->setParameter('{{ max_limit_path }}', 'max') ->setParameter('{{ min_limit_path }}', 'min') ->setCode(Range::NOT_IN_RANGE_ERROR) @@ -1034,8 +1034,8 @@ public function testInvalidDatesCombinedMinPropertyPath($value, $dateTimeAsStrin $this->buildViolation('myNotInRangeMessage') ->setParameter('{{ value }}', $dateTimeAsString) - ->setParameter('{{ min }}', 'Mar 10, 2014, 12:00 AM') - ->setParameter('{{ max }}', 'Mar 20, 2014, 12:00 AM') + ->setParameter('{{ min }}', self::normalizeIcuSpaces("Mar 10, 2014, 12:00\u{202F}AM")) + ->setParameter('{{ max }}', self::normalizeIcuSpaces("Mar 20, 2014, 12:00\u{202F}AM")) ->setParameter('{{ max_limit_path }}', 'max') ->setParameter('{{ min_limit_path }}', 'min') ->setCode(Range::NOT_IN_RANGE_ERROR) diff --git a/src/Symfony/Component/Validator/Tests/IcuCompatibilityTrait.php b/src/Symfony/Component/Validator/Tests/IcuCompatibilityTrait.php new file mode 100644 index 0000000000000..bdd83feb9a309 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/IcuCompatibilityTrait.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests; + +trait IcuCompatibilityTrait +{ + /** + * Normalized spaces in date strings generated by INTL for older ICU versions. + * + * In version 72.1, ICU started to render a narrow non-breaking space (NNBSP) into localized time strings. This + * method allows us to write expectations in a forward-compatible manner. + */ + private static function normalizeIcuSpaces(string $input): string + { + if (\defined('INTL_ICU_VERSION') && version_compare(\INTL_ICU_VERSION, '72.1', '>=')) { + return $input; + } + + return str_replace("\u{202F}", ' ', $input); + } +} From 4f620a1c763bc4073a9e997584e22d91de6d5643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Podhorsk=C3=BD?= Date: Fri, 24 Nov 2023 23:39:32 +0100 Subject: [PATCH 02/19] [String] Fix Inflector for 'icon' --- src/Symfony/Component/String/Inflector/EnglishInflector.php | 3 +++ .../Component/String/Tests/Inflector/EnglishInflectorTest.php | 1 + 2 files changed, 4 insertions(+) diff --git a/src/Symfony/Component/String/Inflector/EnglishInflector.php b/src/Symfony/Component/String/Inflector/EnglishInflector.php index 16efc53a82234..e1bcd87b2ce65 100644 --- a/src/Symfony/Component/String/Inflector/EnglishInflector.php +++ b/src/Symfony/Component/String/Inflector/EnglishInflector.php @@ -253,6 +253,9 @@ final class EnglishInflector implements InflectorInterface // seasons (season), treasons (treason), poisons (poison), lessons (lesson) ['nos', 3, true, true, 'sons'], + // icons (icon) + ['noc', 3, true, true, 'cons'], + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) ['no', 2, true, true, 'a'], diff --git a/src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php b/src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php index 6c7a1c7c6e895..cf66bf05b660c 100644 --- a/src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php +++ b/src/Symfony/Component/String/Tests/Inflector/EnglishInflectorTest.php @@ -295,6 +295,7 @@ public static function pluralizeProvider() ['tree', 'trees'], ['waltz', 'waltzes'], ['wife', 'wives'], + ['icon', 'icons'], // test casing: if the first letter was uppercase, it should remain so ['Man', 'Men'], From fd85bf46463160d338bc2b3f5a3d106e517029e2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 26 Nov 2023 19:07:00 +0100 Subject: [PATCH 03/19] Bump Symfony version to 6.4.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 9ebfac110e959..7825b57cf2148 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.4.0-RC2'; + public const VERSION = '6.4.0-DEV'; public const VERSION_ID = 60400; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'RC2'; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2026'; public const END_OF_LIFE = '11/2027'; From 0182b9f5abc85b8789074581c1c6316dc0b3d034 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sun, 26 Nov 2023 22:19:03 +0100 Subject: [PATCH 04/19] Document BC break with $secret parameter introduction --- UPGRADE-6.4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-6.4.md b/UPGRADE-6.4.md index 182d98cce2f16..be510f1228668 100644 --- a/UPGRADE-6.4.md +++ b/UPGRADE-6.4.md @@ -198,7 +198,7 @@ Security * [BC break] `UserValueResolver` no longer implements `ArgumentValueResolverInterface` * [BC break] Make `PersistentToken` immutable * Deprecate accepting only `DateTime` for `TokenProviderInterface::updateToken()`, use `DateTimeInterface` instead - * Deprecate calling the constructor of `DefaultLoginRateLimiter` with an empty secret + * [BC break] Added required `string $secret` parameter to the constructor of `DefaultLoginRateLimiter` SecurityBundle -------------- From d625fa0c5cf344198c05ada94a52db62c6a866bd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 27 Nov 2023 12:12:09 +0100 Subject: [PATCH 05/19] fix typo --- UPGRADE-6.4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-6.4.md b/UPGRADE-6.4.md index be510f1228668..36b4ea046fc4c 100644 --- a/UPGRADE-6.4.md +++ b/UPGRADE-6.4.md @@ -198,7 +198,7 @@ Security * [BC break] `UserValueResolver` no longer implements `ArgumentValueResolverInterface` * [BC break] Make `PersistentToken` immutable * Deprecate accepting only `DateTime` for `TokenProviderInterface::updateToken()`, use `DateTimeInterface` instead - * [BC break] Added required `string $secret` parameter to the constructor of `DefaultLoginRateLimiter` + * [BC break] Add required `string $secret` parameter to the constructor of `DefaultLoginRateLimiter` SecurityBundle -------------- From bbe8848829f823fc98e344e8aef6b238b28e3d38 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Nov 2023 16:59:28 +0100 Subject: [PATCH 06/19] [VarExporter] Fix serializing objects that implement __sleep() and that are made lazy --- src/Symfony/Component/VarExporter/LazyGhostTrait.php | 2 +- src/Symfony/Component/VarExporter/LazyProxyTrait.php | 2 +- .../Component/VarExporter/Tests/LazyGhostTraitTest.php | 8 +++++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/VarExporter/LazyGhostTrait.php b/src/Symfony/Component/VarExporter/LazyGhostTrait.php index 13e33f59c9bd8..7c3a60507cc15 100644 --- a/src/Symfony/Component/VarExporter/LazyGhostTrait.php +++ b/src/Symfony/Component/VarExporter/LazyGhostTrait.php @@ -355,7 +355,7 @@ public function __serialize(): array $data = []; foreach (parent::__sleep() as $name) { - $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null; + $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$class\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null; if (null === $k) { trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $name), \E_USER_NOTICE); diff --git a/src/Symfony/Component/VarExporter/LazyProxyTrait.php b/src/Symfony/Component/VarExporter/LazyProxyTrait.php index 153c3820844b5..d683ec3f1259d 100644 --- a/src/Symfony/Component/VarExporter/LazyProxyTrait.php +++ b/src/Symfony/Component/VarExporter/LazyProxyTrait.php @@ -295,7 +295,7 @@ public function __serialize(): array $data = []; foreach (parent::__sleep() as $name) { - $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null; + $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0$class\0$name"] ?? $properties[$k = "\0$scope\0$name"] ?? $k = null; if (null === $k) { trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $name), \E_USER_NOTICE); diff --git a/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php b/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php index 0cbbd835b8f64..52a6fe3f6ca8c 100644 --- a/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php +++ b/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php @@ -146,7 +146,13 @@ public function testMagicClass(MagicClass $instance) $instance->bar = 123; $serialized = serialize($instance); $clone = unserialize($serialized); - $this->assertSame(123, $clone->bar); + + if ($instance instanceof ChildMagicClass) { + // ChildMagicClass redefines the $data property but not the __sleep() method + $this->assertFalse(isset($clone->bar)); + } else { + $this->assertSame(123, $clone->bar); + } } public static function provideMagicClass() From 4002efb72ebdd14b54174e6caefc24fc68b8da00 Mon Sep 17 00:00:00 2001 From: Ivan Sarastov Date: Mon, 27 Nov 2023 19:14:29 +0200 Subject: [PATCH 07/19] [Validator] Add missing translations for Bulgarian #51931 --- .../Resources/translations/validators.bg.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf index 455ff81679a1b..d9efdf5751fe1 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Стойността на мрежовата маска трябва да бъде между {{ min }} и {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Името на файла е твърде дълго. Трябва да съдържа не повече от {{ filename_max_length }} символ.|Името на файла е твърде дълго. Трябва да съдържа не повече от {{ filename_max_length }} символа. + + + The password strength is too low. Please use a stronger password. + Сложността на паролата е твърде малка. Моля използвайте по-сложна парола. + + + This value contains characters that are not allowed by the current restriction-level. + Стойността съдържа символи, които не са позволени от текущото ниво на ограничение. + + + Using invisible characters is not allowed. + Използването на невидими символи не е позволено. + + + Mixing numbers from different scripts is not allowed. + Смесването на числа от различни скриптове не е позволено. + + + Using hidden overlay characters is not allowed. + Използването на скрити насложени символи не е позволено. + From b051700a8446a787c455d3f61bb4a1cee2c85429 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Nov 2023 16:46:08 +0100 Subject: [PATCH 08/19] [VarExporter] Work around php/php-src#12695 for lazy objects, fixing nullsafe-related behavior --- .../VarExporter/Internal/Hydrator.php | 8 +++--- .../VarExporter/Internal/LazyObjectState.php | 19 ++++++++------ .../Component/VarExporter/LazyGhostTrait.php | 25 ++++++++++++++----- .../Component/VarExporter/ProxyHelper.php | 3 +++ .../VarExporter/Tests/LazyGhostTraitTest.php | 4 ++- 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/VarExporter/Internal/Hydrator.php b/src/Symfony/Component/VarExporter/Internal/Hydrator.php index f665f6ee15c6e..ebc5914326386 100644 --- a/src/Symfony/Component/VarExporter/Internal/Hydrator.php +++ b/src/Symfony/Component/VarExporter/Internal/Hydrator.php @@ -271,10 +271,10 @@ public static function getPropertyScopes($class) $name = $property->name; if (\ReflectionProperty::IS_PRIVATE & $flags) { - $propertyScopes["\0$class\0$name"] = $propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $class : null]; + $propertyScopes["\0$class\0$name"] = $propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $class : null, $property]; continue; } - $propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $property->class : null]; + $propertyScopes[$name] = [$class, $name, $flags & \ReflectionProperty::IS_READONLY ? $property->class : null, $property]; if (\ReflectionProperty::IS_PROTECTED & $flags) { $propertyScopes["\0*\0$name"] = $propertyScopes[$name]; @@ -288,8 +288,8 @@ public static function getPropertyScopes($class) if (!$property->isStatic()) { $name = $property->name; $readonlyScope = $property->isReadOnly() ? $class : null; - $propertyScopes["\0$class\0$name"] = [$class, $name, $readonlyScope]; - $propertyScopes[$name] ??= [$class, $name, $readonlyScope]; + $propertyScopes["\0$class\0$name"] = [$class, $name, $readonlyScope, $property]; + $propertyScopes[$name] ??= [$class, $name, $readonlyScope, $property]; } } } diff --git a/src/Symfony/Component/VarExporter/Internal/LazyObjectState.php b/src/Symfony/Component/VarExporter/Internal/LazyObjectState.php index 2f649dd1ca481..f47dea4d8e6f5 100644 --- a/src/Symfony/Component/VarExporter/Internal/LazyObjectState.php +++ b/src/Symfony/Component/VarExporter/Internal/LazyObjectState.php @@ -65,29 +65,32 @@ public function initialize($instance, $propertyName, $propertyScope) return $this->status = self::STATUS_INITIALIZED_PARTIAL; } - $status = self::STATUS_UNINITIALIZED_PARTIAL; - if ($initializer = $this->initializer["\0"] ?? null) { if (!\is_array($values = $initializer($instance, LazyObjectRegistry::$defaultProperties[$class]))) { throw new \TypeError(sprintf('The lazy-initializer defined for instance of "%s" must return an array, got "%s".', $class, get_debug_type($values))); } $properties = (array) $instance; foreach ($values as $key => $value) { - if ($k === $key) { - $status = self::STATUS_INITIALIZED_PARTIAL; - } if (!\array_key_exists($key, $properties) && [$scope, $name, $readonlyScope] = $propertyScopes[$key] ?? null) { $scope = $readonlyScope ?? ('*' !== $scope ? $scope : $class); $accessor = LazyObjectRegistry::$classAccessors[$scope] ??= LazyObjectRegistry::getClassAccessors($scope); $accessor['set']($instance, $name, $value); + + if ($k === $key) { + $this->status = self::STATUS_INITIALIZED_PARTIAL; + } } } } - return $status; + return $this->status; + } + + if (self::STATUS_INITIALIZED_PARTIAL === $this->status) { + return self::STATUS_INITIALIZED_PARTIAL; } - $this->status = self::STATUS_INITIALIZED_FULL; + $this->status = self::STATUS_INITIALIZED_PARTIAL; try { if ($defaultProperties = array_diff_key(LazyObjectRegistry::$defaultProperties[$instance::class], $this->skippedProperties)) { @@ -102,7 +105,7 @@ public function initialize($instance, $propertyName, $propertyScope) throw $e; } - return self::STATUS_INITIALIZED_FULL; + return $this->status = self::STATUS_INITIALIZED_FULL; } public function reset($instance): void diff --git a/src/Symfony/Component/VarExporter/LazyGhostTrait.php b/src/Symfony/Component/VarExporter/LazyGhostTrait.php index 13e33f59c9bd8..b0fc3b1cbd3bc 100644 --- a/src/Symfony/Component/VarExporter/LazyGhostTrait.php +++ b/src/Symfony/Component/VarExporter/LazyGhostTrait.php @@ -172,10 +172,18 @@ public function &__get($name): mixed $scope = Registry::getScope($propertyScopes, $class, $name); $state = $this->lazyObjectState ?? null; - if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"])) - && LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !== $state->initialize($this, $name, $readonlyScope ?? $scope) - ) { - goto get_in_scope; + if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"]))) { + if (LazyObjectState::STATUS_INITIALIZED_FULL === $state->status) { + // Work around php/php-src#12695 + $property = $propertyScopes[null === $scope ? $name : "\0$scope\0$name"][3] + ?? (Hydrator::$propertyScopes[$this::class] = Hydrator::getPropertyScopes($this::class))[3]; + } else { + $property = null; + } + + if ($property?->isInitialized($this) ?? LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !== $state->initialize($this, $name, $readonlyScope ?? $scope)) { + goto get_in_scope; + } } } @@ -237,7 +245,9 @@ public function __set($name, $value): void $scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope); $state = $this->lazyObjectState ?? null; - if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"]))) { + if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"])) + && LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status + ) { if (LazyObjectState::STATUS_UNINITIALIZED_FULL === $state->status) { $state->initialize($this, $name, $readonlyScope ?? $scope); } @@ -271,6 +281,7 @@ public function __isset($name): bool $state = $this->lazyObjectState ?? null; if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"])) + && LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status && LazyObjectState::STATUS_UNINITIALIZED_PARTIAL !== $state->initialize($this, $name, $readonlyScope ?? $scope) ) { goto isset_in_scope; @@ -300,7 +311,9 @@ public function __unset($name): void $scope = Registry::getScope($propertyScopes, $class, $name, $readonlyScope); $state = $this->lazyObjectState ?? null; - if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"]))) { + if ($state && ($readonlyScope === $scope || isset($propertyScopes["\0$scope\0$name"])) + && LazyObjectState::STATUS_INITIALIZED_FULL !== $state->status + ) { if (LazyObjectState::STATUS_UNINITIALIZED_FULL === $state->status) { $state->initialize($this, $name, $readonlyScope ?? $scope); } diff --git a/src/Symfony/Component/VarExporter/ProxyHelper.php b/src/Symfony/Component/VarExporter/ProxyHelper.php index 155715de662c9..71530fd55d7f8 100644 --- a/src/Symfony/Component/VarExporter/ProxyHelper.php +++ b/src/Symfony/Component/VarExporter/ProxyHelper.php @@ -322,6 +322,9 @@ private static function exportPropertyScopes(string $parent): string { $propertyScopes = Hydrator::$propertyScopes[$parent] ??= Hydrator::getPropertyScopes($parent); uksort($propertyScopes, 'strnatcmp'); + foreach ($propertyScopes as $k => $v) { + unset($propertyScopes[$k][3]); + } $propertyScopes = VarExporter::export($propertyScopes); $propertyScopes = str_replace(VarExporter::export($parent), 'parent::class', $propertyScopes); $propertyScopes = preg_replace("/(?|(,)\n( ) |\n |,\n (\]))/", '$1$2', $propertyScopes); diff --git a/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php b/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php index 0cbbd835b8f64..83659935d5182 100644 --- a/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php +++ b/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php @@ -65,8 +65,10 @@ public function testUnsetPublic() $this->assertSame(["\0".TestClass::class."\0lazyObjectState"], array_keys((array) $instance)); unset($instance->public); - $this->assertFalse(isset($instance->public)); $this->assertSame(4, $instance->publicReadonly); + $this->expectException(\BadMethodCallException::class); + $this->expectExceptionMessage('__isset(public)'); + isset($instance->public); } public function testSetPublic() From b7d0b69455b4bd40c008884f3afff41ea1e1f956 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 27 Nov 2023 22:04:45 +0100 Subject: [PATCH 09/19] [Translation] Remove `@internal` from abstract testcases --- .../Component/Translation/Test/ProviderFactoryTestCase.php | 2 -- src/Symfony/Component/Translation/Test/ProviderTestCase.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Symfony/Component/Translation/Test/ProviderFactoryTestCase.php b/src/Symfony/Component/Translation/Test/ProviderFactoryTestCase.php index a9c7c0ebf363d..110ea3d7a49f6 100644 --- a/src/Symfony/Component/Translation/Test/ProviderFactoryTestCase.php +++ b/src/Symfony/Component/Translation/Test/ProviderFactoryTestCase.php @@ -28,8 +28,6 @@ * A test case to ease testing a translation provider factory. * * @author Mathieu Santostefano - * - * @internal */ abstract class ProviderFactoryTestCase extends TestCase { diff --git a/src/Symfony/Component/Translation/Test/ProviderTestCase.php b/src/Symfony/Component/Translation/Test/ProviderTestCase.php index 2d16f2bfc77b8..a8fa0b8bbcbac 100644 --- a/src/Symfony/Component/Translation/Test/ProviderTestCase.php +++ b/src/Symfony/Component/Translation/Test/ProviderTestCase.php @@ -25,8 +25,6 @@ * A test case to ease testing a translation provider. * * @author Mathieu Santostefano - * - * @internal */ abstract class ProviderTestCase extends TestCase { From 084f8d1e093bba49eb517391a02938036d67dc40 Mon Sep 17 00:00:00 2001 From: Evert Harmeling Date: Tue, 28 Nov 2023 14:20:50 +0100 Subject: [PATCH 10/19] Minor @var doc update --- .../Component/AssetMapper/ImportMap/ImportMapAuditor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapAuditor.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapAuditor.php index 1597884b215bf..112e68906dfd7 100644 --- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapAuditor.php +++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapAuditor.php @@ -35,7 +35,7 @@ public function audit(): array { $entries = $this->configReader->getEntries(); - /** @var array> $installed */ + /** @var array $packageAudits */ $packageAudits = []; /** @var array> $installed */ From ca1675165854f0a8febc41c8551c905b7b987488 Mon Sep 17 00:00:00 2001 From: Mathias Arlaud Date: Tue, 28 Nov 2023 09:07:59 +0100 Subject: [PATCH 11/19] [Serializer] Fix normalization relying on allowed attributes only --- .../Normalizer/AbstractObjectNormalizer.php | 2 +- .../AbstractObjectNormalizerTest.php | 34 +++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 25f7853762385..b7bf2e15d5bc2 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -318,7 +318,7 @@ protected function getAttributes(object $object, ?string $format, array $context $allowedAttributes = $this->getAllowedAttributes($object, $context, true); if (false !== $allowedAttributes) { - $attributes = array_intersect($attributes, $allowedAttributes); + $attributes = $attributes ? array_intersect($attributes, $allowedAttributes) : $allowedAttributes; } if ($context['cache_key'] && \stdClass::class !== $class) { diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index ad89dcbcd7896..cf33e8e604848 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -458,9 +458,39 @@ public function testNormalizeEmptyObject() public function testNormalizeWithIgnoreAnnotationAndPrivateProperties() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $serializer = new Serializer([new ObjectNormalizer($classMetadataFactory)]); + $normalizer = new ObjectNormalizer($classMetadataFactory); - $this->assertSame(['foo' => 'foo'], $serializer->normalize(new ObjectDummyWithIgnoreAnnotationAndPrivateProperty())); + $this->assertSame(['foo' => 'foo'], $normalizer->normalize(new ObjectDummyWithIgnoreAnnotationAndPrivateProperty())); + } + + public function testNormalizeBasedOnAllowedAttributes() + { + $normalizer = new class() extends AbstractObjectNormalizer { + protected function getAllowedAttributes($classOrObject, array $context, bool $attributesAsString = false) + { + return ['foo']; + } + + protected function extractAttributes(object $object, string $format = null, array $context = []): array + { + return []; + } + + protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []) + { + return $object->$attribute; + } + + protected function setAttributeValue(object $object, string $attribute, $value, string $format = null, array $context = []) + { + } + }; + + $object = new Dummy(); + $object->foo = 'foo'; + $object->bar = 'bar'; + + $this->assertSame(['foo' => 'foo'], $normalizer->normalize($object)); } /** From 02dba6d4a51e65b47c852b9498a20d639f51572e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 28 Nov 2023 21:55:58 +0100 Subject: [PATCH 12/19] [HttpClient] Add Innovative Web AG (i-web) as sponsor of version 6.4/7.0 --- src/Symfony/Component/HttpClient/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Symfony/Component/HttpClient/README.md b/src/Symfony/Component/HttpClient/README.md index 214489b7e7f76..04e15967f64ca 100644 --- a/src/Symfony/Component/HttpClient/README.md +++ b/src/Symfony/Component/HttpClient/README.md @@ -3,6 +3,18 @@ HttpClient component The HttpClient component provides powerful methods to fetch HTTP resources synchronously or asynchronously. +Sponsor +------- + +The HttpClient component for Symfony 6.4 is [backed][1] by [Innovative Web AG][2]. + +Innovative Web AG (i-web) is a specialist for web, applications and the +digitalisation of the public sector based in Switzerland. With their i-CMS, +public authorities and institutions implement modern websites and eGovernment +portals and offer user-friendly eServices for residents and companies. + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -11,3 +23,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://www.i-web.ch +[3]: https://symfony.com/sponsor From 210b371de5069fdf01ec72462ec7e85571ebaa2c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 29 Nov 2023 07:58:28 +0100 Subject: [PATCH 13/19] don't check parameter values if they are not set --- .../Compiler/CheckTypeDeclarationsPass.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php index e69d56fb16265..867a4a22412f2 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php @@ -139,11 +139,17 @@ private function checkTypeDeclarations(Definition $checkedDefinition, \Reflectio $envPlaceholderUniquePrefix = $this->container->getParameterBag() instanceof EnvPlaceholderParameterBag ? $this->container->getParameterBag()->getEnvPlaceholderUniquePrefix() : null; for ($i = 0; $i < $checksCount; ++$i) { - if (!$reflectionParameters[$i]->hasType() || $reflectionParameters[$i]->isVariadic()) { + $p = $reflectionParameters[$i]; + if (!$p->hasType() || $p->isVariadic()) { + continue; + } + if (\array_key_exists($p->name, $values)) { + $i = $p->name; + } elseif (!\array_key_exists($i, $values)) { continue; } - $this->checkType($checkedDefinition, $values[$i], $reflectionParameters[$i], $envPlaceholderUniquePrefix); + $this->checkType($checkedDefinition, $values[$i], $p, $envPlaceholderUniquePrefix); } if ($reflectionFunction->isVariadic() && ($lastParameter = end($reflectionParameters))->hasType()) { From 7dc4abcf3e7f2a8ae93e9e146e9aa99f0cf65835 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 29 Nov 2023 09:02:20 +0100 Subject: [PATCH 14/19] [Routing] Add redirection.io as sponsor of versions 6.4/7.0/7.1 --- src/Symfony/Component/Routing/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Symfony/Component/Routing/README.md b/src/Symfony/Component/Routing/README.md index ae8284f541faa..fe91c63257327 100644 --- a/src/Symfony/Component/Routing/README.md +++ b/src/Symfony/Component/Routing/README.md @@ -41,6 +41,17 @@ $url = $generator->generate('blog_show', [ // $url = '/blog/my-blog-post' ``` +Sponsor +------- + +The Routing component for Symfony 6.4 is [backed][1] by [redirection.io][2]. + +redirection.io logs all your website’s HTTP traffic, and lets you fix errors +with redirect rules in seconds. Give your marketing, SEO and IT teams the +right tool to manage your website traffic efficiently! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -49,3 +60,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://redirection.io +[3]: https://symfony.com/sponsor From f49dcf52d0ec559491e8dd569aab434215c4e563 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Sun, 26 Nov 2023 21:33:54 +0100 Subject: [PATCH 15/19] [Translation] Improve tests coverage --- .../Formatter/MessageFormatter.php | 6 +- .../Catalogue/AbstractOperationTestCase.php | 11 +++ .../TranslationDataCollectorTest.php | 20 ++++++ .../Tests/Exception/ProviderExceptionTest.php | 6 +- .../TranslationProviderCollectionTest.php | 71 +++++++++++++++++++ .../Tests/Writer/TranslationWriterTest.php | 31 ++++++++ 6 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 src/Symfony/Component/Translation/Tests/Provider/TranslationProviderCollectionTest.php diff --git a/src/Symfony/Component/Translation/Formatter/MessageFormatter.php b/src/Symfony/Component/Translation/Formatter/MessageFormatter.php index 29ad574ee12e3..5e101aa438c19 100644 --- a/src/Symfony/Component/Translation/Formatter/MessageFormatter.php +++ b/src/Symfony/Component/Translation/Formatter/MessageFormatter.php @@ -36,11 +36,7 @@ public function __construct(TranslatorInterface $translator = null, IntlFormatte public function format(string $message, string $locale, array $parameters = []): string { - if ($this->translator instanceof TranslatorInterface) { - return $this->translator->trans($message, $parameters, null, $locale); - } - - return strtr($message, $parameters); + return $this->translator->trans($message, $parameters, null, $locale); } public function formatIntl(string $message, string $locale, array $parameters = []): string diff --git a/src/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTestCase.php b/src/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTestCase.php index d6b67d27b53c8..6caee0f6e5b8d 100644 --- a/src/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTestCase.php +++ b/src/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTestCase.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Translation\Tests\Catalogue; use PHPUnit\Framework\TestCase; +use Symfony\Component\Translation\Exception\LogicException; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\MessageCatalogueInterface; @@ -70,5 +71,15 @@ public function testGetEmptyResult() ); } + public function testSourceAndTargetWithDifferentLocales() + { + $this->expectException(LogicException::class); + $this->expectExceptionMessage('Operated catalogues must belong to the same locale.'); + $this->createOperation( + new MessageCatalogue('en'), + new MessageCatalogue('fr') + ); + } + abstract protected function createOperation(MessageCatalogueInterface $source, MessageCatalogueInterface $target); } diff --git a/src/Symfony/Component/Translation/Tests/DataCollector/TranslationDataCollectorTest.php b/src/Symfony/Component/Translation/Tests/DataCollector/TranslationDataCollectorTest.php index 8992569b01d81..c6e0cafdc166c 100644 --- a/src/Symfony/Component/Translation/Tests/DataCollector/TranslationDataCollectorTest.php +++ b/src/Symfony/Component/Translation/Tests/DataCollector/TranslationDataCollectorTest.php @@ -12,6 +12,8 @@ namespace Symfony\Component\Translation\Tests\DataCollector; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Translation\DataCollector\TranslationDataCollector; use Symfony\Component\Translation\DataCollectorTranslator; @@ -130,6 +132,24 @@ public function testCollect() $this->assertEquals($expectedMessages, array_values($dataCollector->getMessages()->getValue(true))); } + public function testCollectAndReset() + { + $translator = $this->getTranslator(); + $translator->method('getLocale')->willReturn('fr'); + $translator->method('getFallbackLocales')->willReturn(['en']); + + $dataCollector = new TranslationDataCollector($translator); + $dataCollector->collect($this->createMock(Request::class), $this->createMock(Response::class)); + + $this->assertSame('fr', $dataCollector->getLocale()); + $this->assertSame(['en'], $dataCollector->getFallbackLocales()); + + $dataCollector->reset(); + + $this->assertNull($dataCollector->getLocale()); + $this->assertEmpty($dataCollector->getFallbackLocales()); + } + private function getTranslator() { $translator = $this diff --git a/src/Symfony/Component/Translation/Tests/Exception/ProviderExceptionTest.php b/src/Symfony/Component/Translation/Tests/Exception/ProviderExceptionTest.php index 245ba8df77e3e..fd1d19168480c 100644 --- a/src/Symfony/Component/Translation/Tests/Exception/ProviderExceptionTest.php +++ b/src/Symfony/Component/Translation/Tests/Exception/ProviderExceptionTest.php @@ -23,8 +23,7 @@ public function testExceptionWithDebugMessage() $mock->method('getInfo')->willReturn('debug'); $exception = new ProviderException('Exception message', $mock, 503); - - self::assertInstanceOf(ProviderException::class, $exception); + $this->assertSame('debug', $exception->getDebug()); } public function testExceptionWithNullAsDebugMessage() @@ -33,7 +32,6 @@ public function testExceptionWithNullAsDebugMessage() $mock->method('getInfo')->willReturn(null); $exception = new ProviderException('Exception message', $mock, 503); - - self::assertInstanceOf(ProviderException::class, $exception); + $this->assertSame('', $exception->getDebug()); } } diff --git a/src/Symfony/Component/Translation/Tests/Provider/TranslationProviderCollectionTest.php b/src/Symfony/Component/Translation/Tests/Provider/TranslationProviderCollectionTest.php new file mode 100644 index 0000000000000..98c1e4c7b80f0 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/Provider/TranslationProviderCollectionTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\Tests\Provider; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Translation\Provider\ProviderInterface; +use Symfony\Component\Translation\Provider\TranslationProviderCollection; + +class TranslationProviderCollectionTest extends TestCase +{ + public function testKeys() + { + $this->assertSame(['foo', 'baz'], $this->createProviderCollection()->keys()); + } + + public function testKeysWithGenerator() + { + $this->assertSame(['foo', 'baz'], (new TranslationProviderCollection( + (function () { + yield 'foo' => $this->createMock(ProviderInterface::class); + + yield 'baz' => $this->createMock(ProviderInterface::class); + })() + ))->keys()); + } + + public function testToString() + { + $this->assertSame('[foo,baz]', (string) $this->createProviderCollection()); + } + + public function testHas() + { + $this->assertTrue($this->createProviderCollection()->has('foo')); + } + + public function testGet() + { + $provider = $this->createMock(ProviderInterface::class); + + $this->assertSame($provider, (new TranslationProviderCollection([ + 'foo' => $provider, + 'baz' => $this->createMock(ProviderInterface::class), + ]))->get('foo')); + } + + public function testGetThrowsException() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Provider "invalid" not found. Available: "[foo,baz]".'); + + $this->createProviderCollection()->get('invalid'); + } + + private function createProviderCollection(): TranslationProviderCollection + { + return new TranslationProviderCollection([ + 'foo' => $this->createMock(ProviderInterface::class), + 'baz' => $this->createMock(ProviderInterface::class), + ]); + } +} diff --git a/src/Symfony/Component/Translation/Tests/Writer/TranslationWriterTest.php b/src/Symfony/Component/Translation/Tests/Writer/TranslationWriterTest.php index 5be071351ef2f..c20c43cb19b2f 100644 --- a/src/Symfony/Component/Translation/Tests/Writer/TranslationWriterTest.php +++ b/src/Symfony/Component/Translation/Tests/Writer/TranslationWriterTest.php @@ -13,6 +13,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Translation\Dumper\DumperInterface; +use Symfony\Component\Translation\Exception\InvalidArgumentException; +use Symfony\Component\Translation\Exception\RuntimeException; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\Writer\TranslationWriter; @@ -29,4 +31,33 @@ public function testWrite() $writer->addDumper('test', $dumper); $writer->write(new MessageCatalogue('en'), 'test'); } + + public function testGetFormats() + { + $writer = new TranslationWriter(); + $writer->addDumper('foo', $this->createMock(DumperInterface::class)); + $writer->addDumper('bar', $this->createMock(DumperInterface::class)); + + $this->assertEquals(['foo', 'bar'], $writer->getFormats()); + } + + public function testFormatIsNotSupported() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('There is no dumper associated with format "foo".'); + $writer = new TranslationWriter(); + + $writer->write(new MessageCatalogue('en'), 'foo'); + } + + public function testUnwritableDirectory() + { + $writer = new TranslationWriter(); + $writer->addDumper('foo', $this->createMock(DumperInterface::class)); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Translation Writer was not able to create directory "/foo/bar/baz".'); + + $writer->write(new MessageCatalogue('en'), 'foo', ['path' => '/foo/bar/baz']); + } } From 8c45f9fbca7691faf273b8fb1ab60a8a5e8a62e7 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 29 Nov 2023 09:26:06 +0100 Subject: [PATCH 16/19] [Serializer] Fix anonymous test class --- .../Tests/Normalizer/AbstractObjectNormalizerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index 259c1d8a43e2e..60eaaad7fc8a5 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -855,7 +855,7 @@ public function testNormalizeWithIgnoreAnnotationAndPrivateProperties() public function testNormalizeBasedOnAllowedAttributes() { $normalizer = new class() extends AbstractObjectNormalizer { - protected function getAllowedAttributes($classOrObject, array $context, bool $attributesAsString = false) + protected function getAllowedAttributes($classOrObject, array $context, bool $attributesAsString = false): array { return ['foo']; } @@ -865,12 +865,12 @@ protected function extractAttributes(object $object, string $format = null, arra return []; } - protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []) + protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []): mixed { return $object->$attribute; } - protected function setAttributeValue(object $object, string $attribute, $value, string $format = null, array $context = []) + protected function setAttributeValue(object $object, string $attribute, $value, string $format = null, array $context = []): void { } }; From 1dc20a875f53346cb1279afa1028c3f3d0f5f6d5 Mon Sep 17 00:00:00 2001 From: Mathias Arlaud Date: Wed, 29 Nov 2023 10:47:40 +0100 Subject: [PATCH 17/19] [Serializer] Revert allowed attributes fix --- .../Normalizer/AbstractObjectNormalizer.php | 16 ++++++++++------ .../AbstractObjectNormalizerTest.php | 19 ------------------- .../Serializer/Tests/SerializerTest.php | 2 +- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index b7bf2e15d5bc2..732586bd85f9b 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -309,16 +309,20 @@ protected function getAttributes(object $object, ?string $format, array $context return $this->attributesCache[$key]; } - $attributes = $this->extractAttributes($object, $format, $context); + $allowedAttributes = $this->getAllowedAttributes($object, $context, true); - if ($this->classDiscriminatorResolver && $mapping = $this->classDiscriminatorResolver->getMappingForMappedObject($object)) { - array_unshift($attributes, $mapping->getTypeProperty()); + if (false !== $allowedAttributes) { + if ($context['cache_key']) { + $this->attributesCache[$key] = $allowedAttributes; + } + + return $allowedAttributes; } - $allowedAttributes = $this->getAllowedAttributes($object, $context, true); + $attributes = $this->extractAttributes($object, $format, $context); - if (false !== $allowedAttributes) { - $attributes = $attributes ? array_intersect($attributes, $allowedAttributes) : $allowedAttributes; + if ($this->classDiscriminatorResolver && $mapping = $this->classDiscriminatorResolver->getMappingForMappedObject($object)) { + array_unshift($attributes, $mapping->getTypeProperty()); } if ($context['cache_key'] && \stdClass::class !== $class) { diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index cf33e8e604848..35616b658ba78 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -17,7 +17,6 @@ use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\PropertyInfo\Type; -use Symfony\Component\Serializer\Annotation\Ignore; use Symfony\Component\Serializer\Exception\ExtraAttributesException; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\LogicException; @@ -455,14 +454,6 @@ public function testNormalizeEmptyObject() $this->assertEquals(new \ArrayObject(), $normalizedData); } - public function testNormalizeWithIgnoreAnnotationAndPrivateProperties() - { - $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); - $normalizer = new ObjectNormalizer($classMetadataFactory); - - $this->assertSame(['foo' => 'foo'], $normalizer->normalize(new ObjectDummyWithIgnoreAnnotationAndPrivateProperty())); - } - public function testNormalizeBasedOnAllowedAttributes() { $normalizer = new class() extends AbstractObjectNormalizer { @@ -586,16 +577,6 @@ class EmptyDummy { } -class ObjectDummyWithIgnoreAnnotationAndPrivateProperty -{ - public $foo = 'foo'; - - /** @Ignore */ - public $ignored = 'ignored'; - - private $private = 'private'; -} - class AbstractObjectNormalizerWithMetadata extends AbstractObjectNormalizer { public function __construct() diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 65f7fd9d508eb..12d8eeefdd1a0 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -473,7 +473,7 @@ public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadata 'groups' => ['two'], ]); - $this->assertEquals('{"type":"one","two":2}', $serialized); + $this->assertEquals('{"two":2,"type":"one"}', $serialized); } public function testDeserializeAndSerializeNestedInterfacedObjectsWithTheClassMetadataDiscriminator() From 4bdbb6dd17f8ff0fefa089783084609c1b9e97e3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 29 Nov 2023 11:39:53 +0100 Subject: [PATCH 18/19] Update CHANGELOG for 6.4.0 --- CHANGELOG-6.4.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-6.4.md b/CHANGELOG-6.4.md index 0733e749d212e..60185b4c5470a 100644 --- a/CHANGELOG-6.4.md +++ b/CHANGELOG-6.4.md @@ -7,6 +7,16 @@ in 6.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v6.4.0...v6.4.1 +* 6.4.0 (2023-11-29) + + * bug #52786 [Serializer] Revert allowed attributes fix (mtarld) + * bug #52765 [Translation] Remove ``@internal`` from abstract testcases (OskarStark) + * bug #52780 [DependencyInjection] don't check parameter values if they are not set (xabbuh) + * bug #52762 [VarExporter] Work around php/php-src#12695 for lazy objects, fixing nullsafe-related behavior (nicolas-grekas) + * bug #52759 [VarExporter] Fix serializing objects that implement __sleep() and that are made lazy (nicolas-grekas) + * bug #52767 [Serializer] Fix normalization relying on allowed attributes only (mtarld) + * bug #52727 [String] Fix Inflector for 'icon' (podhy) + * 6.4.0-RC2 (2023-11-26) * bug #52724 [Security] make secret required for DefaultLoginRateLimiter (RobertMe) From 68c0ba5da7f633ce8f377a0b5731f2df0fae462a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 29 Nov 2023 11:40:15 +0100 Subject: [PATCH 19/19] Update VERSION for 6.4.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7825b57cf2148..39170e8333e20 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.4.0-DEV'; + public const VERSION = '6.4.0'; public const VERSION_ID = 60400; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2026'; public const END_OF_LIFE = '11/2027'; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy