From 55f49c25cbf09a727f5b246a9a7e531e86000eaa Mon Sep 17 00:00:00 2001 From: plfort Date: Mon, 9 Jan 2023 21:38:44 +0100 Subject: [PATCH 01/11] Handle object field in UniqueValidator --- .../Validator/Constraints/UniqueValidator.php | 55 +++++- .../Tests/Constraints/UniqueValidatorTest.php | 184 ++++++++++++++++-- 2 files changed, 222 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index bd78cac721d1f..5094052186a60 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -11,8 +11,13 @@ namespace Symfony\Component\Validator\Constraints; +use Symfony\Component\PropertyAccess\Exception\AccessException; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessor; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\LogicException; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedValueException; @@ -21,7 +26,18 @@ */ class UniqueValidator extends ConstraintValidator { - public function validate(mixed $value, Constraint $constraint): void + + private ?PropertyAccessorInterface $propertyAccessor; + + /** + * @param PropertyAccessorInterface|null $propertyAccessor + */ + public function __construct(?PropertyAccessorInterface $propertyAccessor = null) + { + $this->propertyAccessor = $propertyAccessor; + } + + public function validate(mixed $value, Constraint $constraint) { if (!$constraint instanceof Unique) { throw new UnexpectedTypeException($constraint, Unique::class); @@ -72,18 +88,49 @@ private function getNormalizer(Unique $unique): callable return $unique->normalizer ?? static fn ($value) => $value; } - private function reduceElementKeys(array $fields, array $element): array + private function reduceElementKeys(array $fields, array|object $element): array { $output = []; foreach ($fields as $field) { if (!\is_string($field)) { throw new UnexpectedTypeException($field, 'string'); } - if (\array_key_exists($field, $element)) { - $output[$field] = $element[$field]; + + $elementAsArray = null; + + //handle public object property + if (\is_object($element) && \property_exists($element, $field)) { + $elementAsArray = (array)$element; + } elseif (\is_array($element)) { + $elementAsArray = $element; + } + + if ($elementAsArray && \array_key_exists($field, $element)) { + $output[$field] = $elementAsArray[$field]; + continue; + } + + try { + $output[$field] = $this->getPropertyAccessor()->getValue($element, $field); + } catch (AccessException) { + //fields are optional } } return $output; } + + private function getPropertyAccessor(): PropertyAccessor + { + if (null === $this->propertyAccessor) { + if (!class_exists(PropertyAccess::class)) { + throw new LogicException( + 'Unable to use property path as the Symfony PropertyAccess component is not installed.' + ); + } + $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); + } + + return $this->propertyAccessor; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php index 12efb76982e24..3634687864a38 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php @@ -34,9 +34,9 @@ public function testExpectsUniqueConstraintCompatibleType() /** * @dataProvider getValidValues */ - public function testValidValues($value) + public function testValidValues($value, array $fields) { - $this->validator->validate($value, new Unique()); + $this->validator->validate($value, new Unique(fields: $fields)); $this->assertNoViolation(); } @@ -44,17 +44,79 @@ public function testValidValues($value) public static function getValidValues() { return [ - yield 'null' => [[null]], - yield 'empty array' => [[]], - yield 'single integer' => [[5]], - yield 'single string' => [['a']], - yield 'single object' => [[new \stdClass()]], - yield 'unique booleans' => [[true, false]], - yield 'unique integers' => [[1, 2, 3, 4, 5, 6]], - yield 'unique floats' => [[0.1, 0.2, 0.3]], - yield 'unique strings' => [['a', 'b', 'c']], - yield 'unique arrays' => [[[1, 2], [2, 4], [4, 6]]], - yield 'unique objects' => [[new \stdClass(), new \stdClass()]], + yield 'null' => [[null], []], + yield 'empty array' => [[], []], + yield 'single integer' => [[5], []], + yield 'single string' => [['a'], []], + yield 'single object' => [[new \stdClass()], []], + yield 'unique booleans' => [[true, false], []], + yield 'unique integers' => [[1, 2, 3, 4, 5, 6], []], + yield 'unique floats' => [[0.1, 0.2, 0.3], []], + yield 'unique strings' => [['a', 'b', 'c'], []], + yield 'unique arrays' => [[[1, 2], [2, 4], [4, 6]], []], + yield 'unique objects' => [[new \stdClass(), new \stdClass()], []], + yield 'unique objects public field' => [ + [ + new class { + public int $fieldA = 1; + }, + new class { + public int $fieldA = 2; + }, + ], + ['fieldA'], + ], + yield 'unique objects private field' => [ + [ + new class { + private int $fieldB = 1; + + public function getFieldB(): int + { + return $this->fieldB; + } + }, + new class { + private int $fieldB = 2; + + public function getFieldB(): int + { + return $this->fieldB; + } + }, + ], + ['fieldB'], + ], + yield 'unique objects property accessor field' => [ + [ + new class { + public array $fieldA = ['fieldB' => 1]; + }, + new class { + public array $fieldA = ['fieldB' => 2]; + }, + ], + ['fieldA[fieldB]'], + ], + 'unique objects polymorph field' => [ + [ + new class { + private int $fieldB = 1; + + public function getFieldB(): int + { + return $this->fieldB; + } + }, + new class { + public int $fieldB = 2; + }, + [ + 'fieldB'=>3 + ], + ], + ['fieldB'], + ], ]; } @@ -215,6 +277,43 @@ public function testCollectionFieldsAreOptional() $this->assertNoViolation(); } + public function testCollectionObjectFieldsAreOptional() + { + $this->validator->validate([ + new class { + public int $value = 5; + }, + new class { + public int $id = 1; + public int $value = 5; + }, + ], new Unique(fields: 'id')); + + $this->assertNoViolation(); + } + + public function testCollectionObjectPrivateFieldsAreOptional() + { + $this->validator->validate([ + new class { + private int $id = 2; + public int $value = 5; + }, + new class { + private int $id = 2; + public int $value = 5; + + public function getId(): int + { + return $this->id; + } + }, + + ], new Unique(fields: 'id')); + + $this->assertNoViolation(); + } + /** * @dataProvider getInvalidFieldNames */ @@ -267,6 +366,65 @@ public static function getInvalidCollectionValues(): array ['id' => 1, 'email' => 'bar@email.com'], ['id' => 1, 'email' => 'foo@email.com'], ], ['id'], 'array'], + 'unique object string' => [[ + (object)['lang' => 'eng', 'translation' => 'hi'], + (object)['lang' => 'eng', 'translation' => 'hello'], + ], + ['lang'], 'array'], + 'unique objects public field' => [[ + new class { + public int $fieldA = 1; + }, + new class { + public int $fieldA = 1; + }, + ], + ['fieldA'], 'array'], + 'unique objects property accessor field' => [[ + new class { + public array $fieldA = ['fieldB' => 1]; + }, + new class { + public array $fieldA = ['fieldB' => 1]; + }, + ], + ['fieldA[fieldB]'], 'array'], + 'unique objects private field' => [[ + new class { + private int $fieldB = 1; + + public function getFieldB(): int + { + return $this->fieldB; + } + }, + new class { + private int $fieldB = 1; + + public function getFieldB(): int + { + return $this->fieldB; + } + }, + ], + ['fieldB'], 'array'], + 'unique objects polymorph field' => [[ + new class { + private int $fieldB = 1; + + public function getFieldB(): int + { + return $this->fieldB; + } + }, + new class { + public int $fieldB = 1; + }, + [ + 'fieldB'=>1 + ], + ], + ['fieldB'], 'array'], 'unique null' => [ [null, null], [], From 4d719d79bf6fc012052879890c33f3eabd160bfb Mon Sep 17 00:00:00 2001 From: plfort Date: Tue, 10 Jan 2023 18:35:18 +0100 Subject: [PATCH 02/11] Change CHANGELOG entry order Fix after rebase Update CHANGELOG.md --- src/Symfony/Component/Validator/CHANGELOG.md | 2 +- .../Component/Validator/Constraints/UniqueValidator.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index ae1ae20da804d..87f36af06b44d 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -78,7 +78,7 @@ CHANGELOG 6.3 --- - + * Add support for reading objects properties with `Unique` constraint `fields` option * Add method `getConstraint()` to `ConstraintViolationInterface` * Add `Uuid::TIME_BASED_VERSIONS` to match that a UUID being validated embeds a timestamp * Add the `pattern` parameter in violations of the `Regex` constraint diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index 5094052186a60..69d7c5061b4c9 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -97,7 +97,6 @@ private function reduceElementKeys(array $fields, array|object $element): array } $elementAsArray = null; - //handle public object property if (\is_object($element) && \property_exists($element, $field)) { $elementAsArray = (array)$element; @@ -105,7 +104,7 @@ private function reduceElementKeys(array $fields, array|object $element): array $elementAsArray = $element; } - if ($elementAsArray && \array_key_exists($field, $element)) { + if ($elementAsArray && \array_key_exists($field, $elementAsArray)) { $output[$field] = $elementAsArray[$field]; continue; } From a225a6df2015afbd550b5f17aad46533d3ac2fa3 Mon Sep 17 00:00:00 2001 From: plfort Date: Wed, 11 Jan 2023 14:38:26 +0100 Subject: [PATCH 03/11] CS fix --- .../Validator/Constraints/UniqueValidator.php | 13 ++--- .../Tests/Constraints/UniqueValidatorTest.php | 49 +++++++++---------- 2 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index 69d7c5061b4c9..1cf83bda901c5 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -26,7 +26,6 @@ */ class UniqueValidator extends ConstraintValidator { - private ?PropertyAccessorInterface $propertyAccessor; /** @@ -97,9 +96,9 @@ private function reduceElementKeys(array $fields, array|object $element): array } $elementAsArray = null; - //handle public object property - if (\is_object($element) && \property_exists($element, $field)) { - $elementAsArray = (array)$element; + // handle public object property + if (\is_object($element) && property_exists($element, $field)) { + $elementAsArray = (array) $element; } elseif (\is_array($element)) { $elementAsArray = $element; } @@ -112,7 +111,7 @@ private function reduceElementKeys(array $fields, array|object $element): array try { $output[$field] = $this->getPropertyAccessor()->getValue($element, $field); } catch (AccessException) { - //fields are optional + // fields are optional } } @@ -123,9 +122,7 @@ private function getPropertyAccessor(): PropertyAccessor { if (null === $this->propertyAccessor) { if (!class_exists(PropertyAccess::class)) { - throw new LogicException( - 'Unable to use property path as the Symfony PropertyAccess component is not installed.' - ); + throw new LogicException('Unable to use property path as the Symfony PropertyAccess component is not installed.'); } $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php index 3634687864a38..bf5173e9ad91e 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UniqueValidatorTest.php @@ -57,10 +57,10 @@ public static function getValidValues() yield 'unique objects' => [[new \stdClass(), new \stdClass()], []], yield 'unique objects public field' => [ [ - new class { + new class() { public int $fieldA = 1; }, - new class { + new class() { public int $fieldA = 2; }, ], @@ -68,7 +68,7 @@ public static function getValidValues() ], yield 'unique objects private field' => [ [ - new class { + new class() { private int $fieldB = 1; public function getFieldB(): int @@ -76,7 +76,7 @@ public function getFieldB(): int return $this->fieldB; } }, - new class { + new class() { private int $fieldB = 2; public function getFieldB(): int @@ -89,10 +89,10 @@ public function getFieldB(): int ], yield 'unique objects property accessor field' => [ [ - new class { + new class() { public array $fieldA = ['fieldB' => 1]; }, - new class { + new class() { public array $fieldA = ['fieldB' => 2]; }, ], @@ -100,7 +100,7 @@ public function getFieldB(): int ], 'unique objects polymorph field' => [ [ - new class { + new class() { private int $fieldB = 1; public function getFieldB(): int @@ -108,11 +108,11 @@ public function getFieldB(): int return $this->fieldB; } }, - new class { + new class() { public int $fieldB = 2; }, [ - 'fieldB'=>3 + 'fieldB' => 3, ], ], ['fieldB'], @@ -280,10 +280,10 @@ public function testCollectionFieldsAreOptional() public function testCollectionObjectFieldsAreOptional() { $this->validator->validate([ - new class { + new class() { public int $value = 5; }, - new class { + new class() { public int $id = 1; public int $value = 5; }, @@ -295,11 +295,11 @@ public function testCollectionObjectFieldsAreOptional() public function testCollectionObjectPrivateFieldsAreOptional() { $this->validator->validate([ - new class { + new class() { private int $id = 2; public int $value = 5; }, - new class { + new class() { private int $id = 2; public int $value = 5; @@ -308,7 +308,6 @@ public function getId(): int return $this->id; } }, - ], new Unique(fields: 'id')); $this->assertNoViolation(); @@ -367,30 +366,30 @@ public static function getInvalidCollectionValues(): array ['id' => 1, 'email' => 'foo@email.com'], ], ['id'], 'array'], 'unique object string' => [[ - (object)['lang' => 'eng', 'translation' => 'hi'], - (object)['lang' => 'eng', 'translation' => 'hello'], + (object) ['lang' => 'eng', 'translation' => 'hi'], + (object) ['lang' => 'eng', 'translation' => 'hello'], ], ['lang'], 'array'], 'unique objects public field' => [[ - new class { + new class() { public int $fieldA = 1; }, - new class { + new class() { public int $fieldA = 1; }, ], ['fieldA'], 'array'], 'unique objects property accessor field' => [[ - new class { + new class() { public array $fieldA = ['fieldB' => 1]; }, - new class { + new class() { public array $fieldA = ['fieldB' => 1]; }, ], ['fieldA[fieldB]'], 'array'], 'unique objects private field' => [[ - new class { + new class() { private int $fieldB = 1; public function getFieldB(): int @@ -398,7 +397,7 @@ public function getFieldB(): int return $this->fieldB; } }, - new class { + new class() { private int $fieldB = 1; public function getFieldB(): int @@ -409,7 +408,7 @@ public function getFieldB(): int ], ['fieldB'], 'array'], 'unique objects polymorph field' => [[ - new class { + new class() { private int $fieldB = 1; public function getFieldB(): int @@ -417,11 +416,11 @@ public function getFieldB(): int return $this->fieldB; } }, - new class { + new class() { public int $fieldB = 1; }, [ - 'fieldB'=>1 + 'fieldB' => 1, ], ], ['fieldB'], 'array'], From 2d8dff436a9f7699f5ee39cfd5b6b4f81bfddc88 Mon Sep 17 00:00:00 2001 From: plfort Date: Wed, 11 Jan 2023 22:07:30 +0100 Subject: [PATCH 04/11] Use constructor property promotion --- .../Component/Validator/Constraints/UniqueValidator.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index 1cf83bda901c5..7447dbe8fa012 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -26,14 +26,11 @@ */ class UniqueValidator extends ConstraintValidator { - private ?PropertyAccessorInterface $propertyAccessor; - /** - * @param PropertyAccessorInterface|null $propertyAccessor - */ - public function __construct(?PropertyAccessorInterface $propertyAccessor = null) + public function __construct( + private ?PropertyAccessorInterface $propertyAccessor = null + ) { - $this->propertyAccessor = $propertyAccessor; } public function validate(mixed $value, Constraint $constraint) From 0b309497485c15a44615dc40245118039a83a103 Mon Sep 17 00:00:00 2001 From: plfort Date: Wed, 11 Jan 2023 22:09:16 +0100 Subject: [PATCH 05/11] Update src/Symfony/Component/Validator/Constraints/UniqueValidator.php Co-authored-by: Alexandre Daubois <2144837+alexandre-daubois@users.noreply.github.com> --- src/Symfony/Component/Validator/Constraints/UniqueValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index 7447dbe8fa012..24973caccde63 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -119,7 +119,7 @@ private function getPropertyAccessor(): PropertyAccessor { if (null === $this->propertyAccessor) { if (!class_exists(PropertyAccess::class)) { - throw new LogicException('Unable to use property path as the Symfony PropertyAccess component is not installed.'); + throw new LogicException('Property path requires symfony/property-access package to be installed.'); } $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); } From 5eac0394c0a3e892f6be2d608c7f61d5aa3efc1d Mon Sep 17 00:00:00 2001 From: plfort Date: Thu, 12 Jan 2023 08:31:22 +0100 Subject: [PATCH 06/11] Update src/Symfony/Component/Validator/Constraints/UniqueValidator.php Co-authored-by: Artyum --- src/Symfony/Component/Validator/Constraints/UniqueValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index 24973caccde63..d1f615e479e54 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -119,7 +119,7 @@ private function getPropertyAccessor(): PropertyAccessor { if (null === $this->propertyAccessor) { if (!class_exists(PropertyAccess::class)) { - throw new LogicException('Property path requires symfony/property-access package to be installed.'); + throw new LogicException('Property path requires symfony/property-access package to be installed. Try running "composer require symfony/property-access".'); } $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); } From 777e28d4ea3f545cbf0a8de70fef3c8d260c0608 Mon Sep 17 00:00:00 2001 From: plfort Date: Thu, 12 Jan 2023 08:34:08 +0100 Subject: [PATCH 07/11] CS fix --- .../Component/Validator/Constraints/UniqueValidator.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index d1f615e479e54..9892ef95fac15 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -26,11 +26,9 @@ */ class UniqueValidator extends ConstraintValidator { - public function __construct( private ?PropertyAccessorInterface $propertyAccessor = null - ) - { + ) { } public function validate(mixed $value, Constraint $constraint) From a54a768e3eda71408e81023bbeb004397c23e0b0 Mon Sep 17 00:00:00 2001 From: plfort Date: Fri, 13 Jan 2023 13:44:30 +0100 Subject: [PATCH 08/11] Add newline in CHANGELOG.md --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 87f36af06b44d..891e0d883c61a 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -78,6 +78,7 @@ CHANGELOG 6.3 --- + * Add support for reading objects properties with `Unique` constraint `fields` option * Add method `getConstraint()` to `ConstraintViolationInterface` * Add `Uuid::TIME_BASED_VERSIONS` to match that a UUID being validated embeds a timestamp From 3da875860b65b9662127bab7f5b2ee0a75af41c4 Mon Sep 17 00:00:00 2001 From: plfort Date: Wed, 17 Jul 2024 13:02:00 +0200 Subject: [PATCH 09/11] Add validate return type --- src/Symfony/Component/Validator/Constraints/UniqueValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index 9892ef95fac15..389a11cd1624c 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -31,7 +31,7 @@ public function __construct( ) { } - public function validate(mixed $value, Constraint $constraint) + public function validate(mixed $value, Constraint $constraint): void { if (!$constraint instanceof Unique) { throw new UnexpectedTypeException($constraint, Unique::class); From 3f169ad3a68a8b9b334b7eb2b749621b52401025 Mon Sep 17 00:00:00 2001 From: plfort Date: Tue, 25 Mar 2025 14:31:50 +0100 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: Alexandre Daubois <2144837+alexandre-daubois@users.noreply.github.com> --- .../Validator/Constraints/UniqueValidator.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index 389a11cd1624c..fd0c2a0273902 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -27,7 +27,7 @@ class UniqueValidator extends ConstraintValidator { public function __construct( - private ?PropertyAccessorInterface $propertyAccessor = null + private ?PropertyAccessorInterface $propertyAccessor = null, ) { } @@ -115,13 +115,10 @@ private function reduceElementKeys(array $fields, array|object $element): array private function getPropertyAccessor(): PropertyAccessor { - if (null === $this->propertyAccessor) { - if (!class_exists(PropertyAccess::class)) { - throw new LogicException('Property path requires symfony/property-access package to be installed. Try running "composer require symfony/property-access".'); - } - $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); + if (!class_exists(PropertyAccess::class)) { + throw new LogicException('Property path requires symfony/property-access package to be installed. Try running "composer require symfony/property-access".'); } - return $this->propertyAccessor; + return $this->propertyAccessor ??= PropertyAccess::createPropertyAccessor(); } } From acb1fa0df7c06b26578404592b0e27b99d7d157f Mon Sep 17 00:00:00 2001 From: plfort Date: Tue, 25 Mar 2025 20:37:09 +0100 Subject: [PATCH 11/11] Misplaced changelog entry --- src/Symfony/Component/Validator/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 891e0d883c61a..2b190274dd309 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -13,6 +13,7 @@ CHANGELOG * Add support for multiple fields containing nested constraints in `Composite` constraints * Add the `stopOnFirstError` option to the `Unique` constraint to validate all elements * Add support for closures in the `When` constraint + * Add support for reading objects properties with `Unique` constraint `fields` option 7.2 --- @@ -79,7 +80,6 @@ CHANGELOG 6.3 --- - * Add support for reading objects properties with `Unique` constraint `fields` option * Add method `getConstraint()` to `ConstraintViolationInterface` * Add `Uuid::TIME_BASED_VERSIONS` to match that a UUID being validated embeds a timestamp * Add the `pattern` parameter in violations of the `Regex` constraint