If a base field was overwritten in bundlefieldDefinition() just like comment, drupal core's Tables->addfield() function can't get the right target type when jsonapi filter this kind of field.

ps: because entity reference's default target type is node, so we shouldn't use node to test it.

This can be produced on comment just in core.

  1. make a comment type named "tcomment", and Target entity type set to "Taxonomy term".
  2. add a comment field to vocabulary "tags", and set Comment type to "tcomment".
  3. Add a entity_reference field to tags, set machine name as field_user and target to user.
  4. Create a tag named "foo" and create a comment for it.
  5. GET /jsonapi/comment/tcomment?include=entity_id&filter[entity_id.name][value]=foo will get error
  6. "errors": [
    {
    "title": "Internal Server Error",
    "status": 500,
    "detail": "'name' not found",
    "links": {
    "info": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1"
    },
    "code": 0,
    

Group has this problem too.
Bug reproduced process on group:

  1. Install drupal8.5.x jsonpi group
  2. Create a group type and add a group
  3. Create a group type and add a group
  4. /jsonapi/group_content/demotype-group_membership?include=entity_id&filter[entity_id.name][value]=admin
    Got error:
    "errors": [
    {
    "title": "Internal Server Error",
    "status": 500,
    "detail": "'name' not found",
    "links": {
    "info": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1"
    },
    "code": 0,
    
  5. But if I request
    /jsonapi/group_content/demotype-group_membership?include=uid&filter[uid.name][value]=admin
    I will get the right result.

    Meanwhile If I request group_node
    /jsonapi/group_content/business-group_node-device?include=entity_id&filter[entity_id.uuid][value]=4477a3ba-94b2-4a4c-96d3-8325e3d4e4e3

    I will get

    "errors": [
    {
    "title": "Internal Server Error",
    "status": 500,
    "detail": "'promotion_id' not found",
    "code": 0,
    

Comments

caseylau created an issue. See original summary.

lawxen’s picture

Issue summary: View changes
skyredwang’s picture

I was able to reproduce the first error on simplytest.me. The log shows:

Drupal\Core\Entity\Query\QueryException: 'name' not found in Drupal\Core\Entity\Query\Sql\Tables->ensureEntityTable() (line 348 of /home/d5td/www/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php).

lawxen’s picture

This can be reproduced just in core too.

  1. make a comment type named "tcomment", and Target entity type set to "Taxonomy term".
  2. add a comment field to vocabulary "tags", and set Comment type to "tcomment".
  3. Add a entity_reference field to tags, set machine name as field_user and target to user.
  4. Create a tag and create a comment for it.
  5. GET /jsonapi/comment/tcomment?include=entity_id&filter[entity_id.name][value]=big will get error
  6. "errors": [
    {
    "title": "Internal Server Error",
    "status": 500,
    "detail": "'name' not found",
    "links": {
    "info": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1"
    },
    "code": 0,
    
lawxen’s picture

Title: jsonapi filter don't work with group_content's entity_id » Filter nested relationships fails on comment's entity_id
Issue summary: View changes
Related issues: +#2920194: Inclusion of nested relationships fails for bundle-specific fields
skyredwang’s picture

Priority: Normal » Critical
e0ipso’s picture

What is entity_id in this context? It's probably something internal to the Comment implementation, but I'm not familiar with it.

skyredwang’s picture

Below is a sample output from a sandbox, `entity_id` to client side developer is just another relationship

{
    "data": [
        {
            "type": "group_content--test-group_membership",
            "id": "186644a0-7df6-4719-a3a3-dc945cddca76",
            "attributes": {
                "id": 1,
                "uuid": "186644a0-7df6-4719-a3a3-dc945cddca76",
                "langcode": "en",
                "label": "admin",
                "created": 1521112115,
                "changed": 1521112115,
                "path": {
                    "alias": null,
                    "pid": null,
                    "langcode": "en"
                },
                "default_langcode": true
            },
            "relationships": {
                "type": {
                    "data": {
                        "type": "group_content_type--group_content_type",
                        "id": "b19f252c-bbb5-4b31-b25c-823aa0867b14"
                    },
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/relationships/type",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/type"
                    }
                },
                "gid": {
                    "data": {
                        "type": "group--test",
                        "id": "23c4d3a7-f5e7-4855-9f92-e8d16112a593"
                    },
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/relationships/gid",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/gid"
                    }
                },
                "entity_id": {
                    "data": {
                        "type": "user--user",
                        "id": "99740515-d55a-40cf-a680-19e336225177"
                    },
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/relationships/entity_id",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/entity_id"
                    }
                },
                "uid": {
                    "data": {
                        "type": "user--user",
                        "id": "99740515-d55a-40cf-a680-19e336225177"
                    },
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/relationships/uid",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/uid"
                    }
                },
                "group_roles": {
                    "data": [],
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/relationships/group_roles",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76/group_roles"
                    }
                }
            },
            "links": {
                "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/186644a0-7df6-4719-a3a3-dc945cddca76"
            }
        },
        {
            "type": "group_content--test-group_membership",
            "id": "efc3c949-7218-4bb6-8826-df5d0102dc8e",
            "attributes": {
                "id": 2,
                "uuid": "efc3c949-7218-4bb6-8826-df5d0102dc8e",
                "langcode": "en",
                "label": "admin",
                "created": 1521112115,
                "changed": 1521112115,
                "path": {
                    "alias": null,
                    "pid": null,
                    "langcode": "en"
                },
                "default_langcode": true
            },
            "relationships": {
                "type": {
                    "data": {
                        "type": "group_content_type--group_content_type",
                        "id": "b19f252c-bbb5-4b31-b25c-823aa0867b14"
                    },
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/relationships/type",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/type"
                    }
                },
                "gid": {
                    "data": {
                        "type": "group--test",
                        "id": "23c4d3a7-f5e7-4855-9f92-e8d16112a593"
                    },
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/relationships/gid",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/gid"
                    }
                },
                "entity_id": {
                    "data": {
                        "type": "user--user",
                        "id": "99740515-d55a-40cf-a680-19e336225177"
                    },
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/relationships/entity_id",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/entity_id"
                    }
                },
                "uid": {
                    "data": {
                        "type": "user--user",
                        "id": "99740515-d55a-40cf-a680-19e336225177"
                    },
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/relationships/uid",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/uid"
                    }
                },
                "group_roles": {
                    "data": [],
                    "links": {
                        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/relationships/group_roles",
                        "related": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e/group_roles"
                    }
                }
            },
            "links": {
                "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership/efc3c949-7218-4bb6-8826-df5d0102dc8e"
            }
        }
    ],
    "jsonapi": {
        "version": "1.0",
        "meta": {
            "links": {
                "self": "http://jsonapi.org/format/1.0/"
            }
        }
    },
    "links": {
        "self": "http://d5td.ply.st/jsonapi/group_content/test-group_membership"
    }
}
lawxen’s picture

