To reproduce:
Install plain old Drupal
Install JSONAPI
Go to /jsonapi/entity_form_display/entity_form_display?filter[targetEntityType][value]=node
You will see:
The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">LogicException</em>: Getting the base fields is not supported for entity type Entity form display. in <em class="placeholder">Drupal\Core\Entity\EntityFieldManager->buildBaseFieldDefinitions()</em> (line <em class="placeholder">199</em> of <em class="placeholder">core/lib/Drupal/Core/Entity/EntityFieldManager.php</em>). <pre class="backtrace">Drupal\Core\Entity\EntityFieldManager->getBaseFieldDefinitions('entity_form_display') (Line: 304)
Drupal\Core\Entity\EntityFieldManager->getFieldDefinitions('entity_form_display', 'entity_form_display') (Line: 192)
Drupal\jsonapi\Context\FieldResolver->Drupal\jsonapi\Context\{closure}(Array, Object)
array_reduce(Array, Object, Array) (Line: 197)
Drupal\jsonapi\Context\FieldResolver->getFieldItemDefinitions(Array, 'targetEntityType') (Line: 138)
Drupal\jsonapi\Context\FieldResolver->resolveInternal('entity_form_display', 'entity_form_display', 'targetEntityType') (Line: 184)
Drupal\jsonapi\Normalizer\FilterNormalizer->expandItem('targetEntityType', Array, Array) (Line: 139)
Drupal\jsonapi\Normalizer\FilterNormalizer->expand(Array, Array) (Line: 96)
Drupal\jsonapi\Normalizer\FilterNormalizer->denormalize(Array, 'Drupal\jsonapi\Query\Filter', NULL, Array) (Line: 71)
Drupal\jsonapi\Routing\JsonApiParamEnhancer->enhance(Array, Object) (Line: 94)
Drupal\Core\Routing\LazyRouteEnhancer->enhance(Array, Object) (Line: 280)
Drupal\Core\Routing\Router->applyRouteEnhancers(Array, Object) (Line: 154)
Drupal\Core\Routing\Router->matchRequest(Object) (Line: 90)
Drupal\Core\Routing\AccessAwareRouter->matchRequest(Object) (Line: 101)
Symfony\Component\HttpKernel\EventListener\RouterListener->onKernelRequest(Object, 'kernel.request', Object) (Line: 108)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.request', Object) (Line: 129)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 40)
Drupal\jsonapi\StackMiddleware\FormatSetter->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 657)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
</pre>
The following paths work:
- /jsonapi/entity_form_display/entity_form_display
- /jsonapi/entity_form_display/entity_form_display/some-uuid
Is this expected behavior? On a different site with a slightly older version of jsonapi and core I did not see this problem.
Comments
Comment #2
dpolant commentedComment #3
e0ipsoWe had a fix 2 days ago on the
FieldResolver. Can you try to update to the latest dev? If that still fails, can you try to see if that fix is the cause of your error?Comment #4
dpolant commentedI think that commit is the cause. Revision da9b3865ca06892f40dc373ccf9c65249db63137 (the one before) is OK, but aeca73d7a50b1c85edaeeb78ea46c305ffc767eb (the one from the issue you mentioned) causes the error I posted.
Comment #5
e0ipso@dpolant thanks for the research.
Comment #6
lawxen commentedComment #7
lawxen commentedComment #8
lawxen commentedComment #9
lawxen commentedThese 6 lines code exit before commit da9b3865ca06892f40dc373ccf9c65249db63137
commit aeca73d7a50b1c85edaeeb78ea46c305ffc767eb delete them.
Comment #11
gabesullice@caseylau, good research.
Indeed, those lines would prevent this error, but it was just hiding a problem before. We could add it back in as a stop gap. But it looks like what we really need to do is not load field definitions for entities that do not implement
FieldableEntityInterface.Can't write a patch now, but we should probably have something on ResourceTypes to help determine that.
Comment #12
lawxen commentedComment #13
lawxen commented@gabesullice
Yeah, the previous #7's patch is totally wrong,
If the entity didn't implement FieldableEntityInterface, we should return $field_name directly.
#12 did this.
Comment #14
e0ipso@caseylau what's the reasoning behind:
AFAICT that would imply that those names cannot be overridden. Right?
Comment #15
lawxen commented@e0ipso
> AFAICT that would imply that those names cannot be overridden. Right?
Yes, you are right.
those names should can be overridden.
Comment #16
gabesullice@e0ipso, I think @caseylau was following my suggestion from #11.
I got that idea from this code, where the exception in the IS originated.
My suggestions should be taken with a grain of salt, it's all from research done from my phone :P
This code needs a comment explaining that reasoning (if we solve it with this fix), tests, and we should move the interface checking into
Drupal\jsonapi\ResourceType\ResourceTypeso we can avoid statically loading the EntityType.Thanks for your help with this @caseylau!
Comment #17
gabesulliceI'm not sure that's true @e0ipso, why couldn't you override field names for config entities (which don't implement the interface)?It's possible I misunderstood. Gonna figure this out on Monday.
Also, @caseylau, your patch in #12 was more correct than #15. We want to check that even across nested fields or else this won't work. For example, it would break when you're filtering on the role name of an author's user entity (
uid.roles.name).Comment #18
lawxen commented@gabesullice
Thanks for your sweet review on weekend even just have
a phone:).
I have tested jsonapi/view/view?sort=display.default.position on #12 and #15's patch,
Both works well.
Going to sleep now,It's too late in China,Good night @gabesullice:):):)
Comment #19
gabesulliceHere's a test-only patch which replicates the issue.
Comment #20
gabesulliceIn the last test only patch, I had the order of the expected and input values backwards.
I've attached a patch that includes #15 to illustrate my remarks in #17 about nested field paths. I.e. the first new test should pass, but the second one should fail on
type.uuidbecause the "gate" code isn't run for the second$part("uuid") because we're already in thewhileloop.I say #12 is "more correct" because it will be run even for nested paths. However, it will still be broken because the
$entity_type_idvariable will not have been updated to the nested resource type. I.e. it will still be using the id from the first part of the path, not the referenced entity type.Comment #21
wim leersSomething is off about #20's combined patch:
Comment #22
gabesulliceAlright, let's see what everyone thinks of something like this...
I tried to keep the abstraction of resource types involved, rather than loading the entity type definition directly. This might be wasted effort though, considering that we're relying on entity field definitions later in the code.
Comment #24
gabesulliceWTH? Trying this again.
The number of places I had to change tests is really making me doubt the ResourceType change.
Comment #26
wim leersSo this is the key thing that this is adding, just to allow
This refactoring is exactly what I wanted to suggest in #2920194: Inclusion of nested relationships fails for bundle-specific fields but eventually didn't.
Needless to say, ❤️ :)
If you'd split this off to a separate issue/patch, I'd commit this immediately.
Entities have storage decoupled from SQL. Config entities can also be stored in various storage back ends.
So I think this comment is incorrect.
What is correct, is to say that config entities are never able to express relationships.
… however … it is theoretically possible to expose config dependencies as relationships to other config entities. Maybe we'll want to add that in the future. What then?
FieldResolver, but to instead enrichResourceTypewith additional metadata. But then we need to make sure that this metadata remains valuable in the foreseeable future. In this case, I'm not entirely certain (see my previous review point).It feels that the "real" solution here is to lift
\Drupal\Core\Entity\EntityInterface::referencedEntities()into an interface of its own, and then haveConfigEntityBaseNOT implement that anymore (right now it hardcodesreturn []…). But that is a pipe dream, because that requires a significant BC break.Thoughts?
Comment #27
gabesulliceYeah, I think you're picking up on a lot of the same uneasiness I had about this change (see #22 and #24). So, given your valid concerns and the fact that in
FieldResolver"we're relying on entity field definitions" already. Let's just hardcode it into FieldResolver and address the rest of that class's shortcomings later and fix this regression with minimal changes.Comment #28
wim leers+1
I think your patch was a worthwhile effort though: it explored a solution that was likely going to end up cleaner. The reason it doesn't quite work is that the root cause lies in the incompleteness of the (Config) Entity API. Committing #24 would effectively encode that incompleteness in JSON API.
When you reroll this, please do include a comment with a
@todothat explains at a high level what we should do in the future.Comment #29
gabesulliceGreatly simplified patch.
Comment #30
wim leersYep, patch is simpler because A) no more changes to
ResourceType, B) #2935430: Refactor path expansion in FieldResolver landed the bits cited in #26.2.This is correct, but incomplete: it doesn't mention that we can't reliably implement this in
ResourceTypebecause it is due to incomplete architecture in Drupal core.Comment #31
gabesulliceOkay. Added a bit more detail. I didn't specifically point out anything about potential implementations that would allow this because there are a number of viable solutions.
An interface for the
referencedEntitiesmethod is just one piece of the puzzle. While that will tell us that an entity type might be referencing another entity, it still isn't enough to tell us if we can actually sort and filter based on the paths we're resolving.For now, sorting and filtering by the entity query system relies on SQL backed entities to sort and filter across references, but in future filtering could be done using a mix of both SQL and in-PHP processing.
Comment #32
gabesulliceSome of the "validation" we're doing here is actually somewhat related to discussions elsewhere: #2926089-12: Filter operators not working with multiple values
We're clumsily trying to make sure that the entity query system isn't going to choke on something like
?filter[roles.label]=Administrator, which it unfortunately does...Edit: I say "clumsily" because there aren't APIs that I'm aware of to actually determine this conclusively in advance.
Comment #33
gabesulliceAll issues that are similar in nature to #32.
Comment #34
wim leers#31++
#32 + #33: That's a very valuable insight! I wonder if we need a general issue to address all that?
Also, can I summarize that to: ?
In any case, #31 is RTBC.
Comment #36
gabesullices/Typed Data API/Typed Data and Entity APIs/
Comment #37
e0ipsoMerged. I forgot to tick boxes and didn't give proper attribution so I created a second commit with the missing people.