Problem/Motivation

A notice is being generated from \Drupal\Core\Render\Element\Date::processDate() as a result of #1835016: Polyfill date input type:

Undefined index: type Notice Date.php 58 Drupal\Core\Render\Element\Date::processDate()

when a form element with #type == 'date' is used on its own.

Proposed resolution

Set needed default values for date element

Remaining tasks

Do it

User interface changes

None

API changes

None

Data model changes

None

Beta phase evaluation

Reference: https://www.drupal.org/core/beta-changes
Issue category Bug - it's a regression from previous Drupal 8 Beta releases
Issue priority Normal
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

TR’s picture

Category: Task » Bug report

To reproduce, create a form with this element:

    $form['adate'] = array(
      '#type' => 'date',
      '#description' => $this->t('Enter a date.'),
      '#default_value' => '',
    );

Just visit the form, no need to submit. The notice will be shown in /admin/reports/dblog.

I think this actually fits the definition of a bug report - changing category from task ...

mpdonadio’s picture

Issue summary: View changes
Issue tags: +Needs tests

This is interesting.

The problem is that we have

  public static function processDate(&$element, FormStateInterface $form_state, &$complete_form) {
    // Attach JS support for the date field, if we can determine which date
    // format should be used.
    if ($element['#attributes']['type'] == 'date' && !empty($element['#date_date_format'])) {
      $element['#attached']['library'][] = 'core/drupal.date';
      $element['#attributes']['data-drupal-date-format'] = [$element['#date_date_format']];
    }
    return $element;
  }

A date form element, on its own, is only used in core as part of a datetime element (see the comment on \Drupal\Core\Render\Element\Date::preRenderDate()). The datetime form element creates the sub elements, and wires up the #attributes. If you use the date element on its own (which is never used directly in core), then you will get this notice b/c the #attributes is probably empty.

So, the proper course of action here is how to accomplish the same thing as #1835016: Polyfill date input type w/o relying on being inside a datetime. And if this is a bug (still not 100% convinced about task vs bug here), then we need a test that demonstrates it.

@googletorp, do you recall why you added the `$element['#attributes']['type'] == 'date'` clause to the if statement above?

This isn't really part of the datetime.module proper, either. The base component may be the better home, but datetime.module is probably fine since it is all inter-related.

googletorp’s picture

#2 To answer the idea of using $element['#attributes']['type'] == 'date'

What I was thinking was that doing it this way, would be more generic and make sure that we only effect actual date elements and not other date related elements (like time). I also figured that if there were other types of elements that also would produce date elements (contrib), then this code could more easily be reused.

So generally try to match all <input type="date ..> elements not caring about how they got created.

longwave’s picture

Perhaps a duplicate of #1972660: Add tests for the new HTML5 date elements 'date', 'datetime', 'datetime-local' and 'time', as adding tests for the elements should have caught this.

mpdonadio’s picture

Status: Active » Closed (duplicate)
Related issues: +#2088383: Datetime FAPI DX

I am closing this as a dup of #2088383: Datetime FAPI DX.

TR’s picture

Status: Closed (duplicate) » Active

@mpdonadio: So you're saying that instead of fixing this regression introduced by the recent commit in #1835016: Polyfill date input type we should just ignore the PHP errors and put it off for how long? A year? Maybe we should revert #1835016: Polyfill date input type instead, since it breaks previously working code.

Regardless, I don't see this as a duplicate of an issue (#2088383: Datetime FAPI DX) that has been stagnant for 2 years and is geared towards providing functional features, rather than fixing a recently-introduced bug. By marking this as duplicate you're basically saying this isn't going to get fixed (or at least not for years) and that's not an acceptable response. Plus you've also just postponed #2088383: Datetime FAPI DX, which means that's not going to get worked on either ...

mpdonadio’s picture

@TR, I understand your frustration; the DateTime module has gone fairly untouched since its original integration, and only recently had someone step up as its maintainer. I am trying to triage the issues into ones that can actually be fixed per the beta change policy, and also outline what needs to be done to clean up the module and refactor it to get it in better shape.

I am not convinced that this really is a true regression from #1835016: Polyfill date input type, but rather a quirk in the way this module was integrated. '#type' == 'date' is not used on its own in core, only as part of a '#type' == 'datetime'. We also don't have test coverage for this element (#1972660: Add tests for the new HTML5 date elements 'date', 'datetime', 'datetime-local' and 'time').

We could attempt the attached, but if this is a bug then we really need a test to demonstrate it, too.

#2088383: Datetime FAPI DX would be to fix this mess properly, but it won't be able to be done in a non-disruptive way, hence needing to wait until 8.1.x.

Is using '#type' == 'datetime' in date-only mode not an option for you?

TR’s picture

Yes, that is what I've had to do - I changed everything to

'#type' => 'datetime,
'#date_date_element' => 'date',
'#date_time_element' => 'none',

(none of that is documented, btw - I got that from reading code).

