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();
|
||||
|
||||
// Remove violations of inaccessible fields and not edited fields.
|
||||
$violations
|
||||
->filterByFieldAccess($this->currentUser())
|
||||
->filterByFields(array_diff(array_keys($entity->getFieldDefinitions()), $this->getEditedFieldNames($form_state)));
|
||||
// Remove violations of inaccessible fields.
|
||||
$violations->filterByFieldAccess($this->currentUser());
|
||||
|
||||
// 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);
|
||||
|
||||
|
|
|
@ -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