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) diff --git a/UPGRADE-6.4.md b/UPGRADE-6.4.md index 182d98cce2f16..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 - * Deprecate calling the constructor of `DefaultLoginRateLimiter` with an empty secret + * [BC break] Add required `string $secret` parameter to the constructor of `DefaultLoginRateLimiter` SecurityBundle -------------- 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 */ 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 diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 9ebfac110e959..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-RC2'; + 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 = 'RC2'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2026'; public const END_OF_LIFE = '11/2027'; 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 diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index f9131dbf16e13..c6f279dcfdda5 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -260,16 +260,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 ($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 = array_intersect($attributes, $allowedAttributes); + if ($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 49f19666c2e22..2c274c20d681a 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -18,7 +18,6 @@ use Symfony\Component\PropertyInfo\Type; use Symfony\Component\Serializer\Attribute\Context; use Symfony\Component\Serializer\Attribute\DiscriminatorMap; -use Symfony\Component\Serializer\Attribute\Ignore; use Symfony\Component\Serializer\Attribute\SerializedName; use Symfony\Component\Serializer\Attribute\SerializedPath; use Symfony\Component\Serializer\Exception\ExtraAttributesException; @@ -837,12 +836,34 @@ public function testDenormalizeWithCorrectOrderOfAttributeAndProperty() $this->assertSame('nested-id', $test->id); } - public function testNormalizeWithIgnoreAttributeAndPrivateProperties() + public function testNormalizeBasedOnAllowedAttributes() { - $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader()); - $serializer = new Serializer([new ObjectNormalizer($classMetadataFactory)]); + $normalizer = new class() extends AbstractObjectNormalizer { + protected function getAllowedAttributes($classOrObject, array $context, bool $attributesAsString = false): array + { + return ['foo']; + } + + protected function extractAttributes(object $object, string $format = null, array $context = []): array + { + return []; + } - $this->assertSame(['foo' => 'foo'], $serializer->normalize(new ObjectDummyWithIgnoreAttributeAndPrivateProperty())); + 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 = []): void + { + } + }; + + $object = new Dummy(); + $object->foo = 'foo'; + $object->bar = 'bar'; + + $this->assertSame(['foo' => 'foo'], $normalizer->normalize($object)); } public function testDenormalizeUntypedFormat() @@ -1054,16 +1075,6 @@ class ObjectDummyWithContextAttributeSkipNullValues public ?string $propertyWithNullSkipNullValues = null; } -class ObjectDummyWithIgnoreAttributeAndPrivateProperty -{ - 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 43368cc61721a..e61678b03367a 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -469,7 +469,7 @@ public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadata 'groups' => ['two'], ]); - $this->assertEquals('{"type":"one","two":2}', $serialized); + $this->assertEquals('{"two":2,"type":"one"}', $serialized); } public function testDeserializeAndSerializeNestedInterfacedObjectsWithTheClassMetadataDiscriminator() diff --git a/src/Symfony/Component/String/Inflector/EnglishInflector.php b/src/Symfony/Component/String/Inflector/EnglishInflector.php index a0f6dc938e4cd..feea7f668df04 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'], 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/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 { 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']); + } } 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. + Използването на скрити насложени символи не е позволено. + diff --git a/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php b/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php index 493778183d103..d378ba2925dad 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php @@ -18,6 +18,8 @@ class ConstraintValidatorTest extends TestCase { + use IcuCompatibilityTrait; + /** * @dataProvider formatValueProvider */ @@ -43,10 +45,10 @@ public static function formatValueProvider(): array ['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], ['FirstCase', TestEnum::FirstCase], ]; @@ -62,7 +64,7 @@ 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 ea9efe90e238c..06c0edfbf1a50 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(): EqualToValidator { return new EqualToValidator(); @@ -61,14 +64,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 e1e29576bc7b3..aaeb98d8bfd3f 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(): GreaterThanOrEqualValidator { return new GreaterThanOrEqualValidator(); @@ -64,14 +67,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 bc4b5df04fb06..ab8a0ac10f51d 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(): GreaterThanValidator { return new GreaterThanValidator(); @@ -60,12 +63,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'], @@ -73,7 +76,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 334743c4b0e5e..424c028c0a808 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(): IdenticalToValidator { return new IdenticalToValidator(); @@ -81,13 +84,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 aec7edcb603e4..d4bcc346fdabf 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(): LessThanOrEqualValidator { return new LessThanOrEqualValidator(); @@ -66,15 +69,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 7721d812fe9a5..14064962a26d7 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(): LessThanValidator { return new LessThanValidator(); @@ -60,19 +63,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 de8249d8b37dd..a297ae37fba3f 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(): NotEqualToValidator { return new NotEqualToValidator(); @@ -61,14 +64,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 a594599c4ae09..eab5395bcd808 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(): NotIdenticalToValidator { return new NotIdenticalToValidator(); @@ -77,17 +80,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 1f8cb736aca57..876595c37fc94 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(): RangeValidator { 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'], @@ -277,7 +280,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 @@ -298,7 +301,7 @@ public static function getTenthToTwentiethMarch2014() 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 @@ -306,10 +309,10 @@ 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 \DateTimeImmutable('March 20, 2013'), 'Mar 20, 2013, 12:00 AM'], - [new \DateTimeImmutable('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")], ]; date_default_timezone_set($timezone); @@ -317,7 +320,7 @@ public static function getSoonerThanTenthMarch2014() 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 @@ -325,10 +328,10 @@ 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 \DateTimeImmutable('March 21, 2014'), 'Mar 21, 2014, 12:00 AM'], - [new \DateTimeImmutable('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")], ]; date_default_timezone_set($timezone); @@ -372,7 +375,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 @@ -387,7 +390,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(); } @@ -395,7 +398,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 @@ -410,7 +413,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(); } @@ -418,7 +421,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 @@ -434,8 +437,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(); } @@ -459,13 +462,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], @@ -927,7 +930,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(); @@ -953,7 +956,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(); @@ -980,8 +983,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) @@ -1009,8 +1012,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); + } +} diff --git a/src/Symfony/Component/VarExporter/Internal/Hydrator.php b/src/Symfony/Component/VarExporter/Internal/Hydrator.php index b8068fdc21eba..d792aa5e9b436 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 66345cdc4ad5c..a25fc21a85bb2 100644 --- a/src/Symfony/Component/VarExporter/LazyGhostTrait.php +++ b/src/Symfony/Component/VarExporter/LazyGhostTrait.php @@ -163,10 +163,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; + } } } @@ -228,7 +236,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); } @@ -262,6 +272,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; @@ -291,7 +302,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); } @@ -346,7 +359,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/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 9289e30e8f4b2..52718be0df126 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() @@ -146,7 +148,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() 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