summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2016-11-21 20:51:55 (GMT)
committerNathaniel Catchpole2016-11-21 20:51:55 (GMT)
commit87e10306b55a2e279778d4288d98f7c09fc4155b (patch)
tree1db0c52f1fbacd215fad560fa7c470c187ad5eda
parentb536f0e9854d273564344ff3b7d29bf4ebe75c53 (diff)
Issue #2424791 by jibran, dpi, chx, Berdir: Entity query hardcodes entity_reference and entity specifier
-rw-r--r--core/lib/Drupal/Core/Entity/Query/QueryInterface.php11
-rw-r--r--core/lib/Drupal/Core/Entity/Query/Sql/Tables.php18
-rw-r--r--core/tests/Drupal/KernelTests/Core/Entity/EntityQueryRelationshipTest.php54
3 files changed, 76 insertions, 7 deletions
diff --git a/core/lib/Drupal/Core/Entity/Query/QueryInterface.php b/core/lib/Drupal/Core/Entity/Query/QueryInterface.php
index 630d176..9c05dfa 100644
--- a/core/lib/Drupal/Core/Entity/Query/QueryInterface.php
+++ b/core/lib/Drupal/Core/Entity/Query/QueryInterface.php
@@ -35,13 +35,18 @@ interface QueryInterface extends AlterableInterface {
*
* @param $field
* Name of the field being queried. It must contain a field name, optionally
- * followed by a column name. The column can be "entity" for reference
- * fields and that can be followed similarly by a field name and so on. Some
- * examples:
+ * 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
* - uid.entity.name
+ * - uid.entity:user.name
* "tags" "is the same as "tags.value" as value is the default column.
* If two or more conditions have the same field names they apply to the
* same delta within that field. In order to limit the condition to a
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
index 09cea06..e813cde 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
@@ -7,6 +7,8 @@ use Drupal\Core\Entity\EntityType;
use Drupal\Core\Entity\Query\QueryException;
use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
use Drupal\Core\Entity\Sql\TableMappingInterface;
+use Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface;
+use Drupal\Core\TypedData\DataReferenceDefinitionInterface;
/**
* Adds tables and fields to the SQL entity query.
@@ -254,10 +256,20 @@ class Tables implements TablesInterface {
$relationship_specifier = $specifiers[$key + 1];
$next_index_prefix = $relationship_specifier;
}
+ $entity_type_id = NULL;
+ // Relationship specifier can also contain the entity type ID, i.e.
+ // entity:node, entity:user or entity:taxonomy.
+ if (strpos($relationship_specifier, ':') !== FALSE) {
+ list($relationship_specifier, $entity_type_id) = explode(':', $relationship_specifier, 2);
+ }
// Check for a valid relationship.
- if (isset($propertyDefinitions[$relationship_specifier]) && $field_storage->getPropertyDefinition('entity')->getDataType() == 'entity_reference' ) {
- // If it is, use the entity type.
- $entity_type_id = $propertyDefinitions[$relationship_specifier]->getTargetDefinition()->getEntityTypeId();
+ 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);
$field_storage_definitions = $this->entityManager->getFieldStorageDefinitions($entity_type_id);
// Add the new entity base table using the table and sql column.
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryRelationshipTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryRelationshipTest.php
index 8465438..60dc13c 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryRelationshipTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryRelationshipTest.php
@@ -1,6 +1,8 @@
<?php
namespace Drupal\KernelTests\Core\Entity;
+
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Utility\Unicode;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
@@ -115,7 +117,7 @@ class EntityQueryRelationshipTest extends EntityKernelTestBase {
* Tests querying.
*/
public function testQuery() {
- // This returns the 0th entity as that's only one pointing to the 0th
+ // This returns the 0th entity as that's the only one pointing to the 0th
// account.
$this->queryResults = $this->factory->get('entity_test')
->condition("user_id.entity.name", $this->accounts[0]->getUsername())
@@ -154,6 +156,56 @@ class EntityQueryRelationshipTest extends EntityKernelTestBase {
->condition("$this->fieldName.entity.name", $this->terms[0]->name->value, '<>')
->execute();
$this->assertResults(array(1, 2));
+ // This returns the 0th entity as that's only one pointing to the 0th
+ // account.
+ $this->queryResults = $this->factory->get('entity_test')
+ ->condition("user_id.entity:user.name", $this->accounts[0]->getUsername())
+ ->execute();
+ $this->assertResults(array(0));
+ // This returns the 1st and 2nd entity as those point to the 1st account.
+ $this->queryResults = $this->factory->get('entity_test')
+ ->condition("user_id.entity:user.name", $this->accounts[0]->getUsername(), '<>')
+ ->execute();
+ $this->assertResults(array(1, 2));
+ // This returns all three entities because all of them point to an
+ // account.
+ $this->queryResults = $this->factory->get('entity_test')
+ ->exists("user_id.entity:user.name")
+ ->execute();
+ $this->assertResults(array(0, 1, 2));
+ // This returns no entities because all of them point to an account.
+ $this->queryResults = $this->factory->get('entity_test')
+ ->notExists("user_id.entity:user.name")
+ ->execute();
+ $this->assertEqual(count($this->queryResults), 0);
+ // This returns the 0th entity as that's only one pointing to the 0th
+ // term (test without specifying the field column).
+ $this->queryResults = $this->factory->get('entity_test')
+ ->condition("$this->fieldName.entity:taxonomy_term.name", $this->terms[0]->name->value)
+ ->execute();
+ $this->assertResults(array(0));
+ // This returns the 0th entity as that's only one pointing to the 0th
+ // term (test with specifying the column name).
+ $this->queryResults = $this->factory->get('entity_test')
+ ->condition("$this->fieldName.target_id.entity:taxonomy_term.name", $this->terms[0]->name->value)
+ ->execute();
+ $this->assertResults(array(0));
+ // This returns the 1st and 2nd entity as those point to the 1st term.
+ $this->queryResults = $this->factory->get('entity_test')
+ ->condition("$this->fieldName.entity:taxonomy_term.name", $this->terms[0]->name->value, '<>')
+ ->execute();
+ $this->assertResults(array(1, 2));
+ }
+
+ /**
+ * Tests the invalid specifier in the query relationship.
+ */
+ public function testInvalidSpecifier() {
+ $this->setExpectedException(PluginNotFoundException::class);
+ $this->factory
+ ->get('taxonomy_term')
+ ->condition('langcode.language.foo', 'bar')
+ ->execute();
}
/**