Context
Using image captcha from http://drupal.org/project/captcha/ together with webform module.
The image captcha is embedded using the webform [captcha] field, not through captcha modules config (/admin/config/people/captcha/captcha-points). When using the captcha modules config, this bug does not show up.
To reproduce this bug, I created a webform with only an optional text field and the captcha field.
Problem
When submitting the webform either without filling out the captcha or giving a wrong answer to the captcha, two php errors are logged.
These errors happen inside Drupal\Core\Form\FormState getError() function.
public function getError(array $element) {
if ($errors = $this->getErrors()) {
$parents = [];
foreach ($element['#parents'] as $parent) {
$parents[] = $parent;
$key = implode('][', $parents);
if (isset($errors[$key])) {
return $errors[$key];
}
}
}
}
It seems the $element causing this error is the captcha_refresh element, created in Drupal\webform\Plugin\WebformElement\Captcha which seems to be missing a '#parents' index.
// Add image refresh button to captcha form element.
// @see image_captcha_after_build_process()
if ($form_state->getFormObject() instanceof WebformSubmissionForm) {
$is_image_captcha = FALSE;
if ($element['#captcha_type'] === 'image_captcha/Image') {
$is_image_captcha = TRUE;
}
elseif ($element['#captcha_type'] === 'default') {
$default_challenge = \Drupal::service('config.manager')
->getConfigFactory()
->get('captcha.settings')
->get('default_challenge');
if ($default_challenge === 'image_captcha/Image') {
$is_image_captcha = TRUE;
}
}
if ($is_image_captcha && isset($element['#captcha_info']['form_id'])) {
$form_id = $element['#captcha_info']['form_id'];
$uri = Link::fromTextAndUrl(t('Get new captcha!'),
new CoreUrl('image_captcha.refresh',
['form_id' => $form_id],
['attributes' => ['class' => ['reload-captcha']]]
)
);
$element['captcha_widgets']['captcha_refresh'] = [
'#theme' => 'image_captcha_refresh',
'#captcha_refresh_link' => $uri,
];
}
}
Stacktraces:
Warning: Invalid argument supplied for foreach() in Drupal\Core\Form\FormState->getError() (line 1117 of /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormState.php)
#0 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/includes/bootstrap.inc(600): _drupal_error_handler_real(2, 'Invalid argumen...', '/Users/vincente...', 1117, Array)
#1 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormState.php(1117): _drupal_error_handler(2, 'Invalid argumen...', '/Users/vincente...', 1117, Array)
#2 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(164): Drupal\Core\Form\FormState->getError(Array)
#3 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(124): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState), Array)
#4 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(124): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState), Array)
#5 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(124): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState), Array)
#6 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(124): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState), Array)
#7 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(26): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState))
#8 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormValidator.php(201): Drupal\Core\Form\FormErrorHandler->handleFormErrors(Array, Object(Drupal\Core\Form\FormState))
#9 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormValidator.php(119): Drupal\Core\Form\FormValidator->finalizeValidation(Array, Object(Drupal\Core\Form\FormState), 'webform_submiss...')
#10 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormBuilder.php(577): Drupal\Core\Form\FormValidator->validateForm('webform_submiss...', Array, Object(Drupal\Core\Form\FormState))
#11 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormBuilder.php(320): Drupal\Core\Form\FormBuilder->processForm('webform_submiss...', Array, Object(Drupal\Core\Form\FormState))
#12 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Entity/EntityFormBuilder.php(61): Drupal\Core\Form\FormBuilder->buildForm(Object(Drupal\webform\WebformSubmissionForm), Object(Drupal\Core\Form\FormState))
#13 /Users/vincentehl/code/hillert/drupal-test-instance/web/modules/contrib/webform/src/Entity/Webform.php(1174): Drupal\Core\Entity\EntityFormBuilder->getForm(Object(Drupal\webform\Entity\WebformSubmission), 'add')
#14 /Users/vincentehl/code/hillert/drupal-test-instance/web/modules/contrib/webform/src/Controller/WebformEntityController.php(96): Drupal\webform\Entity\Webform->getSubmissionForm()
#15 [internal function]: Drupal\webform\Controller\WebformEntityController->addForm(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\webform\Entity\Webform))
#16 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#17 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Render/Renderer.php(573): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#18 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#19 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#20 /Users/vincentehl/code/hillert/drupal-test-instance/vendor/symfony/http-kernel/HttpKernel.php(151): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#21 /Users/vincentehl/code/hillert/drupal-test-instance/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#22 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#23 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#24 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#25 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#26 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#27 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(52): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#28 /Users/vincentehl/code/hillert/drupal-test-instance/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#29 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/DrupalKernel.php(694): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#30 /Users/vincentehl/code/hillert/drupal-test-instance/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#31 {main}Notice: Undefined index: #parents in Drupal\Core\Form\FormState->getError() (line 1117 of /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormState.php)
#0 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/includes/bootstrap.inc(600): _drupal_error_handler_real(8, 'Undefined index...', '/Users/vincente...', 1117, Array)
#1 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormState.php(1117): _drupal_error_handler(8, 'Undefined index...', '/Users/vincente...', 1117, Array)
#2 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(164): Drupal\Core\Form\FormState->getError(Array)
#3 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(124): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState), Array)
#4 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(124): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState), Array)
#5 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(124): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState), Array)
#6 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(124): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState), Array)
#7 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormErrorHandler.php(26): Drupal\Core\Form\FormErrorHandler->setElementErrorsFromFormState(Array, Object(Drupal\Core\Form\FormState))
#8 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormValidator.php(201): Drupal\Core\Form\FormErrorHandler->handleFormErrors(Array, Object(Drupal\Core\Form\FormState))
#9 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormValidator.php(119): Drupal\Core\Form\FormValidator->finalizeValidation(Array, Object(Drupal\Core\Form\FormState), 'webform_submiss...')
#10 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormBuilder.php(577): Drupal\Core\Form\FormValidator->validateForm('webform_submiss...', Array, Object(Drupal\Core\Form\FormState))
#11 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Form/FormBuilder.php(320): Drupal\Core\Form\FormBuilder->processForm('webform_submiss...', Array, Object(Drupal\Core\Form\FormState))
#12 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Entity/EntityFormBuilder.php(61): Drupal\Core\Form\FormBuilder->buildForm(Object(Drupal\webform\WebformSubmissionForm), Object(Drupal\Core\Form\FormState))
#13 /Users/vincentehl/code/hillert/drupal-test-instance/web/modules/contrib/webform/src/Entity/Webform.php(1174): Drupal\Core\Entity\EntityFormBuilder->getForm(Object(Drupal\webform\Entity\WebformSubmission), 'add')
#14 /Users/vincentehl/code/hillert/drupal-test-instance/web/modules/contrib/webform/src/Controller/WebformEntityController.php(96): Drupal\webform\Entity\Webform->getSubmissionForm()
#15 [internal function]: Drupal\webform\Controller\WebformEntityController->addForm(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\webform\Entity\Webform))
#16 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#17 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/Render/Renderer.php(573): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#18 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#19 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#20 /Users/vincentehl/code/hillert/drupal-test-instance/vendor/symfony/http-kernel/HttpKernel.php(151): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#21 /Users/vincentehl/code/hillert/drupal-test-instance/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#22 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#23 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#24 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#25 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#26 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#27 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(52): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#28 /Users/vincentehl/code/hillert/drupal-test-instance/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#29 /Users/vincentehl/code/hillert/drupal-test-instance/web/core/lib/Drupal/Core/DrupalKernel.php(694): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#30 /Users/vincentehl/code/hillert/drupal-test-instance/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#31 {main}| Comment | File | Size | Author |
|---|---|---|---|
| #2 | webform.webform.issue_3116669.yml | 4.32 KB | jrockowitz |
| #2 | 3116669-2.patch | 537 bytes | jrockowitz |
Comments
Comment #2
jrockowitz commentedThe attached webform replicate the issue and the attached patch fixes the issue.
Comment #4
jrockowitz commentedI committed the patch. Please download the latest dev release to review.