Problem/Motivation
Closer look at validator
/**
* {@inheritdoc}
*/
public function validate($items, Constraint $constraint) {
if (!$item = $items->first()) {
return;
}
$field_name = $items->getFieldDefinition()->getName();
/** @var \Drupal\Core\Entity\EntityInterface $entity */
$entity = $items->getEntity();
$entity_type_id = $entity->getEntityTypeId();
$id_key = $entity->getEntityType()->getKey('id');
$value_taken = (bool) \Drupal::entityQuery($entity_type_id)
// The id could be NULL, so we cast it to 0 in that case.
->condition($id_key, (int) $items->getEntity()->id(), '<>')
->condition($field_name, $item->value)
->range(0, 1)
->count()
->execute();
if ($value_taken) {
$this->context->addViolation($constraint->message, [
'%value' => $item->value,
'@entity_type' => $entity->getEntityType()->getLowercaseLabel(),
'@field_name' => mb_strtolower($items->getFieldDefinition()->getLabel()),
]);
}
}
reviled that only first field item is check for duplicates.
Proposed resolution
Add test coverage and fix validator.
Remaining tasks
- Write test to confirm bug
- Write test/s to cover all field types that doesn't have a field specific "unique" constraints/validators (see related issues)
- Review
- Commit
User interface changes
None
API changes
None
Data model changes
None
| Comment | File | Size | Author |
|---|---|---|---|
| #13 | 2999225-13.patch | 7.72 KB | rosk0 |
| #13 | 2999225-13-test-only.patch | 6.9 KB | rosk0 |
Comments
Comment #2
rosk0Comment #3
rosk0Test only patch.
Comment #5
rosk0Appropriate test.
Float fields validation still doesn't work and I don't understand why...
Comment #6
rosk0Forgotten patch.
Comment #8
rosk0Spent couple hours reading floats documentation to remember/understand them and why test wasn't working as I expected. Basically it doesn't make any sense to expect this constraint being applied to float because they are so tricky and
I removed them from test. Any kind of uniqueness/validation for float fields will require custom constraint with corresponding business logic.
Bug still there of the rest of fields types: email, telephone, datetime, list_integer, list_string, timestamp, text, string, decimal, integer. So provided patch has test for them and fixed validator.
Expected fail in test-only patch.
Comment #10
wengerkAdd #2478663: UniqueFieldValueValidator works only with single value fields as related issue.
It may seems to be a duplicate nop ?
I see that #2478663: UniqueFieldValueValidator works only with single value fields doesn't have a working patch, what should we do ?
Comment #12
alphawebgroupHi Guys
the latest 2999225-9.patch is failed to apply
Comment #13
rosk0Re-roll.
I will will probably update referenced in #10 issue with the patch from here and close this one as the other is older and has more people looking at it.
Let's make sure that patch is still working first.
Comment #15
berdirTechnically hardcoding ->value is wrong as you could for example use this on an entity reference field. But that was already wrong before and is a separate problem.
not a huge fan of data providers on kernel tests. While they are much faster than functional tests, there's still a bit of overhead. Could also be done with just a regular loop over the data returned by this, not sure.
Comment #16
cilefen commentedComment #18
andyf commentedThanks, this seems to be working for me!
I don't want to divert the issue but was wondering if it makes sense to add a method for grabbing the value just in anticipation of solving the problem for different field types, eg. ER, elsewhere - please see attached.
Comment #19
andyf commented(Exactly the same patch as #18 rolled for D8.7.)
Comment #20
joachim commented> if it makes sense to add a method for grabbing the value just in anticipation of solving the problem for different field types, eg. ER, elsewhere - please see attached.
I don't think the approach in the patch is the right one. The patch is adding a method to the validator. But we're not going to subclass the validator for different field types are we? That would be a pain.
Isn't mainPropertyName() what we should use here?
Comment #21
berdir> mainPropertyName()
Yes. But as I wrote, I'd be fine to improve that in a follow-up issue, it's existing problem with the current code.
Comment #22
andyf commentedSorry all, I think I have diverted the issue: I'll hide the patches I added. @joachim IIUC you're suggesting I do something along the lines of this?
Putting back to needs review for #13.
Thanks!
Comment #23
joachim commented> @joachim IIUC you're suggesting I do something along the lines of this?
Yes, though I agree with @Berdir that it's best done in a follow-up, to keep this issue about just one problem.
(Sorry, I should have said that in my earlier comment!)
Comment #24
andyf commentedThanks, understood, I kinda knew I was breakin the rules but foolishly thought my change would be small and correct! My specific use case is a multi-value ER field, so I've added a little comment to #2973455: Unique field constraint does not work with any field main property name that is not "value".
Thanks!
Comment #25
andyf commentedAt the moment the validator's still passing
$item->valueas part of the violation message.Also at least the following constraints' messages are worded for a single value, don't know if that's something to be addressed as part of this issue?
FeedTitleConstraintFeedUrlConstraintFileUriUniqueUniqueFieldConstraintUserMailUniqueUserNameUniqueI guess any error message we give for a multi-value field will be (annoyingly?) vague or require more queries or entity loading?
Thanks
Comment #26
mbovan commentedIn my opinion #2478663: UniqueFieldValueValidator works only with single value fields provides a more comprehensive fix considering #2478663-56... The tests from this issue would be very useful.
Comment #34
caesius commentedThis issue should now be resolved by #2478663: UniqueFieldValueValidator works only with single value fields
Comment #35
caesius commented