Issue summary: View changes

@e0ipso In the issue summary's example about comment, entity_id represent taxonomy_term--tags

This is /jsonapi/comment/tcomment?include=entity_id result:

{
  "data": [
    {
      "type": "comment--tcomment",
      "id": "26d6e393-8153-4ba4-8394-0142d71963c1",
      "attributes": {
        "cid": 1,
        "uuid": "26d6e393-8153-4ba4-8394-0142d71963c1",
        "langcode": "en",
        "status": true,
        "subject": "This is a comment test",
        "name": null,
        "mail": null,
        "homepage": null,
        "created": 1521113837,
        "changed": 1521113837,
        "thread": "01/",
        "entity_type": "taxonomy_term",
        "field_name": "field_tcomment",
        "default_langcode": true,
        "comment_body": {
          "value": "<p>This is a comment test</p>\r\n",
          "format": "basic_html",
          "processed": "<p>This is a comment test</p>"
        }
      },
      "relationships": {
        "comment_type": {
          "data": {
            "type": "comment_type--comment_type",
            "id": "55680ad9-b54f-495b-bf5c-f675a8e6b7f7"
          },
          "links": {
            "self": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1/relationships/comment_type",
            "related": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1/comment_type"
          }
        },
        "pid": {
          "data": null,
          "links": {
            "self": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1/relationships/pid",
            "related": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1/pid"
          }
        },
        "entity_id": {
          "data": {
            "type": "taxonomy_term--tags",
            "id": "e95515cb-7351-468c-8b89-d584cd7380c6"
          },
          "links": {
            "self": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1/relationships/entity_id",
            "related": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1/entity_id"
          }
        },
        "uid": {
          "data": {
            "type": "user--user",
            "id": "241f5288-4e83-4777-a4ad-d25192628faa"
          },
          "links": {
            "self": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1/relationships/uid",
            "related": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1/uid"
          }
        }
      },
      "links": {
        "self": "http://groupsba.dn8/jsonapi/comment/tcomment/26d6e393-8153-4ba4-8394-0142d71963c1"
      }
    }
  ],
  "jsonapi": {
    "version": "1.0",
    "meta": {
      "links": {
        "self": "http://jsonapi.org/format/1.0/"
      }
    }
  },
  "links": {
    "self": "http://groupsba.dn8/jsonapi/comment/tcomment?include=entity_id"
  },
  "included": [
    {
      "type": "taxonomy_term--tags",
      "id": "e95515cb-7351-468c-8b89-d584cd7380c6",
      "attributes": {
        "tid": 1,
        "uuid": "e95515cb-7351-468c-8b89-d584cd7380c6",
        "langcode": "en",
        "name": "big",
        "description": null,
        "weight": 0,
        "changed": 1521113773,
        "default_langcode": true,
        "path": {
          "alias": null,
          "pid": null,
          "langcode": "en"
        },
        "field_tcomment": {
          "status": 2,
          "cid": 1,
          "last_comment_timestamp": 1521113837,
          "last_comment_name": "",
          "last_comment_uid": 1,
          "comment_count": 1
        }
      },
      "relationships": {
        "vid": {
          "data": {
            "type": "taxonomy_vocabulary--taxonomy_vocabulary",
            "id": "bb34b1e8-d986-410d-8df7-2a068e9696e3"
          },
          "links": {
            "self": "http://groupsba.dn8/jsonapi/taxonomy_term/tags/e95515cb-7351-468c-8b89-d584cd7380c6/relationships/vid",
            "related": "http://groupsba.dn8/jsonapi/taxonomy_term/tags/e95515cb-7351-468c-8b89-d584cd7380c6/vid"
          }
        },
        "parent": {
          "data": [],
          "links": {
            "self": "http://groupsba.dn8/jsonapi/taxonomy_term/tags/e95515cb-7351-468c-8b89-d584cd7380c6/relationships/parent",
            "related": "http://groupsba.dn8/jsonapi/taxonomy_term/tags/e95515cb-7351-468c-8b89-d584cd7380c6/parent"
          }
        },
        "field_user": {
          "data": null,
          "links": {
            "self": "http://groupsba.dn8/jsonapi/taxonomy_term/tags/e95515cb-7351-468c-8b89-d584cd7380c6/relationships/field_user",
            "related": "http://groupsba.dn8/jsonapi/taxonomy_term/tags/e95515cb-7351-468c-8b89-d584cd7380c6/field_user"
          }
        }
      },
      "links": {
        "self": "http://groupsba.dn8/jsonapi/taxonomy_term/tags/e95515cb-7351-468c-8b89-d584cd7380c6"
      }
    }
  ]
}
lastlink’s picture

