Problem/Motivation
When attempting to add a validation constraint on a text_long
field (without summary), I ran into an issue where the violation path (string) $delta . '.value'
did not actually attach the error message to the value property, but rather to the whole widget.
Looking at Drupal\text\Plugin\Field\FieldWidget\TextareaWithSummaryWidget
, we see ::errorElement()
like so:
/**
* {@inheritdoc}
*/
public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
$element = parent::errorElement($element, $violation, $form, $form_state);
return ($element === FALSE) ? FALSE : $element[$violation->arrayPropertyPath[0]];
}
which is fine and good. Provided a $violation->arrayPropertyPath
of 'value'
, a violation targeting field_wysiwyg.value
will attach appropriately.
TextareaWidget
is somewhat different:
/**
* {@inheritdoc}
*/
public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
if ($violation->arrayPropertyPath == ['format'] && isset($element['format']['#access']) && !$element['format']['#access']) {
// Ignore validation errors for formats if formats may not be changed,
// such as when existing formats become invalid.
// See \Drupal\filter\Element\TextFormat::processFormat().
return FALSE;
}
return $element;
}
If called directly, it won't consult the arrayPropertyPath
and thus will target both the value and the format, leading to unfortunate issues like this.
Steps to reproduce
Create a constraint and validator targeting a text_long
field using a textarea
widget, and attempt to target the `value` property of the field in the validator like so:
$this->context->buildViolation($constraint->someMessage)
->atPath((string) $delta . '.value')
->setInvalidValue($text)
->addViolation();
Notice that both the format and the value fields are highlighted, that an error message appears under each, and that the link to the field is constructed inaccurately (e.g. it will link to /node/11463/edit#edit-field-content-block-0-subform-field-wysiwyg-0
when it should link to /node/11463/edit#edit-field-content-block-0-subform-field-wysiwyg-0-value
.
Proposed resolution
My proposed fix is to consult arrayPropertyPath
in TextareaWidget
and then remove the override in TextareaWithSummaryWidget
.
Like so:
TextareaWidget:
/**
* {@inheritdoc}
*/
public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
if ($violation->arrayPropertyPath == ['format'] && isset($element['format']['#access']) && !$element['format']['#access']) {
// Ignore validation errors for formats if formats may not be changed,
// such as when existing formats become invalid.
// See \Drupal\filter\Element\TextFormat::processFormat().
return FALSE;
}
if (($property = $violation->arrayPropertyPath[0]) && !empty($element[$property])) {
return $element[$property];
}
return $element;
}
Remaining tasks
I'll upload a patch here as soon as I remember how.