Problem/Motivation
It's possible to perform bulk actions on entities, and in some cases no validation is performed before the entity is saved.
This became apparent in #3243383: Allow flags to be limited to specific entity types and bundles. There may be other actions that need this as well.
Steps to reproduce
- Create a flag that only applies to one bundle of an entity type.
- Select two entities in /assets - one that is the applicable bundle, and one that is not.
- Select "Flag asset"
- Select a flag that should not be applicable to the other bundle.
- Save - it adds the flag to the bundle that should not receive it.
Proposed resolution
Perform entity validation before calling $entity->save().
Remaining tasks
Implement and test.
User interface changes
None.
API changes
None.
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #5 | example_flag_validation_error.png | 12.4 KB | paul121 |
Issue fork farm-3243667
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 2.x-action-entity-validation
changes, plain diff MR !52
Comments
Comment #2
m.stentaComment #3
paul121 commentedWhat should the expected behavior be when validation fails? I think there are two general options..
I assume option 1 is the easy first step. Is it worth giving 2 much thought? If you select 50 entities, and validation fails on half of them, isn't that kinda annoying? Maybe the reason they fail validation should be the larger consideration..
It would be difficult to fail applying the action to *all entities* since it would require some kind of "undo" logic.. Consider 10 entities, if the 5th one fails, but the previous 1-4 were OK (and already saved), the change would need to be reverted to properly "bail" the entire action.
Or, I suppose the action could go through and make the change but only save the entities as a last step if they all pass validation.
Comment #4
m.stentaI think this makes the most sense to start with, for all the reasons you described.
Comment #5
paul121 commentedI'm curious the best way to go about this. My first simple approach was to simply loop though all of the validation errors and add warning messages for each error but the issue is that the validation errors aren't meaningful by themselves, they really need the context of which field they are associated with. This is called the "property path" with constraint violations. In entity forms the property path is used to highlight the correct input element associated with the constraint violation.
For example, with this simple approach when assigning an invalid flag (as described in the issue summary) the validation message is simply: "The value you selected is not a valid choice." (see attached screenshot). With the property path of "flag.0" this message makes more sense, but I'm not sure how to represent this property path context in warning message. Can we do better than simply including "flag.0" ?
We should also consider that a custom constraint may span multiple fields, eg: "do not allow the 'needs review' flag if the asset is archived", in which case the property path may not be coupled to a single field. Also worth noting that constraints can be added to individual field properties eg:
valueortarget_idon a more granular level.One solution to this problem is to override the "default" constraints with messages that are more descriptive. I believe that the default constraints for a given field could be replaced altogether (with new constraint classes), or it seems that individual messages can be overwritten (this works for the flag action form, but I haven't tested more thoroughly). For example, modifying the flag field
list_itemdefinition'sAllowedValuesconstraint message:If modifying the constraint message like this does not have any other side effects then I think this could be a good path forward. It has the added benefit of a more descriptive constraint message which I imagine would be preferred in most other places too. Unfortunately it still isn't very easy to include the "invalid value" and "allowed values" in the error message without implementing a custom constraint eg: "The "monitoring" flag is not allowed on land assets. Use "priority" instead."
Alternatively, we could naively make the warning message "Could not flag {entity}: validation failed." - but IMO this isn't that helpful anyways.
Comment #6
paul121 commentedAlso worth noting that individual bulk actions could perform more selective validation checking themselves - for example, the flag action could explicitly check for validation errors on the
entity.flagfield and provide a more descriptive error message since the action has knowledge of that specific field. For flags this wouldn't be worthwhile since we implemented logic to prevent "invalid" choices from the UI (thus making the situation described in issue summary a bit irrelevant.. :-) but the idea still holds.BUT my understanding is that this issue is aiming to catch validation errors more generally, when an action might not know about constraint provided by another module. This is the more robust solution anyways. I'd love to see this working.
TL;DR I feel like this issue is *very* important, but could also be quite a bit of work from the get go. So maybe not a beta-blocker? It is likely something we would continue iterating on as edge cases are revealed (new actions are created) and we choose to add additional and more descriptive validation errors.
What do ya think @mstenta?
Comment #7
m.stentaI think there are two separate considerations here:
The first one is by far the most important.
A very simple/naive warning would "prevent invalid data" (most importantly), but it would not "display useful messages".
It seems like we should start with a naive message at the very least, to address the most important part of this (invalid data being saved).
Improving the warnings could be a follow-up, or maybe we don't even need to worry about it right now (wait until someone complains). As long as we know which entity is failing, the user can go to that entity and try to make the change manually, which will then provide better information about what the problem is. That would be the workaround.
Comment #9
paul121 commentedHere's a pass at a simple validation message when entity validation fails. I think these are all of the places we have actions that need to perform validation.... will also need to replicate the state change validation in the log module.
This is a hard thing to test without additional custom constraints. I tested this by modifying/adding a new flag that was limited to only a single log bundle and removed logic from the entity flag action form to allow *all* flags when using the action. This lets you see the validation warning message happen.
Comment #11
m.stentaThanks @paul121! Merged!
I went ahead and did this (and credited you because it was largely copy+paste), tagged Log 2.0.2, and updated farmOS's
composer.jsonto use it.