I'm having a similar issue w/ trying to create a comment of a comment of a comment of a node. This last comment won't create giving me a "This entity (comment: 35) cannot be referenced." error, but I can create then directly on the web and the comments above all create fine. Does jsonapi only support a depth of 2 comments types right now?

lawxen’s picture

Status: Active » Closed (duplicate)

I create another issue about config entity's filter, After several hours's investigation, I find it duplicate with this issue, I must close one and I choose close this one:)

lawxen’s picture

Status: Closed (duplicate) » Active

Jsonapi dosn't support filter nested config entity, fully described here: https://www.drupal.org/project/jsonapi/issues/2959445

This issue's root problem part same with it, But have some difference with it, so reopen it.

Detail:

/jsonapi/group_content/business-group_promotion?include=entity_id&filter[entity_id.promotion_id][value]=1

1. group_content has a base field "entity_id" and set target with group_type .

    // Borrowed this logic from the Comment module.
    // Warning! May change in the future: https://www.drupal.org/node/2346347
    // The target type is set to a config entity to force a string field
    // for the entity ID.
    // @see https://www.drupal.org/node/1757452.
    $fields['entity_id'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('Content'))
      ->setDescription(t('The entity to add to the group.'))
      ->setSetting('target_type', 'group_type')
      ->setDisplayOptions('form', [
        'type' => 'entity_reference_autocomplete',
        'weight' => 5,
        'settings' => [
          'match_operator' => 'CONTAINS',
          'size' => '60',
          'placeholder' => '',
        ],
      ])

