Skip to content

Commit

Permalink
Allow to ignore specific nullable fields
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet committed Feb 8, 2023
1 parent e480a66 commit beee940
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,9 @@ public function testValidateUniquenessWithNull(UniqueEntity $constraint)

/**
* @dataProvider provideConstraintsWithIgnoreNullDisabled
* @dataProvider provideConstraintsWithIgnoreNullEnabledOnFirstField
*/
public function testValidateUniquenessWithIgnoreNullDisabled(UniqueEntity $constraint)
public function testValidateUniquenessWithIgnoreNullDisableOnSecondField(UniqueEntity $constraint)
{
$entity1 = new DoubleNameEntity(1, 'Foo', null);
$entity2 = new DoubleNameEntity(2, 'Foo', null);
Expand Down Expand Up @@ -303,6 +304,7 @@ public function testAllConfiguredFieldsAreCheckedOfBeingMappedByDoctrineWithIgno

/**
* @dataProvider provideConstraintsWithIgnoreNullEnabled
* @dataProvider provideConstraintsWithIgnoreNullEnabledOnFirstField
*/
public function testNoValidationIfFirstFieldIsNullAndNullValuesAreIgnored(UniqueEntity $constraint)
{
Expand Down Expand Up @@ -337,6 +339,18 @@ public function provideConstraintsWithIgnoreNullEnabled(): iterable
yield 'Named arguments' => [new UniqueEntity(message: 'myMessage', fields: ['name', 'name2'], em: 'foo', ignoreNull: true)];
}

public function provideConstraintsWithIgnoreNullEnabledOnFirstField(): iterable
{
yield 'Doctrine style (name field)' => [new UniqueEntity([
'message' => 'myMessage',
'fields' => ['name', 'name2'],
'em' => self::EM_NAME,
'ignoreNull' => 'name',
])];

yield 'Named arguments (name field)' => [new UniqueEntity(message: 'myMessage', fields: ['name', 'name2'], em: 'foo', ignoreNull: 'name')];
}

public function testValidateUniquenessWithValidCustomErrorPath()
{
$constraint = new UniqueEntity([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* Constraint for the Unique Entity validator.
*
* @Annotation
*
* @Target({"CLASS", "ANNOTATION"})
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
Expand Down Expand Up @@ -45,7 +46,8 @@ class UniqueEntity extends Constraint
protected static $errorNames = self::ERROR_NAMES;

/**
* @param array|string $fields the combination of fields that must contain unique values or a set of options
* @param array|string $fields the combination of fields that must contain unique values or a set of options
* @param bool|array|string $ignoreNull the combination of fields that ignore null values
*/
public function __construct(
$fields,
Expand All @@ -55,7 +57,7 @@ public function __construct(
string $entityClass = null,
string $repositoryMethod = null,
string $errorPath = null,
bool $ignoreNull = null,
bool|string|array $ignoreNull = null,
array $groups = null,
$payload = null,
array $options = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public function validate(mixed $entity, Constraint $constraint)
$class = $em->getClassMetadata($entity::class);

$criteria = [];
$hasNullValue = false;
$hasIgnorableNullValue = false;

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

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

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

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

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

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

Expand Down Expand Up @@ -193,6 +191,15 @@ public function validate(mixed $entity, Constraint $constraint)
->addViolation();
}

private function ignoreNullForField(UniqueEntity $constraint, string $fieldName): bool
{
if (\is_bool($constraint->ignoreNull)) {
return $constraint->ignoreNull;
}

return \in_array($fieldName, (array) $constraint->ignoreNull, true);
}

private function formatWithIdentifiers(ObjectManager $em, ClassMetadata $class, mixed $value)
{
if (!\is_object($value) || $value instanceof \DateTimeInterface) {
Expand Down

0 comments on commit beee940

Please sign in to comment.