Problem/Motivation
When an empty field value goes in, the normalizer can not fetch a valid date instance and then fails calling methods on it, resulting in the following exception:
The website encountered an unexpected error. Please try again later.
Error: Call to a member function setTimezone() on null in Drupal\jsonapi\ForwardCompatibility\Normalizer\DateTimeNormalizer->normalize() (line 49 of modules/contrib/jsonapi/src/ForwardCompatibility/Normalizer/DateTimeNormalizer.php).
Drupal\jsonapi\ForwardCompatibility\Normalizer\DateTimeNormalizer->normalize(Object, 'api_json', Array) (Line: 42)
Drupal\jsonapi\ForwardCompatibility\Normalizer\DateTimeIso8601Normalizer->normalize(Object, 'api_json', Array) (Line: 143)
Symfony\Component\Serializer\Serializer->normalize(Object, 'api_json', Array) (Line: 61)
Drupal\jsonapi\Serializer\Serializer->normalize(Object, 'api_json', Array) (Line: 118)
Drupal\jsonapi\Normalizer\EntityReferenceFieldNormalizer->normalize(Object, 'api_json', Array) (Line: 143)
...
Proposed resolution
Add an if condition to check for that and return NULL in case we do not have data to format.
Remaining tasks
Discussion, patch etc.
User interface changes
None (maybe)
API changes
TBD.
Data model changes
TBD.
Release notes snippet
TBD.
Comments
Comment #2
ndobromirov commentedHere is a simple patch that resolved exception for me. Please review :).
Comment #3
wim leersGood find!
So this is failing on optional
@FieldType=datetimeinstances?Comment #4
ndobromirov commentedNot sure I can't recall it, as I did not bother much to look into the data issue (sorry).
Will try to find an exact reproduce scenario...
Comment #5
ndobromirov commentedFrom what I am finding this should be related to webforms.
How it's happening to trigger a date normalizer - no idea.
The data structure that gets normalized is:
1. Node type basic page.
2. paragraph reference field.
3. Paragraph type.
4. Webform reference field
Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceFieldItemList5. Some strange property -
open. That has empty string value and for some reason it was mapped toDrupal\Core\TypedData\Plugin\DataType\DateTimeIso8601and thus failing.If you need more details on this one just ping back...
Comment #6
ndobromirov commentedMore context:
- Drupal 8.6.3
- jsonapi 2.x-dev (latest)
- jsonapi_extras 3.x-dev (latest)
- webform (8.x-5.0-rc26) (maybe should try an update there is RC29...)
- webform_rest (8.x-2.0-beta1) (same here).
Comment #7
ndobromirov commentedOld patch does not apply for some reason. Here is a new (smaller one) against latest dev.
Comment #8
wim leersThat seems like a bug in Webform. Moving to their issue queue, along with an initial patch.
It also seems that validation constraints are missing from
\Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceItem, it doesn't list any constraints in its annotation. See\Drupal\file\Plugin\Field\FieldType\FileItemfor an example.Comment #10
jrockowitz commentedI am stumped because the webform entity reference open/close are optional.
The 'datetime_iso8601' datatype is seldom used is core and always required. For example, the date range field requires both start and end dates.
I feel like the patch #2 makes sense unless we always want to require a value for the 'datetime_iso8601' datatype.
Comment #11
jrockowitz commentedWith #2794481: Allow end date to be optional the range's end date would become an optional 'datetime_iso8601' datatype. I think we are going to have the same issue with daterange field.
@Wim Leers I am not sure how Webform can fix this issue. For now, I am moving this ticket back into the JSON API issue.
Comment #12
wim leers@jrockowitz: Thanks for moving it back to this issue queue! (And congrats on releasing Webform 5.0 stable! 🎉)
So I started working on test coverage. Only to find out that I cannot reproduce this using "regular" (configurable)
datetimefields. Hence I installed Webform 5.0 and added a (@FieldType=webform, which is\Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceItem). Instantly it is reproducible.It reminded me of #3014380-26: EntityReference base fields that are optional are not empty, but its sole item is empty, causing EntityReferenceFieldNormalizer to fail, but it's different.
In this case, there is a non-empty reference field, but there seems to be an empty
openproperty (which is a@DataType=datetime_iso8601instance). Turns out it's not empty: it's got''(the empty string) as its value.This is why it's impossible to reproduce this with an optional
datetimefield (either base or configurable): because then they're considered empty. This can only be reproduced with an optionaldatetime_iso8601property on a non-empty field.. In the case of\Drupal\webform\Plugin\Field\FieldType\WebformEntityReferenceItem, thetarget_idproperty is not empty (because it's required), theopenandclosedproperties on that same field item are optional.Comment #13
wim leersBecause of the need for a custom field type to reproduce this, I think writing test coverage for this is a bit excessive. Especially since this is just something that's a forward port of the #2926508: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API core issue.
Comment #14
wim leersRebased after #2999438: [upstream] Datetime field shown with wrong timezone offset landed.
Comment #15
wim leersThis is really a bug report for #2926508: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API in core. Hence marking .
This is the second bug found in that core patch thanks to JSON:API leaping ahead of core (#2999438: [upstream] Datetime field shown with wrong timezone offset was the other, which led to #3002164: DateTimeIso8601::getDateTime() does not specify the storage timezone when constructing DrupalDateTime object getting fixed in core).
Comment #16
wim leersBugfix added to the upstream patch at #2926508-149: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API, including tests. If/when that comes back green, I'm committing this.
Comment #17
wim leers#2926508-149: Add DateTimeNormalizer+TimestampNormalizer, deprecate TimestampItemNormalizer: @DataType-level normalizers are reusable by JSON:API came back green! ✅
Comment #19
wim leersComment #20
jrockowitz commented@Wim Leers The patch makes sense. Thanks for taking care of this issue.