8000 Allow to ignore specific nullable fields · symfony/symfony@c982ea5 · GitHub
[go: up one dir, main page]

Skip to content

Commit c982ea5

Browse files
Allow to ignore specific nullable fields
1 parent 8174483 commit c982ea5

File tree

3 files changed

+32
-9
lines changed

3 files changed

+32
-9
lines changed

src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,9 @@ public function testValidateUniquenessWithNull(UniqueEntity $constraint)
250250

251251
/**
252252
* @dataProvider provideConstraintsWithIgnoreNullDisabled
253+
* @dataProvider provideConstraintsWithIgnoreNullEnabledOnFirstField
253254
*/
254-
public function testValidateUniquenessWithIgnoreNullDisabled(UniqueEntity $constraint)
255+
public function testValidateUniquenessWithIgnoreNullDisableOnSecondField(UniqueEntity $constraint)
255256
{
256257
$entity1 = new DoubleNameEntity(1, 'Foo', null);
257258
$entity2 = new DoubleNameEntity(2, 'Foo', null);
@@ -303,6 +304,7 @@ public function testAllConfiguredFieldsAreCheckedOfBeingMappedByDoctrineWithIgno
303304

304305
/**
305306
* @dataProvider provideConstraintsWithIgnoreNullEnabled
307+
* @dataProvider provideConstraintsWithIgnoreNullEnabledOnFirstField
306308
*/
307309
public function testNoValidationIfFirstFieldIsNullAndNullValuesAreIgnored(UniqueEntity $constraint)
308310
{
@@ -337,6 +339,18 @@ public static function provideConstraintsWithIgnoreNullEnabled(): iterable
337339
yield 'Named arguments' => [new UniqueEntity(message: 'myMessage', fields: ['name', 'name2'], em: 'foo', ignoreNull: true)];
338340
}
339341

342+
public function provideConstraintsWithIgnoreNullEnabledOnFirstField(): iterable
343+
{
344+
yield 'Doctrine style (name field)' => [new UniqueEntity([
345+
'message' => 'myMessage',
346+
'fields' => ['name', 'name2'],
347+
'em' => self::EM_NAME,
348+
'ignoreNull' => 'name',
349+
])];
350+
351+
yield 'Named arguments (name field)' => [new UniqueEntity(message: 'myMessage', fields: ['name', 'name2'], em: 'foo', ignoreNull: 'name')];
352+
}
353+
340354
public function testValidateUniquenessWithValidCustomErrorPath()
341355
{
342356
$constraint = new UniqueEntity([

src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* Constraint for the Unique Entity validator.
1818
*
1919
* @Annotation
20+
*
2021
* @Target({"CLASS", "ANNOTATION"})
2122
*
2223
* @author Benjamin Eberlei <kontakt@beberlei.de>
@@ -45,7 +46,8 @@ class UniqueEntity extends Constraint
4546
protected static $errorNames = self::ERROR_NAMES;
4647

4748
/**
48-
* @param array|string $fields the combination of fields that must contain unique values or a set of options
49+
* @param array|string $fields the combination of fields that must contain unique values or a set of options
50+
* @param bool|array|string $ignoreNull the combination of fields that ignore null values
4951
*/
5052
public function __construct(
5153
$fields,
@@ -55,7 +57,7 @@ public function __construct(
5557
string $entityClass = null,
5658
string $repositoryMethod = null,
5759
string $errorPath = null,
58-
bool $ignoreNull = null,
60+
bool|string|array $ignoreNull = null,
5961
array $groups = null,
6062
$payload = null,
6163
array $options = []

src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function validate(mixed $entity, Constraint $constraint)
8585
$class = $em->getClassMetadata($entity::class);
8686

8787
$criteria = [];
88-
$hasNullValue = false;
88+
$hasIgnorableNullValue = false;
8989

9090
foreach ($fields as $fieldName) {
9191
if (!$class->hasField($fieldName) && !$class->hasAssociation($fieldName)) {
@@ -94,11 +94,9 @@ public function validate(mixed $entity, Constraint $constraint)
9494

9595
$fieldValue = $class->reflFields[$fieldName]->getValue($entity);
9696

97-
if (null === $fieldValue) {
98-
$hasNullValue = true;
99-
}
97+
if (null === $fieldValue && $this->ignoreNullForField($constraint, $fieldName)) {
98+
$hasIgnorableNullValue = true;
10099

101-
if ($constraint->ignoreNull && null === $fieldValue) {
102100
continue;
103101
}
104102

@@ -114,7 +112,7 @@ public function validate(mixed $entity, Constraint $constraint)
114112
}
115113

116114
// validation doesn't fail if one of the fields is null and if null values should be ignored
117-
if ($hasNullValue && $constraint->ignoreNull) {
115+
if ($hasIgnorableNullValue) {
118116
return;
119117
}
120118

@@ -193,6 +191,15 @@ public function validate(mixed $entity, Constraint $constraint)
193191
->addViolation();
194192
}
195193

194+
private function ignoreNullForField(UniqueEntity $constraint, string $fieldName): bool
195+
{
196+
if (\is_bool($constraint->ignoreNull)) {
197+
return $constraint->ignoreNull;
198+
}
199+
200+
return \in_array($fieldName, (array) $constraint->ignoreNull, true);
201+
}
202+
196203
private function formatWithIdentifiers(ObjectManager $em, ClassMetadata $class, mixed $value): string
197204
{
198205
if (!\is_object($value) || $value instanceof \DateTimeInterface) {

0 commit comments

Comments
 (0)
0