2. each group_content bundle will override the entity_id field and set the entity_id with custom target type.

  public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
    // Borrowed this logic from the Comment module.
    // Warning! May change in the future: https://www.drupal.org/node/2346347
    if ($group_content_type = GroupContentType::load($bundle)) {
      $plugin = $group_content_type->getContentPlugin();

      /** @var \Drupal\Core\Field\BaseFieldDefinition $original */
      $original = $base_field_definitions['entity_id'];

      // Recreated the original entity_id field so that it does not contain any
      // data in its "propertyDefinitions" or "schema" properties because those
      // were set based on the base field which had no clue what bundle to serve
      // up until now. This is a bug in core because we can't simply unset those
      // two properties, see: https://www.drupal.org/node/2346329
      $fields['entity_id'] = BaseFieldDefinition::create('entity_reference')
        ->setLabel($plugin->getEntityReferenceLabel() ?: $original->getLabel())
        ->setDescription($plugin->getEntityReferenceDescription() ?: $original->getDescription())
        ->setConstraints($original->getConstraints())
        ->setDisplayOptions('view', $original->getDisplayOptions('view'))
        ->setDisplayOptions('form', $original->getDisplayOptions('form'))
        ->setDisplayConfigurable('view', $original->isDisplayConfigurable('view'))
        ->setDisplayConfigurable('form', $original->isDisplayConfigurable('form'))
        ->setRequired($original->isRequired());

      foreach ($plugin->getEntityReferenceSettings() as $name => $setting) {
        $fields['entity_id']->setSetting($name, $setting);
      }

3. The url will eventually equal to execute
$query = \Drupal::entityTypeManager()->getStorage('group_content')->getQuery();
$query->condition('entity_id.entity.promotion_id', '1','=')->execute();

4. The drupal core will

class Tables implements TablesInterface {
....
         $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id);
...
          $field_storage = $field_storage_definitions[$specifier];
....

          $propertyDefinitions = $field_storage->getPropertyDefinitions();

...
          $target_definition = $propertyDefinitions[$relationship_specifier]->getTargetDefinition();
          if (!$entity_type_id && $target_definition instanceof EntityDataDefinitionInterface) {
            $entity_type_id = $target_definition->getEntityTypeId();
          }
          $entity_type = $this->entityManager->getDefinition($entity_type_id);
          $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id);
          // Add the new entity base table using the table and sql column.

We can see the final query don't get the bundle's entity_id field, but get the original entity_type's field.

Then $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); ($entity_type_id = group_type) will get error:

"errors": [
{
"title": "Internal Server Error",
"status": 500,
"detail": "Getting the base fields is not supported for entity type Group type.",

just like Content entity query following a reference to a config entity cannot be queried ,

Even through Content entity query following a reference to a config entity cannot be queried be fixed, This issue can't be fixed. So I must reopen this issue.

lawxen’s picture

Title: Filter nested relationships fails on comment's entity_id » Can't get the right target type when jsonapi filter "bundle overwritten entity reference field
Issue summary: View changes
lawxen’s picture

Issue summary: View changes
lawxen’s picture

wim leers’s picture

Thanks for the detailed bug report, and the discussion in the comments! This has been most helpful :)

Based on the IS, this sounds related to #2958587: Unable to filter on columns of entity reference fields, which just got fixed.

But based on #13, this is a bug in \Drupal\Core\Entity\Query\Sql\Tables::addField()? Digging in more…

wim leers’s picture

wim leers’s picture

Assigned: Unassigned » wim leers
Issue summary: View changes

Reproduced with the steps to reproduce. Debugging now. Also making a slight clarification to the STR in the IS.

wim leers’s picture

wim leers’s picture

To be 100% clear: I can reproduce the failure when testing with /jsonapi/comment/tcomment?include=entity_id&filter[entity_id.name][value]=big.

I stepped through the code with a debugger. JSON API correctly expands entity_id.name to entity_id.entity.name. It's deep in the entity query system that things fail.

Now, \Drupal\Core\Entity\Query\QueryInterface::condition()'s docs say this:

   * @param $field
   *   Name of the field being queried. It must contain a field name, optionally
   *   followed by a column name. The column can be the reference property,
   *   usually "entity", for reference fields and that can be followed
   *   similarly by a field name and so on. Additionally, the target entity type
   *   can be specified by appending the ":target_entity_type_id" to "entity".
   *   Some examples:
   *   - nid
   *   - tags.value
   *   - tags
   *   - tags.entity.name
   *   - tags.entity:taxonomy_term.name

Specifically the Additionally, the target entity type can be specified by appending the ":target_entity_type_id" to "entity". caught my attention. Why do we support this? But first let's try my hunch: I added this at the top of \Drupal\Core\Entity\Query\Sql\Tables::addField():

    if ($field === 'entity_id.entity.name') {
      $field = 'entity_id.entity:taxonomy_term.name';
    }

This is equivalent to "hinting" to the entity query system what the target entity type will be. And guess what? Suddenly things worked! I'm very very much suspecting that this is caused by the two referencable entity types from tcomment being user and taxonomy_term, and both have a name field! Still, from the entity_id field on tcomment entities, only the taxonomy_term entity type can be referenced, so it shouldn't be confused by this.

Digging deeper…

wim leers’s picture

wim leers’s picture

Issue summary: View changes
StatusFileSize
new697.98 KB

The problem definitely lies in \Drupal\Core\Entity\Query\Sql\Tables::addField(), but it's extremely complex.

The first call to ::addField(), all goes well. But the second time around, $entity_type_id === 'node', which of course does not make sense; we're only dealing with comment, taxonomy_term and user here! So how could we POSSIBLY end up with node?!

Due to the recursion used this was extremely hard to pinpoint.

@caseylau already alluded to the root cause though: the $field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id); call. It returns seemingly correct data … but actually that's not the case.

