Problem
Follow-up for #2002158: Convert form validation of comments to entity validation: In the original issue all validation logic for fields has been converted to the entity validation API, however conditional validation logic that validates field values in dependence of another field value has not been converted. See CommentForm::validate() for the logic that needs conversion.
Proposed resolution
Solve #2105797: Add CompositeConstraintBase so that constraints involving multiple fields, such as CommentNameConstraint, can be discovered and apply the solution by moving validation logic to the CommentNameConstraint or other respective constraints.
Current code with annotations
parent::validate($form, $form_state);
$entity = $this->entity;
if (!$entity->isNew()) {
/** Does this hunk belong in a pre-save submit handler, not validate? There is no validation **/
// Verify the name in case it is being changed from being anonymous.
$accounts = $this->entityManager->getStorage('user')->loadByProperties(array('name' => $form_state->getValue('name')));
$account = reset($accounts);
$form_state->setValue('uid', $account ? $account->id() : 0);
/** This needs to be a validation handler (handler 1) **/
$date = $form_state->getValue('date');
if ($date instanceOf DrupalDateTime && $date->hasErrors()) {
$form_state->setErrorByName('date', $this->t('You have to specify a valid date.'));
}
/** This needs to be another validation handler (handler 2) **/
if ($form_state->getValue('name') && !$form_state->getValue('is_anonymous') && !$account) {
$form_state->setErrorByName('name', $this->t('You have to specify a valid author.'));
}
}
/** This exists - CommentName **/
elseif ($form_state->getValue('is_anonymous')) {
// Validate anonymous comment author fields (if given). If the (original)
// author of this comment was an anonymous user, verify that no registered
// user with this name exists.
if ($form_state->getValue('name')) {
$accounts = $this->entityManager->getStorage('user')->loadByProperties(array('name' => $form_state->getValue('name')));
if (!empty($accounts)) {
$form_state->setErrorByName('name', $this->t('The name you used belongs to a registered user.'));
}
}
}
Remaining tasks
All.
User interface changes
-
API changes
-
Beta phase evaluation
Issue category | Bug because the conversion is supposed to be complete and required for REST validation to cover it. |
---|---|
Issue priority | Critical, because REST request might miss some validation logic. |
Disruption | Not disruptive as comment and form validation works as before, comment entity validation just becomes more complete. |
Comment | File | Size | Author |
---|---|---|---|
#48 | comment-constraints.48.patch | 15.1 KB | larowlan |
#48 | interdiff.txt | 3.38 KB | larowlan |
Comments
Comment #1
Berdir#2227503: Apply formatters and widgets to Comment base fields is doing a lot there already, but we have issues with the uid/author behavior, I don't know how to fix that.
Comment #2
larowlanIs this a critical if we have a critical meta? I'd think that'd make this a major?
Also postponed on issue in OP
Comment #3
larowlanDiscussed with catch
Comment #4
larowlanAdded proposed handler to issue summary - I see there are three, and one hunk that belongs in a pre-save handler (is not to do with validaton)
Comment #5
larowlanTaking this on, doesn't need that issue to progress from what I can see
Comment #6
larowlanhandler 3 already exists
Comment #7
larowlanComment #8
larowlanWIP, doesn't touch 'date' yet - @Berdir indicated there are fixes in #2227503: Apply formatters and widgets to Comment base fields for that, so posting what I have and moving over there
Comment #9
kim.pepperIf you want to inject dependencies, just implement
\Drupal\Core\Plugin\ContainerFactoryPluginInterface::create
Comment #11
fagoWe need take account of the settings also, i.e. check CommentForm #required name.
The same applies to email and homepage.
The form also uses "name" to assign the comment owner if it matches a user name. Imo, we can/should use that in buildEntity() to update the comment owner and name fields respectively, then comment validation should be able to run from there.
Comment #12
larowlanmore work
fixes #11
#9 see #2197029: Allow to inject dependencies into validation constraints
still to do - date
Also think #2227503: Apply formatters and widgets to Comment base fields will come back green now - but some questions around UX
Comment #13
larowlanthis ensures the
=== 0
in the validator works, because "0" (from form submissions) !== 0Comment #15
larowlanComment #17
andypostprotected
get6X()
helper would be great!needs comment/todo why limiting type
why not check that entity implements
getOwnerId()
method?author name used latter and
isEmpty()
looks more reasonableComment #18
larowlanThanks @andypost will do
Comment #19
larowlanTagging for today's office hours
Comment #20
kim.pepperTaking a look
Comment #21
kim.pepperThis (hopefully) addresses the points in #17 Didn't get time to look at the fail, sorry.
Comment #22
kim.pepperComment #24
kim.pepperRolled back the isEmpty() change as it caused more fails.
Comment #26
amitgoyal CreditAttribution: amitgoyal commentedComment #27
idebr CreditAttribution: idebr commentedThis should fix the failing test. Just date left now.
Comment #28
larowlanLegend! thanks
This should happen in ::buildEntity? Which should in turn trigger the validation in ::validate(). I wonder why that isn't happening
Comment #29
larowlanFixes #28
CommentForm wasn't using buildEntity in the same fashion as other entity forms, is now.
Now onto date
Comment #30
larowlandidn't mean that
Comment #31
larowlanDoes date and the rest
Comment #32
jibranOver are patch look good. Just some minor issues. I think it is ready.
Let's call it comment. Comment entity and commented entity is already very confusing imo.
I think it is fixed by #2232477: Fatal when adding new fields with NOT NULL constraints in a base table that contains existing entities.
This is a comment right? Can we rename it?
I confused it with core contact entity can we rename this?
You can use isAuthenticated instead.
User::create
Comment #33
larowlanFixed #32 except for #2 - see the comment in the code for the reasoning.
Comment #34
jibranThank you for the fixes.
Comment #35
alexpottThis looks untested.
Where has this validation gone?
Comment #36
fagoI think we should be able to do all validation logic with constraints now, and move conditional stuff into constraints.
Then we need to solve #2395831: Entity forms skip validation of fields that are not in the EntityFormDisplay just to make sure the violations are not wrongly ignored. We might have to change constraints registration a bit, but as the logic won't change it makes sense to convert this now. I'll take a look at it.
So invalid name validation will be done by the constraint, right? So let's comment that.
Usually, this would be just a widget imo, and thus widget validation, but as we've got the $comment->name this case a bit different.
wrong comment.
I don't think validation should be different depending on the currently logged in user - imo we should avoid that as far as possible. It should be enough to verify the comment name matches the set owner, if given.
Comment #37
fagook, worked over the patch to move all conditional logic intro constraints, which get always invoked. Also, I addressed my remarks. ad 2), this actually is not about validation but building the entity, thus I fixed the comment instead. I moved all name related validation logic in the comment name constraint, as I don't think it makes much sense to have to custom constraints for the same field - both wouldn't be re-usable anyway.
Finally, I extended validation a bit such that we ensure a stored author name matches a stored comment author. As usually, we store the comment name in addition to the comment author reference I guess it would make sense to enforce that via a presave hook. However, changing that behaviour seems to be out-of-scope for this issue, thus I just made sure any saved author name value matches (and added test coverage for that).
Comment #38
larowlanInterdiff for 37
Comment #39
andypostis this really gone?
Type checking could fail. Suppose better to use isAnonymous() on author entity.
Also 0 has special constant.
Comment #40
larowlangrep says yes
Comment #41
andypostso if current user switched somehow between form build and validate then form processing is wrong
Comment #42
larowlanCould be combined into one if.
So those two minor changes and I think this is RTBC again. I'll talk someone through it during tomorrow's critical office hours.
Manually tested removal of the old is_anonymous - works great
Comment #43
larowlanor I'll just do it now :)
fixed #39 and #42
Comment #45
larowlanWe can't use getOwner()->isAnonymous() because sometimes the user entity is not set.
I think this is rtbc again
Comment #46
fagoRight. Seems wrong if you would do that to me though.
Thanks larowan for the changes, looks good. I agree that this is ready again.
Comment #47
jibranSo @fago +1ed it so nothing functional just extreme nits
@var blocks missing.
These can switch places.
I don't see this var anywhere? Maybe stale comment. Or move it near the use of var :)
Can we use === here?
Gets the anonymous contact details setting form the comment.
@param type mismatch. Can we please rename it to comment?
I think we can use getSetting('anonymous') here
Comment #48
larowlanFixes ##4
Comment #49
jibranThanks for the fixes. As per #46 it is RTBC.
Comment #50
alexpottThis issue addresses a critical bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 91a0564 and pushed to 8.0.x. Thanks!
Lovely.
Comment #52
Wim LeersThis also opens the door to interesting new comment UIs and mechanisms in (headless) D8, without having to reimplement all validation :) Great work!
Comment #53
bzrudi71 CreditAttribution: bzrudi71 commentedNice! This one fixed all remaining exceptions in #2356967: PostgreSQL: Fix tests in comment test group and just leaves 2 fails open in new CommentRestExportTest tests. Great!
Comment #54
fagoDone. :)