DateTimeComputed: Fatal error when Ajax call in form. (strlen() on array)

Created on 3 October 2022, almost 3 years ago
Updated 4 February 2023, over 2 years ago

Problem/Motivation

When a form launches an AJAX call (like in the yoast_seo module), then the form_state is build by the request. (core/lib/Drupal/Core/Form/EventSubscriber/FormAjaxSubscriber.php r:103)
Therefor, the DateTime fields have their values as an array and not a string (array containing date and time elements), like in the form names: field_date[0][value][date] and field_date[0][value][time].
Result: in the DateTimeComputed.php (r:47) =>

$value = $item->{($this->definition->getSetting('date source'))};

the value is now an array, instead of a string, which on line 58 -> 251, throws an error:

TypeError: DateTime::createFromFormat(): Argument #2 ($datetime) must be of type string, array given in DateTime::createFromFormat() (line 251 of /var/app/web/core/lib/Drupal/Component/Datetime/DateTimePlus.php)

Steps to reproduce

  1. Install Drupal core with the Standard profile.
  2. Install and enable the Paragraphs module.
  3. Create a Test paragraph type with a required date field (Date type: Date only).
  4. Add an entity-reference revisions (ERR) field to the page content type, referencing the Test paragraph type (number of values: unlimited).
  5. Create a page node. Leave the date field empty. Click the "Add Test" button.

Proposed resolution

I'll share a patch in comments, but it probably can be handled better.
As we don't know which key is being handled (date/time) I just check if the value is an array, and if so just use the first element instead.
feel free to further search for a cleaner solution.

Remaining tasks

  1. Find steps to reproduce without using contributed modules.
  2. Decide on the right approach. (See the patch in Comment #2 and the one on 🐛 DateTime::createFromFormat() expects parameter 2 to be string Closed: duplicate .)
  3. Add tests.
🐛 Bug report
Status

Active

Version

9.5

Component
Datetime 

Last updated 6 days ago

Created by

🇧🇪Belgium Tim Lammar

Live updates comments and jobs are added and updated live.
  • PHP 8.1

    The issue particularly affects sites running on PHP version 8.1.0 or later.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇺🇸United States benjifisher Boston area

    I am adding steps to reproduce the bug to the issue summary. I used the steps in 🐛 DateTime::createFromFormat() expects parameter 2 to be string Closed: duplicate and #3052608-8: DateTimeComputed tries to compute from an empty value as a starting point.

    I am pretty sure that this issue and 🐛 DateTime::createFromFormat() expects parameter 2 to be string Closed: duplicate are duplicates. The other issue was created first and has a better description of how to reproduce the bug. This issue has a better explanation of what goes wrong. Each issue has a patch, and they change different parts of the process.

  • 🇨🇦Canada igorbiki

    Patch #2 works for me. Used with paragraphs in a custom block.

  • 46:07
    42:35
    Running
  • 🇫🇮Finland sonyavpaa

    Implemented patch #2 and works great with latest Paragraphs 1.17 & Drupal core 10.2.7!

  • 🇺🇸United States jldust

    Confirming that patch #2 works cleanly on Drupal 10.3.2 with Paragraphs v1.18. Does this change need tests to be updated?

  • Status changed to Needs work 12 months ago
  • Tests are expected by default. Maybe a unit test will do.

  • 🇺🇸United States jldust

    I've created a MR with the patch applied, I'm new to test writing so I'm not sure where to start for this specific issue. If there is a specific guide page I would be happy to look at it!

  • Pipeline finished with Success
    12 months ago
    Total: 623s
    #281715
  • First commit to issue fork.
  • 🇳🇱Netherlands eelkeblok Netherlands 🇳🇱

    That last commit was me. I did it through the web interface, so that's probably the reason it doesn't properly show up.

    From my limited testing, I noticed that only when the field is empty, the value will indeed be an array. I think the solution from the previous patch is than in fact not quite appropriate; it just takes one of the empty values and passes it through the test of the code. Instead, I changed it to treat it similarly to a NULL value; just bail out when it is an array.

    Still needs a test, of course :)

  • Pipeline finished with Success
    10 months ago
    Total: 610s
    #339752
  • First commit to issue fork.
  • Pipeline finished with Failed
    10 days ago
    Total: 606s
    #577848
  • Pipeline finished with Failed
    10 days ago
    Total: 194s
    #577860
  • Pipeline finished with Failed
    10 days ago
    Total: 1568s
    #577883
  • Pipeline finished with Failed
    10 days ago
    Total: 710s
    #577893
  • Pipeline finished with Canceled
    10 days ago
    Total: 69s
    #578562
  • Pipeline finished with Failed
    10 days ago
    Total: 656s
    #578563
  • 🇨🇦Canada tame4tex

    I was able to reproduce the bug in core in a FunctionalJavascript test using NestedEntityTestForm from the field_test module. That test has been pushed to the MR.

    This bug will occur when the following conditions exist:

    1. An ajax submission is triggered on a nested form that contains a datetime (or date range) field.
    2. The submitted datetime field value is invalid and fails Datetime::validateDatetime which means the formState value for the element remains as an array.
    3. The nested form calls EntityFormDisplayInterface::extractFormValues from a validate callback (e.g. NestedEntityTestForm::validateForm or ParagraphsWidget::elementValidate which results in DateTimeItem::setValue getting called and the item's values property gets set to the value array. Then when the nested form is rebuilt on ajax and DateTimeWidgetBase::formElement is called, the call to the date property on line 35 results in DateTimeComputed::getValue being called and because the value is an array, it throws an throwableerror which is not caught but the try/catch and Ajax fails.

    Based on these findings I feel the current proposed solution both here and on issue 🐛 DateTimeComputed tries to compute from an empty value Needs work , while preventing the bug, is fixing a symptom rather than the cause. I propose instead that we modify DateTimeWidgetBase::massageFormValues and DateRangeWidgetBase::massageFormValues to ensure both valid and invalid values are handled correctly to match the expectations of DateTimeComputed::getValue. If $item['value'] is not a DrupalDateTime, it did not pass validation so it is still an array, we should set it to NULL.

    I have pushed this change to the MR and updated the Issue Summary with my findings and the updated proposed resolution.

  • Pipeline finished with Success
    10 days ago
    Total: 1011s
    #578598
  • 🇯🇴Jordan Qusai Taha Amman

    Patch file to work with Drupal 10.4.7

Production build 0.71.5 2024