So, the first call to ::addField(), all seems well. But what's crucial is that at the end of the call to ::addField(), we set up things for the second call:

      // If there are more specifiers to come, it's a relationship.
      if ($field_storage && $key < $count) {
        // Computed fields have prepared their property definition already, do
        // it for properties as well.
        if (!$propertyDefinitions) {
          $propertyDefinitions = $field_storage->getPropertyDefinitions();
…
        }
        $entity_type_id = NULL;
…
        if (isset($propertyDefinitions[$relationship_specifier]) && $propertyDefinitions[$relationship_specifier] instanceof DataReferenceDefinitionInterface) {
          // If it is, use the entity type if specified already, otherwise use
          // the definition.
          $target_definition = $propertyDefinitions[$relationship_specifier]->getTargetDefinition();
          if (!$entity_type_id && $target_definition instanceof EntityDataDefinitionInterface) {
            $entity_type_id = $target_definition->getEntityTypeId();
          }
          $entity_type = $this->entityManager->getDefinition($entity_type_id);

And this seems fine too, and actually would be fine. If it weren't for the fact that it's setting $entity_type based on data in $field_storage. And the data in $field_storage is very wrong:

So I'd love to say: "the entity query system is BROKEN! Not up to JSON API to fix this!". But … AFAICT the entity query system is designed to work at the entity type level, not the bundle level! Zero mentions of "bundle" in \Drupal\Core\Entity\Query\QueryInterface.

Basically, AFAICT, #2424791: Entity query hardcodes entity_reference and entity specifier was necessary for https://www.drupal.org/project/dynamic_entity_reference fields in general, but a bundle/configurable field (non-base field) on an entity type that is an entity reference and configures different target entity reference types is equivalent to a https://www.drupal.org/project/dynamic_entity_reference field from a querying POV!

It'd be great to have this confirmed by an Entity API/Entity Query API expert.

wim leers’s picture

Assigned: wim leers » Unassigned
Status: Active » Needs review
Issue tags: +Needs tests
Related issues: +#2064191: Fix the 'target_bundle' field setting - 'target_bundles' are not validated when entity_reference is enabled
StatusFileSize
new772 bytes

We can fix this by having JSON API automatically generate the syntax introduced by #2424791: Entity query hardcodes entity_reference and entity specifier. JSON API's FieldResolver can reliably determine the target entity type thanks to

      ->setTargetDefinition(EntityDataDefinition::create($settings['target_type']))
      // We can add a constraint for the target entity type. The list of
      // referenceable bundles is a field setting, so the corresponding
      // constraint is added dynamically in ::getConstraints().
      ->addConstraint('EntityType', $settings['target_type']);

in \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::propertyDefinitions().

(Many thanks to #2064191: Fix the 'target_bundle' field setting - 'target_bundles' are not validated when entity_reference is enabled for adding that comment. Also see #2064191-48: Fix the 'target_bundle' field setting - 'target_bundles' are not validated when entity_reference is enabled for prior complaints about bundles + Tables::addField(), which already was infamous back then.)

All of that writing and research eventually results in this … one-liner 😆 Well, tests are of course still necessary :)


@caseylau, please test this patch!

wim leers’s picture

Issue tags: +Entity query

Status: Needs review » Needs work

The last submitted patch, 24: 2953207-24.patch, failed testing. View results

lawxen’s picture

@Wim Leers
Thanks for the digging,
I test 2953207-24.patch, it works for this issue's filter。

But after apply the patch, issue: Inclusion of nested relationships fails for bundle-specific fields 's problem come back.

  1. /jsonapi/comment/forterm?include=entity_id,entity_id.field_myuser
  2. /jsonapi/group_content/business-group_product-default?entity_id,entity_id.field_product_vocabulary

include won't get the nested level result. Now that the resolution has been found, "nested include issue" can be easily fixed, Great works:).

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new7.43 KB
new8.15 KB

Updated FieldResolverTest to now expect the more specific entity query expressions!

Note that based on the expectations I had to update, I don't have confidence in my patch being 100% correct. Because only the uid.name case is getting the target entity type ID set; any filter expression that already includes entity (e.g. uid.entity.name) will NOT get it in the current patch. I think that's something best left to the person who knows FieldResolver best: @gabesullice.

Status: Needs review » Needs work

The last submitted patch, 28: 2953207-28.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new797 bytes
new8.89 KB

Down to one fail, yay! Let's get it down to zero.

wim leers’s picture

#27: that problem should be fixed by #30 — the failure in \Drupal\Tests\jsonapi\Functional\JsonApiFunctionalTest::testRead() caught that :)

#2953321: Comprehensive JSON API integration test coverage phase 5: nested includes and sparse field sets will massively expand the test coverage for this.

gabesullice’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: +API-First Initiative
StatusFileSize
new855 bytes
new8.8 KB

This looks good except for one thing, let's use the data definitions instead of the "more likely to change" constraint.

I'm happy to see that the "ambiguous" code is already going to prove more useful. Perhaps this is a real use case that we can test, rather than making our own field (as per #2971281: Test coverage: ambiguous filter expression paths)

lawxen’s picture

I have tested the latest patch, both works on nested include and filter on bundle overwritten entity reference field.

wim leers’s picture

Status: Reviewed & tested by the community » Needs review
+++ b/src/Context/FieldResolver.php
@@ -376,7 +376,9 @@
         if ($property_definition instanceof DataReferenceDefinitionInterface) {
-          $reference_property_names[] = $property_name . ':' . $property_definition->getConstraint('EntityType');
+          /* @var \Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface $target_definition */
+          $target_definition = $property_definition->getTargetDefinition();
+          $reference_property_names[] = $property_name . ':' . $target_definition->getEntityTypeId();

instanceof DataReferenceDefinitionInterface … but we're calling getEntityTypeId().

Shouldn't we do:

if ($property_definition instanceof EntityDataDefinitionInterface) {
  $reference_property_names[] = $property_names . ':' . …;
}
else {
  $reference_property_names[] = $property_names;
}

?

gabesullice’s picture

Status: Needs review » Needs work

Hm, it's kind of an impossibility given that entity references should only reference entities. So, I was sort of counting on the code to blow up if non-entity data was every encountered in the hope that we would one day be alerted to a real world example, but that's bad DX.

What do you think of throwing an exception like: "Filtering or including data in the path $path is not supported. Please report this incident in the JSON API issue queue."

gabesullice’s picture

Status: Needs work » Needs review
wim leers’s picture

StatusFileSize
new2.94 KB
new1.43 KB
new9.56 KB

That makes sense (entity references should only reference entities). I tried to do what you suggested, but didn't like the end result (see attached interdiff-nope.txt). But then I realized that this is exactly what assert() is for! What do you think of interdiff.txt?

gabesullice’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/src/Context/FieldResolver.php
@@ -376,8 +377,8 @@ class FieldResolver {
+          assert($target_definition instanceof EntityDataDefinitionInterface, 'Entity reference fields should only be able to reference entities.');

❤️

wim leers’s picture

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

Let me try to get test coverage going first :)

wim leers’s picture

Title: Can't get the right target type when jsonapi filter "bundle overwritten entity reference field » Can't get the right target type when filtering on relationship with bundle-specific target entity type
Assigned: wim leers » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new2.04 KB
new11.54 KB

The failing test is also the interdiff. Regression test coverage modeled after \Drupal\Tests\big_pipe\FunctionalJavascript\BigPipeRegressionTest(). That makes it very easy to add regression tests for complex scenarios that require particular setup.

The last submitted patch, 40: 2953207-40-tests_only_FAIL.patch, failed testing. View results

gabesullice’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/tests/src/Functional/JsonApiRegressionTest.php
@@ -0,0 +1,62 @@
+class JsonApiRegressionTest extends JsonApiFunctionalTestBase {
...
+   * @see https://www.drupal.org/node/2698811
...
+  public function testBundleSpecificTargetEntityType_2953207() {

This is a really nice pattern.

wim leers’s picture

❤️

I found some more nits that I'll fix, but that means I can get this committed today, yay!

wim leers’s picture

StatusFileSize
new1.86 KB
new11.5 KB

Fixed nits.

wim leers’s picture

Crediting the people who materially helped shape this patch.

  • Wim Leers committed d3c42f5 on 8.x-1.x
    Issue #2953207 by Wim Leers, gabesullice, caseylau, skyredwang: Can't...
  • Wim Leers committed 5be05db on 8.x-2.x
    Issue #2953207 by Wim Leers, gabesullice, caseylau, skyredwang: Can't...
wim leers’s picture

Status: Reviewed & tested by the community » Fixed

Still green, so … committed!

skyredwang’s picture

Status: Fixed » Needs work

@caseylau found a bug to this patch, he needs to supply additional test and patch to fix it.

lawxen’s picture

Issue summary: View changes
StatusFileSize
new203.4 KB
new99.49 KB
new78.86 KB
new302.78 KB
new113.78 KB

commit #46 make some complex include don't work.

    1. Install drupal8.5.x jsonapi:1.x-dev commerce commerce_product_bundle commerce_pricelist
    2. Add:
      1. Product:Apple
      2. Product Bundle:Apple Bundle
      3. Price list:Test price list
    3. Get /jsonapi/price_list/default?include=field_price_list_item,field_price_list_item.purchased_entity.uid
                          "title": "Bad Request",
                          "status": 400,
                          "detail": "Ambiguous path. Try one of the following: entity:commerce_product_bundle,
                          entity:commerce_product_variation, before the given path: uid",
                      
    4. If I cd /module/contirb/jsonapi and execute: git reset --hard f118327b86dbd0ea1a11e9f5fd678b6e3db76734
      I will get the right result.
    1. Install drupal8.5.x dynamic_entity_reference jsonapi:1.x-dev
    2. Add a dynamic_entity_reference field on node-article, name it as "field_dynamic_field"
    3. Create an article
    4. Get /jsonapi/node/article?include=field_dynamic_field,field_dynamic_field.vid

      No vid info.
    5. If I cd /module/contirb/jsonapi and execute: git reset --hard f118327b86dbd0ea1a11e9f5fd678b6e3db76734
      I will get the right result.
wim leers’s picture

Status: Needs work » Fixed

#48/#49: This was committed in #46 and released. Please create a new issue for this newly discovered problem! Otherwise it's impossible to find the discussion associated with a given commit.

  • Wim Leers committed dd790e1 on 8.x-1.x authored by gabesullice
    Issue #2973681 by caseylau, gabesullice, Wim Leers, e0ipso: Regression...
  • Wim Leers committed aa16638 on 8.x-2.x authored by gabesullice
    Issue #2973681 by caseylau, gabesullice, Wim Leers, e0ipso: Regression...

Status: Fixed » Closed (fixed)

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

wim leers’s picture

#49: I think you never got around to filing that, @caseylau? If you did, it was never referenced here.

It just happens to be that @effulgentsia asked a great question in #3040280-22: FieldResolver::resolveInternalIncludePath() does not handle resolving a single public include path to multiple internal include paths that required some issue queue digging. I ended up on this issue again and … happened to see #49. I'm 95% certain that the problem you're reporting is the same problem we just fixed in #3040280: FieldResolver::resolveInternalIncludePath() does not handle resolving a single public include path to multiple internal include paths :)

lawxen’s picture

@Wim Leers (I just change my name to KaysenLau, because there's many duplicate "caseylau" in China😀)
Yeah, I forgot to got around to filing that

I had created a new issue for #49 on
#2973681: Regression introduced by #2953207: Deep nested include on multi target entity type field fail and not point this information on this issue, my mistake.
#49 has been fixed on #2973681
Seems like it's been optimized again in #3040280: FieldResolver::resolveInternalIncludePath() does not handle resolving a single public include path to multiple internal include paths

rpayanm’s picture

Project: JSON:API » Drupal core
Version: 8.x-1.x-dev » 8.9.x-dev
Component: Code » jsonapi.module

Moving to Drupal core's issue queue.

I'm working on https://www.drupal.org/project/drupal/issues/3122113