Problem/Motivation
The EntityViewBuilder::getBuildDefaults has an $entity parameter that should respect the EntityInterface.
Yet in the getBuildDefaults() method there's a call on the $entity object to a method that's not on the EntityInterface:
$entity->isDefaultRevision();
isDefaultRevision() lives on the ContentEntityBase but EntityViewBuilder might be used by a ConfigEntityBase.
This may result in an error Error: Call to undefined method Drupal\my_module\Entity\MyConfigEntity::isDefaultRevision() in EntityViewBuilder.php on line 181
Proposed resolution
We should check if the entity is an instance of RevisionableInterface first:
$entity instanceof RevisionableInterface
| Comment | File | Size | Author |
|---|---|---|---|
| #15 | 2951487_15_no-tests.patch | 915 bytes | Jaesin |
Issue fork drupal-2951487
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
mpp commentedAdded a check for the RevisionableInterface and also fixed some coding standards.
Comment #3
filsterjisah commentedI wonder why the defaults should only set the cache keys when rendering a revisional entity? Since there is no revision id being set.
Comment #4
berdirWe already have other issues, the fact is that EntityViewBuilder really is ContentEntityViewBuilder, nothing in there really works for config entities and needs to be completely overridden anyway, see BlockViewBuilder as an example in core.
Comment #5
mpp commented@filsterjisah perhaps this makes more sense:
@berdir, so we need to refactor everything to ContentEntityViewBuilder and change the arguments interface to ContentEntityInterface?
Ideally we'd have a static code analysis tool which checks if interfaces are respected but it would seem useful to have this patch to check for the interface anyhow?
There are similar cases in that class:
$entity instanceof TranslatableInterface
$entity instanceof FieldableEntityInterface
Comment #6
borisson_I'm not sure if that makes this issue irrelevant (closed duplicate) or not. I think this is a good improvement for the current situation.
Comment #7
berdirI'm also not sure. I guess in the example here, it worked because buildMultiple() was then overridden but not view, unlike BlockViewBuilder?
I'd avoid refactoring everything, at least here. Maybe we should just check the interface in the default buildMultiple() implementation and throw a clear exception that the default implementation only supports fieldable/content entities? Together with this fix you can then at least get the default placeholder/render-caching logic.
I'm not a fan of multi-line if conditions, especially not if we start to further nest it. What if we add a $this->isEntityCacheable($entity) and move the isNew and revision check in there? Then it should become much more readable and we can probably keep it in a single line? (we could in theory even move all existing conditions into that method, then we can do early returns or something like that to keep it readable?
That would also allow to customize the logic, e.g. if someone wants to cache non-default revisions?
Comment #8
mpp commented@berdir, I agree that adding
$this->isEntityCacheable($entity)with early returns will be an improvement.While my suggestion won't break anything else, I'm not 100% sure that adding an exception won't break any existing config entity that extends EntityViewBuilder.
Comment #9
berdirI'm OK with not adding any exceptions here. Looking at \Drupal\Core\Entity\EntityViewBuilder::buildMultiple(), I guess it will simply do nothing now for config entities as it will never put them into $view_modes, so it will just silently do nothing.
Comment #10
mpp commentedok, thanks.
Fyi, we ran into this issue as we had a custom config entity (a Map) extending EntityViewBuilder that we're viewing on a Node as an entity reference field.
Comment #11
berdirNeeds work for adding a wrapper method to make it more readable. Also maybe this needs a test, but I guess it won't be very useful as it won't do much except no longer failing.
Comment #12
ducktape commentedAdded a wrapper method with the checks.
Comment #13
berdirThanks.
So one remaining question is #3. Why not always cache non-revisionable entities? Basically turn around the conditions, check for isNew() first, return FALSE and then check for either not revisionable or being the default revision?
We also need tests. Unsure how that would work exactly, possibly with a custom view builder on a config entity that overrides buildMultiple() and does something simple in there like returning a property?
Comment #15
Jaesin commentedAs far as I can see the view builder is just trying not to cache builds for non default revisions.
Comment #16
luismagr commentedThis patch works fine for me. I had the same problem. Thanks for the work!
Comment #18
mxr576Can't this be fixed before 8.7.0 is out? If not, is there a chance to get this merged before 8.8.0? How can I help to speed things up?
It is a bug and in my opinion, its fix is a small change, it should not break anything.
Comment #19
mxr576Comment #28
mykola dolynskyiStill facing this in Drupal 9.5.2 in context of https://www.drupal.org/project/dashboards/issues/3294986
Comment #31
kalpanajaiswal commentedCreated a MR for Drupal 11.
MR: https://git.drupalcode.org/project/drupal/-/merge_requests/8299
Branch: 2951487-check-instance-type
Comment #32
mxr576Fails on code style check
Comment #33
prabha1997 commentedWorking on code style check
Comment #34
prabha1997 commentedUpdated MR please check
https://git.drupalcode.org/project/drupal/-/merge_requests/8299
Comment #35
kalpanajaiswal commentedComment #36
smustgrave commentedWas previously tagged for tests. Did not review