Problem/Motivation

When an optional relationship on a grouped view is empty, the view fails with a fatal error.

Recoverable fatal error: Argument 1 passed to Drupal\views\Plugin\views\field\Field::createEntityForGroupBy() must implement interface Drupal\Core\Entity\EntityInterface, null given, called in /core/modules/views/src/Plugin/views/field/Field.php on line 826 and defined in Drupal\views\Plugin\views\field\Field->createEntityForGroupBy() (Line 868 in /core/modules/views/src/Plugin/views/field/Field.php).

How to reproduce:

Fresh Drupal 8.1.9 installation.
Create entity reference field in basic page called "used in" to reference content, limit bundle to article.
Create a view "article_rel" showing content elements of bundle Article.
Add a relationship to field_used_in from basic page. (optional).

  1. Add a node article 1.
  2. Add a node article 2.
  3. Add a node article 3.
  4. Add a node article 4.
  5. Add a basic page 1.
  6. reference article 1 and article 2 in "used in" field
  7. Add a basic page 2.
  8. reference article 2 in "used in" field

View now shows duplicate entries for basic page 2.
Enable aggregation.
View now fails with error message from above.

Problem here is $this->getEntity() in FieldBase doesn't cover the case of optional / empty relationships. which returns nothing right now. (Returning null explicitely instead of nothing would be probably even nicer here).

That null is then passed to createEntityForGroupBy which expects an EntityInterface causing this bug.

Proposed resolution

Following the behavior for non existing fields setting the output to null would be just fine. Similar for bundles which don't provide those fields Views aggregation: Grouping a field that doesn't exist on all bundles causes an error..

Comments

Andre-B created an issue. See original summary.

Andre-B’s picture

StatusFileSize
new1.38 KB

adding patch

Andre-B’s picture

Issue summary: View changes
Andre-B’s picture

Issue summary: View changes
cilefen’s picture

Priority: Normal » Major

This is at least Major according to the standards:

Trigger a PHP error through the user interface, but only under rare circumstances or affecting only a small percentage of all users, even if there is a workaround.

Andre-B’s picture

maybe someone can help me here with the automated patch. I can't get the view to actually group the contents, the grouped view then actually should fail (at least that's the idea.).

Andre-B’s picture

Assigned: Andre-B » Unassigned
lendude’s picture

Status: Active » Closed (duplicate)

This sounds like a duplicate of at least one (maybe all) of these :

#2731433: Fatal error when using group by on views
#2715483: [regression] getEntity() doesn't always return entity, which results in add comment field not working in Views
#2319005: Notice: Undefined index: [field name] is thrown if relationship entities are missing
#2457999: Cannot use relationship for rendered entity on Views

d.o seems to have issues with me downloading the patch here at the moment, so can't check if the fix overlaps with any of the fixes proposed in those issues.
@Andre-B sounds like you might be in a good position to look at the existing fixes and maybe consolidate all the efforts into one issue? If we have 5 issues open for it, it sounds like something that people run into with some frequency.

dawehner’s picture

StatusFileSize
new8.15 KB
new3.22 KB

@lendude+++++++

Thank you for working on this quite tough problem space. Groupby, especially in the context of the generic field handler is always challenging.
I think your setup is a little bit borked.

You group by both name and field_data_test_unlimited and the same time, which results in effectively no grouping. Maybe you want to group just by the second field?
The attached patch just fixes some minor bits.

Andre-B’s picture

@Lendude: I already looked at the issues mentioned. They are similar but I can not really tell wether they are all caused by the same issue (and if my patch would cover all of them).

#2715483: [regression] getEntity() doesn't always return entity, which results in add comment field not working in Views
#2319005: Notice: Undefined index: [field name] is thrown if relationship entities are missing
#2457999: Cannot use relationship for rendered entity on Views

#2731433 looks like to be the same. but since the steps to reproduce exactly aren't available I opened this one here.
I can move over my findings patch etc. to #2731433: Fatal error when using group by on views or save the hassle, close #2731433 and continue here?

Andre-B’s picture

StatusFileSize
new6.21 KB
new4.4 KB

@dawehner ain't quiet at it yet. Here are the views I created locally to reproduce the bug. maybe that helps.

see view-with-group-by.txt

lendude’s picture

Status: Closed (duplicate) » Needs review

@Andre-B yeah lets open this up and maybe close #2731433: Fatal error when using group by on views, this has a fix and test proposed. Setting to needs review to see what the testbot thinks.

The last submitted patch, 6: 2799415-optional-empty-relationship-with-test.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 9: 2799415-7.patch, failed testing.

Andre-B’s picture

Status: Needs work » Needs review
StatusFileSize
new8.54 KB
new2.96 KB

I think I got it now.

lendude’s picture

Status: Needs review » Needs work

Looking good. Bit of nitpicking:

  1. +++ b/core/modules/field/tests/src/Kernel/EntityReference/Views/EntityReferenceRelationshipTest.php
    @@ -276,4 +281,50 @@ public function testDataTableRelationshipWithLongFieldName() {
    +  public function testGroupByWithEmptyRelationships() {
    

    This needs a docblock

  2. +++ b/core/modules/field/tests/src/Kernel/EntityReference/Views/EntityReferenceRelationshipTest.php
    @@ -276,4 +281,50 @@ public function testDataTableRelationshipWithLongFieldName() {
    +    $this->assertNotEmpty($view->getStyle()->getField(0, 'name_2'));
    +    $this->assertNotEmpty($view->getStyle()->getField(1, 'name_2'));
    +    $this->assertNotEmpty($view->getStyle()->getField(2, 'name_2'));
    +    $this->assertEqual('', $view->getStyle()->getField(3, 'name_2'));
    

    This could use some explanation about what we test/expect.

  3. +++ b/core/modules/views/src/Plugin/views/field/Field.php
    @@ -820,10 +820,16 @@ public function getItems(ResultRow $values) {
    +      // optional relationships do not provide an entity at all. So we can't use
    

    Needs a capital at the start and should 'do not' not be 'may not'? They can provide an entity, they just don't always do.

Also a test-only patch would be nice to show the bug in the current HEAD.

dawehner’s picture

The fix looks great for me as well!

Andre-B’s picture

StatusFileSize
new8.79 KB
new7.44 KB
new2.23 KB
Andre-B’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 18: 2799415-17-test-only.patch, failed testing.

Andre-B’s picture

Status: Needs work » Needs review
StatusFileSize
new7.44 KB

test only added against 8.1.x. @Lendude did you mean another branch for that one? - not sure if I manage to invest some time before the weekend for that.

lendude’s picture

@Andre-B test-only against 8.1.x is perfect

+++ b/core/modules/views/src/Plugin/views/field/Field.php
@@ -820,10 +820,16 @@ public function getItems(ResultRow $values) {
+      // Optional relationships may not provide an entity at all. So we can't use

If you are still in a rerolling mood, this is now over 80 characters long. But that could just be fixed on commit. Will RTBC if it all comes back green.

Nice work!

Status: Needs review » Needs work

The last submitted patch, 21: 2799415-17-test-only-1.patch, failed testing.

Andre-B’s picture

@Lendude the test only patch failed testing, the other went through just fine. So RTBC? that 80 characters could just be fixed on commit.

lendude’s picture

Status: Needs work » Reviewed & tested by the community

We got a test, we got a fix. Nice.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
  1. +++ b/core/modules/views/src/Plugin/views/field/Field.php
    @@ -820,10 +820,16 @@ public function getItems(ResultRow $values) {
    +      // Optional relationships may not provide an entity at all. So we can't use
    

    Longer than 80 chars.

  2. +++ b/core/modules/views/src/Plugin/views/field/Field.php
    @@ -820,10 +820,16 @@ public function getItems(ResultRow $values) {
    +      if (($entity = $this->getEntity($values)) && ($entity = $this->createEntityForGroupBy($entity, $values))) {
    

    Double assignment of the same variable in the same if looks a bit fragile. Also I can't see how $this->createEntityForGroupBy() can ever return a bool as its documentation claims... so the whole thing might be easier to understand if it was like this:

          // Optional relationships may not provide an entity at all. So we can't
          // use createEntityForGroupBy() for those rows.
          if ($entity = $this->getEntity($values)) { 
            $entity = $this->createEntityForGroupBy($entity, $values);
            // Some bundles might not have a specific field, in which case the faked
            // entity doesn't have it either.
            $build_list = isset($entity->{$this->definition['field_name']}) ? $entity->{$this->definition['field_name']}->view($display) : NULL;
          }
          else {
            $build_list = NULL;
          }
    
lendude’s picture

Version: 8.1.x-dev » 8.2.x-dev
Status: Needs work » Needs review
StatusFileSize
new1.09 KB
new8.79 KB
new8.81 KB

Feedback for #26 applied, looks much better indeed. Needs a separate 8.3.x patch so rolled that too.

xjm’s picture

@dawehner, @tim.plunkett, @alexpott, @cilefen, and I discussed this issue awhile back. As a fatal error that can be triggered with just the UI, this is definitely a major bug.

@tim.plunkett noted that it seems related to #2457999: Cannot use relationship for rendered entity on Views.

dawehner’s picture

+++ b/core/modules/views/src/Plugin/views/field/EntityField.php
@@ -818,10 +818,17 @@ public function getItems(ResultRow $values) {
+      else {
+        $build_list = NULL;
+      }

We could get rid of 2 lines of code when we predeclare $build_list = NULL

lendude’s picture

Status: Needs review » Closed (duplicate)

Turn out I missed one in #8, this is a duplicate of #2666166: View with not required relationship and aggregation enabled fails to execute. Work was done on both issues and that is the older issue, so moving this there.

xjm’s picture