Problem/Motivation
Submitting a configuration form crashes, if inline_form_errors is enabled, at least one configuration value of the form are overridden and there are invalid items in the configuration related to the form.
Steps to reproduce
- Export the current configuration.
- Add the following line to system.performance.yml of the configuration export:
invalid_conf: 12345 - Import the altered configuration.
- Add the following line to settings.php:
$config['system.performance']['css']['preprocess'] = FALSE; - Visit /admin/config/development/performance. The page should show the message that values of the form are overridden and will be saved, but will not apply.
- Save the form. There should be an error message about "invalid_conf" being an invalid key.
- Install inline_form_errors.
- Save the form at /admin/config/development/performance again. Now the site crashes with this error message:
Got error 'PHP message: Uncaught PHP Exception TypeError: "implode(): If argument #1 ($separator) is of type string, argument #2 ($array) must be of type array, null given" at .../web/core/lib/Drupal/Core/Form/FormElementHelper.php line 28',
Proposed resolution
In inline_form_errors/src/FormErrorHandler.php in displayErrorMessages() FormElementHelper::getElementByName($name, $form) is called which has this code:
public static function getElementByName($name, array $form) {
foreach (Element::children($form) as $key) {
if (implode('][', $form[$key]['#parents']) === $name) {
[...]
}
[...]
}
return [];
}
Since there is a config override, $form contains the key "config_override_status_messages", but $form['config_override_status_messages']['#parents'] does not exist.
Now, I'm not sure how to fix this. The obvious fix would be to check in FormElementHelper::getElementByName() if $form[$key]['#parents'] exists, before using it. However, if I understand correctly, there is an invariant, that $form[$key]['#parents'] should exist.
"config_override_status_messages" is inserted into the form via ConfigFormBase::checkConfigOverrides(), which is called from FormBuilder::doBuildForm() via "#after_build". "#parents" is added to elements of the form earlier, also in FormBuilder::doBuildForm(). So it seems, that doBuildForm() is never run on "config_override_status_messages" and therefore "#parents" is missing. Now, should "#parents" be added via ConfigFormBase::checkConfigOverrides() or should it be arranged somehow that doBuildForm() is run on "config_override_status_messages"?
Remaining tasks
User interface changes
None.
Introduced terminology
None.
API changes
None.
Data model changes
None.
Comments