Issue #2901943 by amateescu, Berdir: Content entity form validation does not respect the #limit_validation_errors property from field widgets
parent
3529e208aa
commit
12a28a5eba
|
@ -188,10 +188,29 @@ class ContentEntityForm extends EntityForm implements ContentEntityFormInterface
|
||||||
|
|
||||||
$violations = $entity->validate();
|
$violations = $entity->validate();
|
||||||
|
|
||||||
// Remove violations of inaccessible fields and not edited fields.
|
// Remove violations of inaccessible fields.
|
||||||
$violations
|
$violations->filterByFieldAccess($this->currentUser());
|
||||||
->filterByFieldAccess($this->currentUser())
|
|
||||||
->filterByFields(array_diff(array_keys($entity->getFieldDefinitions()), $this->getEditedFieldNames($form_state)));
|
// In case a field-level submit button is clicked, for example the 'Add
|
||||||
|
// another item' button for multi-value fields or the 'Upload' button for a
|
||||||
|
// File or an Image field, make sure that we only keep violations for that
|
||||||
|
// specific field.
|
||||||
|
$edited_fields = [];
|
||||||
|
if ($limit_validation_errors = $form_state->getLimitValidationErrors()) {
|
||||||
|
foreach ($limit_validation_errors as $section) {
|
||||||
|
$field_name = reset($section);
|
||||||
|
if ($entity->hasField($field_name)) {
|
||||||
|
$edited_fields[] = $field_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$edited_fields = array_unique($edited_fields);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$edited_fields = $this->getEditedFieldNames($form_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove violations for fields that are not edited.
|
||||||
|
$violations->filterByFields(array_diff(array_keys($entity->getFieldDefinitions()), $edited_fields));
|
||||||
|
|
||||||
$this->flagViolations($violations, $form, $form_state);
|
$this->flagViolations($violations, $form, $form_state);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\FunctionalTests\Entity;
|
||||||
|
|
||||||
|
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||||
|
use Drupal\field\Entity\FieldConfig;
|
||||||
|
use Drupal\field\Entity\FieldStorageConfig;
|
||||||
|
use Drupal\Tests\BrowserTestBase;
|
||||||
|
use Drupal\Tests\TestFileCreationTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests field validation filtering on content entity forms.
|
||||||
|
*
|
||||||
|
* @group Entity
|
||||||
|
*/
|
||||||
|
class ContentEntityFormFieldValidationFilteringTest extends BrowserTestBase {
|
||||||
|
|
||||||
|
use TestFileCreationTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the type of the entity under test.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $entityTypeId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The single-valued field name being tested with the entity type.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $fieldNameSingle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The multi-valued field name being tested with the entity type.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $fieldNameMultiple;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the file field being tested with the entity type.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $fieldNameFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = ['entity_test', 'field_test', 'file', 'image'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$web_user = $this->drupalCreateUser(['administer entity_test content']);
|
||||||
|
$this->drupalLogin($web_user);
|
||||||
|
|
||||||
|
// Create two fields of field type "test_field", one with single cardinality
|
||||||
|
// and one with unlimited cardinality on the entity type "entity_test". It
|
||||||
|
// is important to use this field type because its default widget has a
|
||||||
|
// custom \Drupal\Core\Field\WidgetInterface::errorElement() implementation.
|
||||||
|
$this->entityTypeId = 'entity_test';
|
||||||
|
$this->fieldNameSingle = 'test_single';
|
||||||
|
$this->fieldNameMultiple = 'test_multiple';
|
||||||
|
$this->fieldNameFile = 'test_file';
|
||||||
|
|
||||||
|
FieldStorageConfig::create([
|
||||||
|
'field_name' => $this->fieldNameSingle,
|
||||||
|
'entity_type' => $this->entityTypeId,
|
||||||
|
'type' => 'test_field',
|
||||||
|
'cardinality' => 1,
|
||||||
|
])->save();
|
||||||
|
FieldConfig::create([
|
||||||
|
'entity_type' => $this->entityTypeId,
|
||||||
|
'field_name' => $this->fieldNameSingle,
|
||||||
|
'bundle' => $this->entityTypeId,
|
||||||
|
'label' => 'Test single',
|
||||||
|
'required' => TRUE,
|
||||||
|
'translatable' => FALSE,
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
FieldStorageConfig::create([
|
||||||
|
'field_name' => $this->fieldNameMultiple,
|
||||||
|
'entity_type' => $this->entityTypeId,
|
||||||
|
'type' => 'test_field',
|
||||||
|
'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
|
||||||
|
])->save();
|
||||||
|
FieldConfig::create([
|
||||||
|
'entity_type' => $this->entityTypeId,
|
||||||
|
'field_name' => $this->fieldNameMultiple,
|
||||||
|
'bundle' => $this->entityTypeId,
|
||||||
|
'label' => 'Test multiple',
|
||||||
|
'translatable' => FALSE,
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
// Also create a file field to test its '#limit_validation_errors'
|
||||||
|
// implementation.
|
||||||
|
FieldStorageConfig::create([
|
||||||
|
'field_name' => $this->fieldNameFile,
|
||||||
|
'entity_type' => $this->entityTypeId,
|
||||||
|
'type' => 'file',
|
||||||
|
'cardinality' => 1,
|
||||||
|
])->save();
|
||||||
|
FieldConfig::create([
|
||||||
|
'entity_type' => $this->entityTypeId,
|
||||||
|
'field_name' => $this->fieldNameFile,
|
||||||
|
'bundle' => $this->entityTypeId,
|
||||||
|
'label' => 'Test file',
|
||||||
|
'translatable' => FALSE,
|
||||||
|
])->save();
|
||||||
|
|
||||||
|
|
||||||
|
entity_get_form_display($this->entityTypeId, $this->entityTypeId, 'default')
|
||||||
|
->setComponent($this->fieldNameSingle, ['type' => 'test_field_widget'])
|
||||||
|
->setComponent($this->fieldNameMultiple, ['type' => 'test_field_widget'])
|
||||||
|
->setComponent($this->fieldNameFile, ['type' => 'file_generic'])
|
||||||
|
->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests field widgets with #limit_validation_errors.
|
||||||
|
*/
|
||||||
|
public function testFieldWidgetsWithLimitedValidationErrors() {
|
||||||
|
$assert_session = $this->assertSession();
|
||||||
|
$this->drupalGet($this->entityTypeId . '/add');
|
||||||
|
|
||||||
|
// The 'Test multiple' field is the only multi-valued field in the form, so
|
||||||
|
// try to add a new item for it. This tests the '#limit_validation_errors'
|
||||||
|
// property set by \Drupal\Core\Field\WidgetBase::formMultipleElements().
|
||||||
|
$assert_session->elementsCount('css', 'div#edit-test-multiple-wrapper div.form-type-textfield input', 1);
|
||||||
|
$this->drupalPostForm(NULL, [], 'Add another item');
|
||||||
|
$assert_session->elementsCount('css', 'div#edit-test-multiple-wrapper div.form-type-textfield input', 2);
|
||||||
|
|
||||||
|
// Now try to upload a file. This tests the '#limit_validation_errors'
|
||||||
|
// property set by
|
||||||
|
// \Drupal\file\Plugin\Field\FieldWidget\FileWidget::process().
|
||||||
|
$text_file = current($this->getTestFiles('text'));
|
||||||
|
$edit = [
|
||||||
|
'files[test_file_0]' => drupal_realpath($text_file->uri)
|
||||||
|
];
|
||||||
|
$assert_session->elementNotExists('css', 'input#edit-test-file-0-remove-button');
|
||||||
|
$this->drupalPostForm(NULL, $edit, 'Upload');
|
||||||
|
$assert_session->elementExists('css', 'input#edit-test-file-0-remove-button');
|
||||||
|
|
||||||
|
// Make the 'Test multiple' field required and check that adding another
|
||||||
|
// item throws a validation error.
|
||||||
|
$field_config = FieldConfig::loadByName($this->entityTypeId, $this->entityTypeId, $this->fieldNameMultiple);
|
||||||
|
$field_config->setRequired(TRUE);
|
||||||
|
$field_config->save();
|
||||||
|
|
||||||
|
$this->drupalPostForm($this->entityTypeId . '/add', [], 'Add another item');
|
||||||
|
$assert_session->pageTextContains('Test multiple (value 1) field is required.');
|
||||||
|
|
||||||
|
// Check that saving the form without entering any value for the required
|
||||||
|
// field still throws the proper validation errors.
|
||||||
|
$this->drupalPostForm(NULL, [], 'Save');
|
||||||
|
$assert_session->pageTextContains('Test single field is required.');
|
||||||
|
$assert_session->pageTextContains('Test multiple (value 1) field is required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue