Problem/Motivation
We've been getting a recurring issue where users become locked out of the form to create a node with a date_recur field due to this fatal error: "InvalidArgumentException: End date must not occur before start date"
The full stack trace is this:
"The website encountered an unexpected error. Try again later.
InvalidArgumentException: End date must not occur before start date. in Drupal\date_recur\DateRange->validateDates() (line 114 of modules/contrib/date_recur/src/DateRange.php).
Drupal\date_recur\DateRange->__construct(Object, Object) (Line: 32)
Drupal\date_recur\DateRecurNonRecurringHelper->__construct(Object, Object) (Line: 39)
Drupal\date_recur\DateRecurNonRecurringHelper::createInstance('', Object, Object) (Line: 452)
Drupal\date_recur\Plugin\Field\FieldType\DateRecurItem->getHelper() (Line: 138)
Drupal\date_recur_modular\Plugin\Field\FieldWidget\DateRecurModularWidgetBase->getRule(Object) (Line: 127)
Drupal\date_recur_modular\Plugin\Field\FieldWidget\DateRecurModularAlphaWidget->formElement(Object, 0, Array, Array, Object) (Line: 459)
Drupal\Core\Field\WidgetBase->formSingleElement(Object, 0, Array, Array, Object) (Line: 219)
Drupal\Core\Field\WidgetBase->formMultipleElements(Object, Array, Object) (Line: 120)
Drupal\Core\Field\WidgetBase->form(Object, Array, Object) (Line: 190)
Drupal\Core\Entity\Entity\EntityFormDisplay->buildForm(Object, Array, Object) (Line: 121)
Drupal\Core\Entity\ContentEntityForm->form(Array, Object) (Line: 134)
Drupal\node\NodeForm->form(Array, Object) (Line: 107)
Drupal\Core\Entity\EntityForm->buildForm(Array, Object)
call_user_func_array(Array, Array) (Line: 536)
Drupal\Core\Form\FormBuilder->retrieveForm('node_event_form', Object) (Line: 284)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 48)
Drupal\Core\Entity\EntityFormBuilder->getForm(Object, 'default', Array) (Line: 392)
Drupal\group\Entity\Controller\GroupRelationshipController->createForm(Object, 'group_node:event')
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 638)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 121)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 53)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 116)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 90)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 741)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)"
We are using date_recur in combination with group and date_recur_modular. You can see both of these are in the stack trace.
I believe the user becomes repeatedly locked out of the form by this error no matter how much they refresh the page because group uses the private tempstore to save the form state as part of a multi step form process. These rows in the key_value_expire table appear to be the culprit:
Because a row will be deleted from the key_value_expire table at most 7 days from when the row was added, this is a temporary problem for the user but still very frustrating. Unlike regular form validation they are never given a chance to correct their mistake.
Looking at \Drupal\date_recur\DateRange
it's apparent that this class is working outside of the Form API. Why is that? Why should form validation throw an exception instead of using $form_state->setErrorByName()
?
Steps to reproduce
I'm unsure exactly how to reproduce this and I suspect you won't be interested in installing other contrib modules to reproduce it. Still I think my concern about not working within Form API is valid.
Proposed resolution
Make \Drupal\date_recur\DateRange
work within the Form API.