Problem/Motivation

If a datetime field is invalid, the error message is too generic. It is unclear what field is incorrect, especially if there are multiple datetime fields on the entity (color alone is not sufficient).

This is a bug because

  • Incorrect or misleading user interface text

and would qualify for an 8.1.x minor release.

Proposed resolution

Update error message for invalid datetime fields to include the field label.

Remaining tasks

Add test coverage for date-only fields.

User interface changes

Better error messages for invalid datetime fields.

API changes

None.

Data model changes

None.

Original Report

The validation handler for datelist \Drupal\Core\Datetime\Element\Datelist::validateDatelist form element has wrong error messages.

$form_state->setError($element, t('The %field date is required.'));

and

$form_state->setError($element, t('The %field date is invalid.'));

CommentFileSizeAuthor
#60 interdiff.txt1.88 KBpfrenssen
#60 2486019-60.patch15.87 KBpfrenssen
#59 interdiff.txt7.64 KBpfrenssen
#59 2486019-59.patch14.34 KBpfrenssen
#55 interdiff.txt7.38 KBpfrenssen
#55 2486019-55.patch8.11 KBpfrenssen
#48 interdiff-46-48.txt687 bytesmpdonadio
#48 2486019-48.patch4.7 KBmpdonadio
#46 interdiff-42-46.txt4.86 KBmpdonadio
#46 2486019-46.patch4.78 KBmpdonadio
#42 2486019-42.patch875 bytesmichielnugter
#42 interdiff-35-40.txt0 bytesmichielnugter
#40 2486019-40.patch538.64 KBmichielnugter
#40 interdiff-35-40.txt503.14 KBmichielnugter
#37 2486019-35.patch5.58 KBmian3010
#34 2486019-34.patch5.56 KBjofitz
#32 2486019-32.patch1.12 KBmiax
#28 interdiff-25-28.txt3.12 KBmpdonadio
#28 2486019-28.patch5.58 KBmpdonadio
#25 2486019-25.patch8.7 KBmpdonadio
#14 2486019-test-only.patch4.72 KBmpdonadio
#12 2486019-12.patch8.64 KBwebflo
#10 DateTimeFieldTest-2486019-10.patch4.4 KBhauruck
#9 2486019-9.patch3.92 KBwebflo
#8 2486019-8.patch3.41 KBwebflo
#6 datelist-validatedatelist-messages-1.patch1.42 KBmaris.abols
#4 Screen Shot 2015-05-09 at 17.08.07.png169.42 KBiMiksu
datelist-validatedatelist-messages.patch1.27 KBAnonymous (not verified)
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Anonymous’s picture

Issue summary: View changes

Status: Needs review » Needs work

The last submitted patch, datelist-validatedatelist-messages.patch, failed testing.

iMiksu’s picture

Assigned: Unassigned » iMiksu
iMiksu’s picture

Assigned: iMiksu » Unassigned
FileSize
169.42 KB

Before this patch, the test of creating datetime field entity was passing nicely.

After this patch, Drupal is throwing an error (in \Drupal\datetime\Tests\DateTimeFieldTest::testDatelistWidget()) when testing creating an entity with datetime values:

This value should be of the correct primitive type.

Screenshot of the output given on failure:
Screenshot of the error

maris.abols’s picture

Assigned: Unassigned » maris.abols
maris.abols’s picture

Previous patch returned multiple errors instead of just one. I created this patch and ran tests for DateTimeFieldTest and everything seems to be ok.

maris.abols’s picture

Assigned: maris.abols » Unassigned
Status: Needs work » Needs review
webflo’s picture

I think the bug is in the datetime widget itself, because the "Authored on" form element on the node form works fine without any errors.

webflo’s picture

FileSize
3.92 KB
hauruck’s picture

The test for TimeDateField has been update to include the missing field name. Current test skips over the first part of the error message to ignore this core bug.

Status: Needs review » Needs work

The last submitted patch, 10: DateTimeFieldTest-2486019-10.patch, failed testing.

webflo’s picture

Status: Needs work » Needs review
FileSize
8.64 KB
mpdonadio’s picture

Component: forms system » datetime.module

Reassigning this to datetime.module as it looks like a bug with it. This may be related to a patch where some of the logic where the widget changed, but I need to dig to find the issue.

mpdonadio’s picture

Just stripping out the test changes to make sure the changes do catch the bug.

Because of the patch this is an invalid test-only patch. Manual testing is needed to demonstrate the problem.

Status: Needs review » Needs work

