Below are my findings and the result of dozens of hours spent of unrewarding digging in the code.

I was trying to create a validation constraint for a custom entity and figured out that it is impossible to create a violation for a field properly.

First, it seems to be impossible to create a constraint dynamically, while this is purely corresponds to the logic of validation: in an entity constraint validator or entity validate() method one can decide to enable constraints on some entity fields depending on some conditions like the weather condition or other field values. But there's no way to do this, at least none I personally found.

Second, I found no way to create a violation for a field so that the Entity form could reflect this.
For example this:

$this->context->buildViolation($constraint->message)->atPath($field_name)->addViolation();

will never throw any violation and just saves wrong entity simply because Drupal can't set error due to how WidgetBase process fields. The latter finally calls:

$error_element = $this->errorElement($delta_element, $violation, $form, $form_state);

but $delta_element contains parent element and not the value itself. So it's not actually a delta_element, instead it's a wrappring element. For example this is how EntityReferenceAutocompleteWidget->errorElement() is implemented:

  public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) {
    return isset($element['target_id']) ? $element['target_id'] : FALSE;

i.e. it expects 'target_id' item while it lives one level deeper (under '0' key). This results to FALSE and the violation is just skipped.
In other words, I found no way to set error on a field from the entity validator. I consider this as a bug.

The only way I found so far to not get the violation ignored is to NOT specify the field_name:

$this->context->buildViolation($constraint->message)->addViolation();

But in this case user doesn't see the wrong field highlighted, which is a hit at usability obviously.

Huh...

Comments

OnkelTem created an issue. See original summary.

jdleonard’s picture

Version: 8.0.5 » 8.4.x-dev
Category: Support request » Bug report
Priority: Normal » Major
Related issues: +#2027059: Improve the documentation of WidgetBase::errorElement() for mapping violation property paths to form elements

I just ran into this exact same issue while writing an entity constraint validator. It seems that this will likely be solved in #2027059: Improve the documentation of WidgetBase::errorElement() for mapping violation property paths to form elements.

I believe this qualifies as a Major Bug because it "Render[s] one feature unusable with no workaround" and/or "Block[s] contributed projects with no workaround".

amateescu’s picture

Status: Active » Closed (duplicate)