Spin-off from #2064191: Fix the 'target_bundle' field setting - 'target_bundles' are not validated when entity_reference is enabled
Problem/Motivation
The "selection handler" plugins are in charge of defining which entities can be referenced by an e_r field. However, they don't take part in the validation of entity_ref fields :
- ERItem::getConstraints() only hardcodes a check against the list of referenceable bundles, if the field uses the default "selection handler" plugin. That was added as a quickfix in #2064191: Fix the 'target_bundle' field setting - 'target_bundles' are not validated when entity_reference is enabled.
- Other selection handlers are left out of the validation process entirely. That includes ViewsSelector, which lets you define referenceable entities using a View, or even the various NodeSelector, UserSelector, that extend the default "by bundle" SelectorBase by refining the logic a bit (e.g "can't reference an unpublished node")
What is affected :
- REST operations
- The "options" widget are immune by design (they only let you select valid options), but they are seldom used (unusable with 20+ referenceable entities)
- The autocomplete widget is affected : it doesn't call the Selection plugin's validateReferenceableEntities(), because it uses the EntityAutocomplete FAPI element with #validate_reference = FALSE, which is correct for a widget (leave the real data validation to data-level constraints, to avoid doing the work twice), except the ValidReference constraint will do it (which it doesn't atm).
Meaning, the autocompletion list only shows valid options, but the user can manually type "whatever (42)", with 42 being the ID of any entity of the target type, and no error will be reported (other than the 'invalid bundle' violation caught by our hardcoded Bundle constraint). Any other restriction imposed by the Selection plugin is ignored .
- Other (contrib/custom) widgets can be affected as well, depending on their implementation.
Proposed resolution
It should be the selection handler plugins that define what is checked during validation, since they are the ones that already contain the logic for "what is referenceable for this field".
In #2064191: Fix the 'target_bundle' field setting - 'target_bundles' are not validated when entity_reference is enabled, it was considered to repurpose the existing ValidReference constraint to operate on the FieldItemList level (rather than Item-by-Item, which is a perf drag), and have its validator :
- collect the target_ids across each Item, call the *existing* $selector_plugin->validateReferenceableEntities($ids), and flag a violation on each delta whose target_id is deemed invalid
- collect the fresh ("autosaved") entities across each item, call a *new* $selector_plugin->validateNewEntities($entities) method (name TBD), and flag a violation on each delta whose entity is deemed invalid
As a side note : ViewsSelector is inherently incompatible with "autosave". You cannot validate that an $entity that isn't in the database yet will match a given View. How fun :-) That would probably need taking into account for the field config UI in #2412569: Target bundle for auto-created entity references with multiple target bundles. For the validation issue here, I guess ViewsSelector::isEntityValid() would just say "no / not supported" for unsaved entities.
Remaining tasks
- Decide/refine on the new SelectorInterface::validateNewEntities($entities)
- Fix tests
API changes
A new method would be needed on SelectorInterface to validate entities that are not in the db yet.