The last submitted patch, 14: 2486019-test-only.patch, failed testing.

mpdonadio’s picture

Status: Needs work » Needs review

Back to NR.

Status: Needs review » Needs work

The last submitted patch, 14: 2486019-test-only.patch, failed testing.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mpdonadio’s picture

Retesting to see where this lands w/ 8.1.x. May or may not conflict with #2696353: Bad dates in Select List widget throw an exception.

The last submitted patch, 14: 2486019-test-only.patch, failed testing.

mpdonadio’s picture

Status: Needs work » Needs review

Back to NR. Will look closer at this, but

+++ b/core/modules/datetime/src/Tests/DateTimeFieldTest.php
@@ -738,7 +739,7 @@ function testInvalidField() {
-    $this->assertText('date is invalid', 'Empty date value has been caught.');
+    $this->assertText(format_string('The @field_name date is invalid', array('@field_name' => $field_label)), 'Empty date value has been caught.');
 

I think with the expected string we are testing for, we want to use t() instead of format_string(). Also elsewhere.

+++ b/core/modules/datetime/src/Tests/DateTimeFieldTest.php
@@ -746,7 +747,7 @@ function testInvalidField() {
-    $this->assertText('date is invalid', format_string('Invalid year value %date has been caught.', array('%date' => $date_value)));
+    $this->assertText(format_string('The @field_name date is invalid', array('@field_name' => $field_label)), format_string('Invalid year value %date has been caught.', array('%date' => $date_value)));

I think the format_string() in the messages is overkill. We can just say ''Invalid year failed validation.' or similar. Also elsewhere.

mpdonadio’s picture

Issue summary: View changes
Status: Needs review » Needs work
Issue tags: +Needs tests
+++ b/core/modules/datetime/src/Tests/DateTimeFieldTest.php
@@ -738,7 +739,7 @@ function testInvalidField() {
-    $this->assertText('date is invalid', 'Empty date value has been caught.');
+    $this->assertText(format_string('The @field_name date is invalid', array('@field_name' => $field_label)), 'Empty date value has been caught.');

The expected strings should use t() and not format_string(). That is the general convention in tests. This happens several times in the patch.

While we are at it, we should update DateTimeFieldTest::testInvalidField() to check for the updated error message on date-only fields to prevent regressions.

This one is a little hard to test. Using FF and disabling Javascript to prevent the datepicker polyfill is the best way to manually tests this.

mpdonadio’s picture

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mpdonadio’s picture

Status: Needs work » Needs review
FileSize
8.7 KB

Re-roll against 8.2.x.

jhedstrom’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/core/lib/Drupal/Core/Datetime/Element/Datelist.php
@@ -311,7 +311,7 @@ public static function validateDatelist(&$element, FormStateInterface $form_stat
-        $form_state->setError($element, t('The %field date is required.'));

Wow, that's a pretty big oversight indeed!

Fix looks good to go.

I agree this is a bug and should be considered for a minor release of 8.2.x.

xjm’s picture

Version: 8.2.x-dev » 8.3.x-dev
Status: Reviewed & tested by the community » Needs work

Thanks all!

+++ b/core/modules/datetime/src/Tests/DateTimeFieldTest.php
@@ -736,7 +737,7 @@ function testInvalidField() {
-    $this->assertText('date is invalid', format_string('Invalid hour value %time has been caught.', array('%time' => $time_value)));
+    $this->assertText(format_string('The @field_name date is invalid', array('@field_name' => $field_label)), format_string('Invalid hour value %time has been caught.', array('%time' => $time_value)));

Instead of using the deprecated format_string(), we can just concatenate strings inline, since this is an assertion. See #2549805: Remove all usage of FormattableMarkup in tests apart from explicit tests of that API. (Also, a separate message assertion parameter is usually not useful with assertText() anyway since it is redundant and obscures the actual validation message, but that's not introduced here.)

+++ b/core/includes/theme.inc
@@ -568,9 +568,11 @@ function template_preprocess_datetime_form(&$variables) {
+  $element['#title_display'] = isset($element['#title_display']) ? $element['#title_display'] : 'before';
 
   if (!empty($element['#title'])) {
     $variables['title'] = $element['#title'];
+    $variables['title_display'] = $element['#title_display'];

+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
@@ -23,7 +23,6 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
-    $element['#theme_wrappers'][] = 'datetime_wrapper';

@@ -32,6 +31,8 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
+      '#title' => $element['#title'],
+      '#title_display' => 'invisible',

Are these bits a required part of the fix?

mpdonadio’s picture

This backs out the theme changes; the test changes are not in this.

Pretty sure it will fail b/c

+++ b/core/lib/Drupal/Core/Datetime/Element/Datelist.php
@@ -311,7 +311,7 @@ public static function validateDatelist(&$element, FormStateInterface $form_stat
-        $form_state->setError($element, t('The %field date is required.'));
+        $form_state->setError($element, t('The %field date is required.', array('%field' => !empty($element['#title']) ? $element['#title'] : '')));

However,

+++ b/core/modules/datetime/src/Plugin/Field/FieldWidget/DateTimeWidgetBase.php
@@ -23,7 +23,6 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
-    $element['#theme_wrappers'][] = 'datetime_wrapper';
     $element['#attributes']['class'][] = 'container-inline';

entangles this with #2788359: datetime_wrapper improperly applied to DateTimeWidgetBase and/or #1918994: Improve Datetime and Daterange Widget accessibility. I think we may want to postpone on the first of those.

Status: Needs review » Needs work

The last submitted patch, 28: 2486019-28.patch, failed testing.

mpdonadio’s picture

Status: Needs work » Postponed

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

miax’s picture

I needed this patch for Drupal 8.3. So i fixed the patch to work with that release.
I also added t() function to the placeholder %part in the setError message since this value was never translated to another language.
I know this issue is postponed but I needed this and maybe this patch will help someone =)

mpdonadio’s picture

Status: Postponed » Needs work
Issue tags: +Needs reroll

This is good to work on again, I missed it in my sweep of #2788359: datetime_wrapper improperly applied to DateTimeWidgetBase and #1918994: Improve Datetime and Daterange Widget accessibility.

The patch in #28 should be rerolled, as that has the tests. Then we can look at #32.

jofitz’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
FileSize
5.56 KB

Re-rolled.

Status: Needs review » Needs work

The last submitted patch, 34: 2486019-34.patch, failed testing.

mpdonadio’s picture

+++ b/core/modules/datetime/tests/src/Functional/DateTimeFieldTest.php
@@ -735,7 +736,7 @@ public function testInvalidField() {
-    $this->assertText('date is invalid', 'Empty date value has been caught.');
+    $this->assertText(format_string('The @field_name date is invalid', ['@field_name' => $field_label]), 'Empty date value has been caught.');

We can just sprintf() these since we are trying to avoid these formatting functions in tests now.

Didn't look into why we still have a fail. I suspect we also want to add test coverage to DateRangeFieldTest.

mian3010’s picture

FileSize
5.58 KB

Rerolled #28 on to make it apply in 8.3.x

Vinay15’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 37: 2486019-35.patch, failed testing.

michielnugter’s picture

Status: Needs work » Needs review
FileSize
503.14 KB
538.64 KB

The test changes were unrelated to the applied fix, I removed them and the test now passes. Test was moved to PHPUnit as well in the mean time.

I do think we need test coverage for the change to verify the label is now shown, only setting to needs review now to see if the test-bot agrees with the patch passing.

Interestingly though the element label for the invalid dates is not shown either right now, the placeholder in the HTML is empty:

The <em class="placeholder"></em> date is invalid.

Is the issue bigger or the test-case not good enough?

Status: Needs review » Needs work

The last submitted patch, 40: 2486019-40.patch, failed testing.

michielnugter’s picture

Sorry, garbage patch.

jhedstrom’s picture

Fix in #42 has lost the tests from above.

michielnugter’s picture

@jhedstrom That was on purpose as my comment stated: the test changes were unrelated because the changes tested another area. It still needs tests though but at the moment I'm too busy with the PHPUnit initiative.

mpdonadio’s picture

Assigned: Unassigned » mpdonadio

Working on this. The current fix only covers part of the problem and am adjusting the tests.

mpdonadio’s picture

Assigned: mpdonadio » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
4.78 KB
4.86 KB

Should be green. There is probably a better way to get the field name in the $element here, but I am spacing. Also not 100% sure this will interfere w/ plain FormAPI usage of this.

The path through the invalid date logic requires a form alter to get past the option validation in order to generate an invalid date via the widget. Don't think this is worth it.

jhedstrom’s picture

This looks good to me. One tiny nit:

+++ b/core/lib/Drupal/Core/Datetime/Element/Datelist.php
@@ -311,12 +312,14 @@ public static function validateDatelist(&$element, FormStateInterface $form_stat
+        //print_r($element);

Stray debugging code here.

mpdonadio’s picture

Status: Needs review » Needs work

The last submitted patch, 48: 2486019-48.patch, failed testing.

mpdonadio’s picture

Status: Needs work » Needs review

Back to NR. CI error was was from one of the know, but fairly rare, PHP segfaults.

pfrenssen’s picture

Status: Needs review » Needs work

From looking at the code it appears this uses the machine name of the field in the error message that is presented to the user. It will look something like:

The field_event_dates date is invalid.

This is confusing to end users since the text field_event_dates is not visible in the page, the actual title will be something human readable like "Event date". We should use the human readable field title if possible.

pfrenssen’s picture

Assigned: Unassigned » pfrenssen
pfrenssen’s picture

Assigned: pfrenssen » Unassigned
Status: Needs work » Reviewed & tested by the community

I looked into this but the machine name being used instead of the human readable name appears to be a separate issue that pervades the entire datetime module. The other field formatters and error messages are also affected by this. This hasn't been detected before since in DateTestBase the same name is used for both the machine name and the human readable name when the field configuration is created :(

I will make a separate issue to use the human readable name in all error messages.

This means this issue is good to go. I reviewed the code and it looks good. I wasn't entirely sure about the language used in the error message, I would have chosen "The date for the %field field is incomplete/invalid" instead of "The %field date is incomplete/invalid". But since this has been written by native English speakers my suggestion is probably worse :)

pfrenssen’s picture

pfrenssen’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
8.11 KB
7.38 KB

I had a go at #2876047: Correctly mention field labels in form validation error messages and it is actually possible to use the human readable names in this issue too without affecting the other field type, since they are in separate classes.

Fixed the patch to use the human readable field name rather than the machine name.

mpdonadio’s picture

+++ b/core/lib/Drupal/Core/Datetime/Element/Datelist.php
@@ -302,6 +302,19 @@ public static function processDatelist(&$element, FormStateInterface $form_state
+    $title = '';
+    if (!empty($element['#title'])) {
+      $title = $element['#title'];
+    }
+    else {
+      $parents = $element['#array_parents'];
+      array_pop($parents);
+      $parent_element = NestedArray::getValue($complete_form, $parents);
+      if (!empty($parent_element['#title'])) {
+        $title = $parent_element['#title'];
+      }
+    }

Sa-weet. Do we want to move this logic to DateElementBase so we can reuse it in #2876047: Correctly mention field labels in form validation error messages?

Status: Needs review » Needs work

The last submitted patch, 55: 2486019-55.patch, failed testing.

pfrenssen’s picture

Oh yeah that is a really good idea, we can create a helper function for it and reuse the code!

I see that I missed one test too, it also needs to be updated to use the $field_label = $this->field->label(); when checking the label of the fieldset.

pfrenssen’s picture

Status: Needs work » Needs review
FileSize
14.34 KB
7.64 KB
pfrenssen’s picture

One more test fix.

pfrenssen’s picture

I postponed #2876047: Correctly mention field labels in form validation error messages on this issue since so it will be able to reuse the method on DateElementBase that @mpdonadio proposed in #56.

The last submitted patch, 59: 2486019-59.patch, failed testing.

jhedstrom’s picture

Status: Needs review » Reviewed & tested by the community

I think this is good to go. Thanks!

+++ b/core/modules/datetime/tests/src/Functional/DateTestBase.php
@@ -107,6 +107,7 @@ protected function setUp() {
+    $field_label = Unicode::ucfirst(Unicode::strtolower($this->randomMachineName()));

I like the use of proper upper case style standards =)

  • catch committed fde3369 on 8.4.x
    Issue #2486019 by mpdonadio, pfrenssen, webflo, michielnugter, maris....
catch’s picture

Version: 8.4.x-dev » 8.3.x-dev

Committed fde3369 and pushed to 8.4.x. Thanks!

I'm not 100% sure on a backport to 8.3.x here. The string changes/additions are probably fine because it's explicitly fixing broken strings, and the new protected static method should also be OK, moving to RTBC against 8.3.x for now and will have a think.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 60: 2486019-60.patch, failed testing. View results

michielnugter’s picture

Status: Needs work » Reviewed & tested by the community

8.3 stil green, back to rtbc

catch’s picture

Version: 8.3.x-dev » 8.4.x-dev
Status: Reviewed & tested by the community » Fixed

Discussed about backporting this. It's a new method on a base class, so to backport to 8.3.x we'd have to inline that logic, which is a fair bit of work/thought for a backport compared to cherry-pick. Given that, moving back to 8.4.x and fixed.

Status: Fixed » Closed (fixed)

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