Commit 3b951a05 authored by alexpott's avatar alexpott

Issue #2784015 by amateescu, jlbellido, Gogowitsch, krknth, ibustos: Widget...

Issue #2784015 by amateescu, jlbellido, Gogowitsch, krknth, ibustos: Widget validation crashes on ItemList violations for widgets with a custom errorElement() implementation
parent b6890803
......@@ -118,7 +118,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
* {@inheritdoc}
*/
public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) {
return isset($element['target_id']) ? $element['target_id'] : FALSE;
return $element['target_id'];
}
/**
......
......@@ -423,21 +423,26 @@ public function flagErrors(FieldItemListInterface $items, ConstraintViolationLis
if (Element::isVisibleElement($element)) {
$handles_multiple = $this->handlesMultipleValues();
$violations_by_delta = [];
$violations_by_delta = $item_list_violations = [];
foreach ($violations as $violation) {
// Separate violations by delta.
$property_path = explode('.', $violation->getPropertyPath());
$delta = array_shift($property_path);
$violations_by_delta[$delta][] = $violation;
if (is_numeric($delta)) {
$violations_by_delta[$delta][] = $violation;
}
// Violations at the ItemList level are not associated to any delta.
else {
$item_list_violations[] = $violation;
}
$violation->arrayPropertyPath = $property_path;
}
/** @var \Symfony\Component\Validator\ConstraintViolationInterface[] $delta_violations */
foreach ($violations_by_delta as $delta => $delta_violations) {
// Pass violations to the main element:
// - if this is a multiple-value widget,
// - or if the violations are at the ItemList level.
if ($handles_multiple || !is_numeric($delta)) {
// Pass violations to the main element if this is a multiple-value
// widget.
if ($handles_multiple) {
$delta_element = $element;
}
// Otherwise, pass errors by delta to the corresponding sub-element.
......@@ -453,6 +458,13 @@ public function flagErrors(FieldItemListInterface $items, ConstraintViolationLis
}
}
}
/** @var \Symfony\Component\Validator\ConstraintViolationInterface[] $item_list_violations */
// Pass violations to the main element without going through
// errorElement() if the violations are at the ItemList level.
foreach ($item_list_violations as $violation) {
$form_state->setError($element, $violation->getMessage());
}
}
}
}
......
......@@ -3,6 +3,7 @@
namespace Drupal\entity_test\Entity;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
/**
* Defines the test entity class for testing entity constraint violations.
......@@ -39,6 +40,16 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
]);
$fields['name']->addConstraint('FieldWidgetConstraint', []);
// Add a field that uses a widget with a custom implementation for
// \Drupal\Core\Field\WidgetInterface::errorElement().
$fields['test_field'] = BaseFieldDefinition::create('integer')
->setLabel(t('Test field'))
->setDisplayOptions('form', [
'type' => 'number',
'weight' => 1,
])
->addConstraint('FieldWidgetConstraint', []);
return $fields;
}
......
......@@ -87,15 +87,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
*/
public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
$element = parent::errorElement($element, $violation, $form, $form_state);
if ($element === FALSE) {
return FALSE;
}
elseif (isset($violation->arrayPropertyPath[0])) {
return $element[$violation->arrayPropertyPath[0]];
}
else {
return $element;
}
return ($element === FALSE) ? FALSE : $element[$violation->arrayPropertyPath[0]];
}
}
......@@ -15,7 +15,7 @@
*/
class FieldWidgetConstraintValidatorTest extends KernelTestBase {
public static $modules = ['entity_test', 'field', 'user', 'system'];
public static $modules = ['entity_test', 'field', 'field_test', 'user', 'system'];
/**
* {@inheritdoc}
......@@ -54,7 +54,8 @@ public function testValidation() {
$display->validateFormValues($entity, $form, $form_state);
$errors = $form_state->getErrors();
$this->assertEqual($errors['name'], 'Widget constraint has failed.', 'Constraint violation is generated correctly');
$this->assertEqual($errors['name'], 'Widget constraint has failed.', 'Constraint violation at the field items list level is generated correctly');
$this->assertEqual($errors['test_field'], 'Widget constraint has failed.', 'Constraint violation at the field items list level is generated correctly for an advanced widget');
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment