Issue #3398974 by alexpott, Wim Leers, borisson_: Follow-up for #3382510: FormStateInterface::setErrorByName() needs not #name but a variation

merge-requests/5261/head
catch 2023-11-06 12:30:50 +00:00
parent 13883cc380
commit 97e6267a62
7 changed files with 169 additions and 14 deletions

View File

@ -137,7 +137,6 @@ abstract class ConfigFormBase extends FormBase {
if (is_string($target)) {
$target = ConfigTarget::fromString($target);
}
$target->elementName = $element['#name'];
$target->elementParents = $element['#parents'];
$map[$target->configName . ':' . $target->propertyPath] = $target;
$form_state->set(static::CONFIG_KEY_TO_FORM_ELEMENT_MAP, $map);
@ -192,7 +191,20 @@ abstract class ConfigFormBase extends FormBase {
// will not have the sequence index in it.
$property_path = rtrim($property_path, '0123456789.');
}
$form_element_name = $map["$config_name:$property_path"]->elementName;
if ($property_path === '') {
// There is a map to a non-existing config key. Try to work backwards.
$property_path = $violation->getParameters()['@key'] ?? '';
}
if (isset($map["$config_name:$property_path"])) {
$form_element_name = implode('][', $map["$config_name:$property_path"]->elementParents);
}
else {
// We cannot determine where to place the violation. The only option
// is the entire form.
$form_element_name = '';
}
$violations_per_form_element[$form_element_name][$index] = $violation;
}

View File

@ -9,18 +9,6 @@ namespace Drupal\Core\Form;
*/
final class ConfigTarget {
/**
* The name of the form element which maps to this config property.
*
* @var string
*
* @see \Drupal\Core\Form\ConfigFormBase::storeConfigKeyToFormElementMap()
*
* @internal
* This property is for internal use only.
*/
public string $elementName;
/**
* The parents of the form element which maps to this config property.
*

View File

@ -5,3 +5,9 @@ form_test.object:
bananas:
type: string
label: 'Bananas'
favorite_vegetable:
type: required_label
label: 'Favorite vegetable'
nemesis_vegetable:
type: required_label
label: 'Nemesis vegetable'

View File

@ -528,3 +528,17 @@ form_test.javascript_states_form:
_form: '\Drupal\form_test\Form\JavascriptStatesForm'
requirements:
_access: 'TRUE'
form_test.tree_config_target:
path: '/form-test/tree-config-target'
defaults:
_form: '\Drupal\form_test\Form\TreeConfigTargetForm'
requirements:
_access: 'TRUE'
form_test.incorrect_config_target:
path: '/form-test/incorrect-config-target'
defaults:
_form: '\Drupal\form_test\Form\IncorrectConfigTargetForm'
requirements:
_access: 'TRUE'

View File

@ -0,0 +1,36 @@
<?php
namespace Drupal\form_test\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
class IncorrectConfigTargetForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['form_test.object'];
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'form_test_incorrect_config_target_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['missing_key'] = [
'#type' => 'textfield',
'#title' => t('Missing key'),
'#config_target' => 'form_test.object:does_not_exist',
];
return parent::buildForm($form, $form_state);
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace Drupal\form_test\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
class TreeConfigTargetForm extends ConfigFormBase {
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return ['form_test.object'];
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'form_test_tree_config_target_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['vegetables'] = [
'#type' => 'details',
'#tree' => TRUE,
'#input' => TRUE,
'#title' => t('Vegetable preferences'),
];
$form['vegetables']['favorite'] = [
'#type' => 'textfield',
'#title' => t('Favorite'),
'#default_value' => 'Potato',
'#config_target' => 'form_test.object:favorite_vegetable',
];
$form['vegetables']['nemesis'] = [
'#type' => 'textfield',
'#title' => t('Nemesis'),
'#default_value' => 'Broccoli',
'#config_target' => 'form_test.object:nemesis_vegetable',
];
return parent::buildForm($form, $form_state);
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Drupal\Tests\system\Functional\Form;
use Drupal\Tests\BrowserTestBase;
/**
* Tests forms using #config_target.
*
* @group Form
*/
class ConfigTargetTest extends BrowserTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['form_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Tests #config_target where #tree is set to TRUE.
*/
public function testTree(): void {
$this->drupalGet('/form-test/tree-config-target');
$page = $this->getSession()->getPage();
$page->fillField('Favorite', '');
$page->pressButton('Save configuration');
$assert_session = $this->assertSession();
$assert_session->statusMessageContains('This value should not be blank.', 'error');
$assert_session->elementAttributeExists('named', ['field', 'Favorite'], 'aria-invalid');
$assert_session->elementAttributeNotExists('named', ['field', 'Nemesis'], 'aria-invalid');
}
/**
* Tests #config_target with an incorrect key.
*/
public function testIncorrectKey(): void {
$this->drupalGet('/form-test/incorrect-config-target');
$page = $this->getSession()->getPage();
$page->pressButton('Save configuration');
$assert_session = $this->assertSession();
$assert_session->statusMessageContains('\'does_not_exist\' is not a supported key.', 'error');
$assert_session->elementAttributeExists('named', ['field', 'Missing key'], 'aria-invalid');
}
}