But I really need only the date so I had to add a lot of code in my validate and submit functions to throw away the time part (can't compare two dates properly if the times are different ...). When I have to make compromises like this, I know I am going to hear shit down the road about how "Ubercart doesn't follow Drupal best practices" and the like, so I'd really rather not make compromises - I need a 'date' element and Drupal is supposed to support the 'date' element. (Google "site:drupal.org html5 date element" and you will see the many issues opened about the 'date' element and how I conclude that 'date' is claimed to be supported by Drupal.)

The larger problem is that there is ABSOLUTELY NO DOCUMENTATION on any D8 form elements. So technically I guess this isn't a bug because NONE of the expected behavior is documented. On the other hand, everyone keeps pointing me to https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!theme.api.... as the "official" word on what elements are available, and that says: "...look for classes with the RenderElement or FormElement annotation to discover what render elements are available." If I do that, I find that the #type = 'date' should work.

And that's my main frustration: I'd be perfectly fine with a clear document that said 'date' was not permitted (or documentation that didn't list 'date' at all), but there is no documentation at all on what the allowed form elements are - you have to read LOTS of issues and LOTS of code and they all imply that 'date' is valid, so that's what I've been using in D8 for a year now. Then all of a sudden it starts throwing PHP notices and there are NO CHANGE NOTICES to explain this. I have to resort to git bisect and running my tests a dozen times to pinpoint which commit broke my code, then I'm told tough beans, you shouldn't have been doing that anyway.

I know you're the maintainer, so I will respect your decision on how to handle this - mark it as duplicate if you want, etc. But I think it's wrong to put this off - if it's known to be broken it shouldn't be in 8.0. If 'date' isn't allowed, then it shouldn't be allowed at all - recognizing 'date' as a valid '#type' yet delivering broken behavior is just not something that should happen.

As far as a true regression ... my code was working for a year until #1835016: Polyfill date input type. I consider that a step backwards.

mpdonadio’s picture

Status: Active » Needs review

@TR, I'm not really going to disagree with anything you said. There is really no documentation on this, and the code isn't up to the same quality as the rest of a lot of Drupal 8. And, some people are gone from the Drupal world and nobody seems to recall why some decisions were made. And, I know this put people like you, who maintain large popular, modules in a bad spot, especially since your users will expect UC to be working the day Drupal 8.0.0 is tagged.

I volunteered a few weeks to be the maintainer b/c of working through several date related issues, and uncovering and fixing a lot of bugs along the way, and because I feel strongly about getting this module back into shape (some of which will be have to be deferred to 8.1.x b/c of API changes).

If someone wants to manually test the patch I made, we can fill out the IS and add a Beta Eval and see try to see if it can get in w/o a test as a Quick Fix. But, I think we will have to get a test done to get this committed. Calling a form builder w/ the form element described above should be enough for a test, as a Notice should trigger a fail.

BTW, I haven't looked at your code, but I think if you call `datetime_date_default_time()` on the object you get back, it will normalize the time to noon, so you should be able to compare directly. Yes, this is undocumented. Yes, I have no clue why this isn't baked into the classes themselves and still exists as a standalone procedural function. And yes, this will be figured out once I can get through the current issue queue to clear out all of the out-of-date issues and start to put together a roadmap for public comment.

Berdir’s picture

Status: Needs review » Needs work
+++ b/core/lib/Drupal/Core/Render/Element/Date.php
@@ -62,7 +62,7 @@ public function getInfo() {
     // Attach JS support for the date field, if we can determine which date
     // format should be used.
-    if ($element['#attributes']['type'] == 'date' && !empty($element['#date_date_format'])) {
+    if (!empty($element['#attributes']['type']) && $element['#attributes']['type'] == 'date' && !empty($element['#date_date_format'])) {

I think the common approach for this is to set up defaults in getInfo(), so that those default attributes and so on are always set, or set them up in process (because array defaults aren't merged).

I would expect to have this behavior as the default if I just use #type date, otherwise I won't get the polyfill?

For tests, there's just one place where any date from element is currently used and that is FormTestDisabledElementsForm. Not really the correct place to add test coverage for this I guess but it should actually be there anyway, so that might be enough ? ;)

googletorp’s picture

Status: Needs work » Needs review
FileSize
1.7 KB

Here's the test that we need to fix.

googletorp’s picture

And here is the fix, setting the default values needed, like Berdir suggested in #10.

googletorp’s picture

Issue summary: View changes

Updated issue summery and added beta evaluation.

I'm not sure if this being a regression makes it more important to fix or not, but since it's a non API changing bugfix to a regression, this should be fine to get in.

googletorp’s picture

Issue tags: -Needs tests

We have tests, so not needed anymore.

The last submitted patch, 11: fix_notice_in-2528482-11-TEST-ONLY.patch, failed testing.

mpdonadio’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

OK, we have a test that demonstrates the problem described in the IS, a patch that fixes it, and a proper IS and BE. I also manually tested this in Firefox 39 under OSX, and the parent patch still works. Thanks all.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Nice find, nice fix and nice test. Committed 9f6d914 and pushed to 8.0.x. Thanks!

  • alexpott committed 9f6d914 on 8.0.x
    Issue #2528482 by googletorp, mpdonadio, TR: Fix notice in Date::...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

imanoop’s picture

#8 is the correct one. To avoid the notice need to to define '#type' = 'datetime' and to remove the time field you can use below code.

'#date_date_element' => 'date',
'#date_time_element' => 'none',

Thanks,
Anoop Singh