diff --git a/core/lib/Drupal/Core/Entity/Query/QueryInterface.php b/core/lib/Drupal/Core/Entity/Query/QueryInterface.php index 041a6b6..8852f0b 100644 --- a/core/lib/Drupal/Core/Entity/Query/QueryInterface.php +++ b/core/lib/Drupal/Core/Entity/Query/QueryInterface.php @@ -35,39 +35,40 @@ public function getEntityTypeId(); * @endcode * * @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: + * 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: * - nid * - tags.value * - tags * - uid.entity.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. - * It is also possible to add the numeric delta value between the field - * name and the column name. - * @code + * same delta within that field. In order to limit the condition to a + * specific item a numeric delta should be added between the field name and + * the column name. + * @code * ->condition('tags.5.value', 'news') - * @endcode + * @endcode * This will require condition to be satisfied on a specific delta of the * field. The condition above will require the 6th value of the field to - * match the provided value. - * Further, it's possible to create a condition on the delta itself by using - * '%delta'. For example, - * @code + * match the provided value. Further, it's possible to create a condition on + * the delta itself by using '%delta'. For example, + * @code * ->condition('tags.%delta', 5) - * @endcode - * will find only entities which have at least six tags. - * Finally, the condition on the delta itself accompanied with a condition - * on the value will require the value to appear in the specific delta - * range. For example, - * @code + * @endcode + * will find only entities which have at least six tags. Finally, the + * condition on the delta itself accompanied with a condition on the value + * will require the value to appear in the specific delta range. For + * example, + * @code * ->condition('tags.%delta', 0, '>')) * ->condition('tags.%delta.value', 'news')) - * @endcode - * will only find the "news" tag if it is not the first value. + * @endcode + * will only find the "news" tag if it is not the first value. It should be + * noted that conditions on specific deltas and delta ranges are only + * supported when querying content entities. * @param $value * The value for $field. In most cases, this is a scalar and it's treated as * case-insensitive. For more complex operators, it is an array. The meaning diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php index 32a257e..c8bf59d 100644 --- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php +++ b/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php @@ -119,7 +119,8 @@ public function addField($field, $type, $langcode) { if ($key < $count) { $next = $specifiers[$key + 1]; - // Is this a delta value? + // If this is a numeric specifier we're adding a condition on the + // specific delta. if (is_numeric($next)) { $delta = $next; $index_prefix .= ".$delta"; @@ -127,14 +128,15 @@ public function addField($field, $type, $langcode) { $key++; $next = $specifiers[$key + 1]; } - // Is this a delta wildcard? - elseif ($next == '%delta') { - $index_prefix .= '.%delta'; + // If this specifier is the reserved keyword "%delta" we're adding a + // condition on a delta range. + elseif ($next == TableMappingInterface::DELTA) { + $index_prefix .= TableMappingInterface::DELTA; // Do not process it again. $key++; - // If there are yet specifiers to work with then continue - // processing. If this is the last specifier then use the delta - // wildcard as column name. + // If there are more specifiers to work with then continue + // processing. If this is the last specifier then use the reserved + // keyword as a column name. if ($key < $count) { $next = $specifiers[$key + 1]; } @@ -198,8 +200,9 @@ public function addField($field, $type, $langcode) { // next one is a column of this field. if ($key < $count) { $next = $specifiers[$key + 1]; - // Is this a delta wildcard? - if ($next == '%delta') { + // If this specifier is the reserved keyword "%delta" we're adding a + // condition on a delta range. + if ($next == TableMappingInterface::DELTA) { $key++; if ($key < $count) { $next = $specifiers[$key + 1]; @@ -208,7 +211,9 @@ public function addField($field, $type, $langcode) { return 0; } } - // Is this a delta value? + // If this is a numeric specifier we're adding a condition on the + // specific delta. Since we know that this is a single value base + // field no other value than 0 makes sense. if (is_numeric($next)) { if ($next > 0) { $this->sqlQuery->condition('1 <> 1'); diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/TablesInterface.php b/core/lib/Drupal/Core/Entity/Query/Sql/TablesInterface.php index 3aea711..bd8e0de 100644 --- a/core/lib/Drupal/Core/Entity/Query/Sql/TablesInterface.php +++ b/core/lib/Drupal/Core/Entity/Query/Sql/TablesInterface.php @@ -11,10 +11,10 @@ * Adds a field to a database query. * * @param string $field - * If it doesn't contain a dot, then an entity base field name. - * If it contains a dot, then either field name dot field column or - * field name dot delta dot field column. Delta can be a numeric value or a - * %delta for any value. + * If it doesn't contain a dot, then an entity base field name. If it + * contains a dot, then either field name dot field column or field name dot + * delta dot field column. Delta can be a numeric value or a "%delta" for + * any value. * @param string $type * Join type, can either be INNER or LEFT. * @param string $langcode diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php index 5ec3057..ac55a30 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php @@ -543,7 +543,7 @@ public function testDelta() { ->execute(); $this->assertResult(3, 7, 11, 15); - // Test '%delta' wildcard. + // Test the delta range condition. $this->queryResults = $this->factory->get('entity_test_mulrev') ->condition("$figures.%delta.color", array('blue', 'red'), 'IN') ->condition("$figures.%delta", array(0, 1), 'IN') @@ -552,13 +552,47 @@ public function testDelta() { // Figure delta 0 or 1 can be blue or red, this matches a lot of entities. $this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15); - // Test '%delta' wildcard without other conditions. + // Test the delta range condition without conditions on the value. $this->queryResults = $this->factory->get('entity_test_mulrev') ->condition("$figures.%delta", 1) ->sort('id') ->execute(); // Entity needs to have atleast two figures. $this->assertResult(3, 7, 11, 15); + + // Numeric delta on single value base field should return results only if + // the first item is being targeted. + $this->queryResults = $this->factory->get('entity_test_mulrev') + ->condition("id.0.value", array(1,3,5), 'IN') + ->sort('id') + ->execute(); + $this->assertResult(1, 3, 5); + $this->queryResults = $this->factory->get('entity_test_mulrev') + ->condition("id.1.value", array(1,3,5), 'IN') + ->sort('id') + ->execute(); + $this->assertResult(); + + // Delta range condition on single value base field should return results + // only if just the field value is targeted. + $this->queryResults = $this->factory->get('entity_test_mulrev') + ->condition("id.%delta.value", array(1,3,5), 'IN') + ->sort('id') + ->execute(); + $this->assertResult(1, 3, 5); + $this->queryResults = $this->factory->get('entity_test_mulrev') + ->condition("id.%delta.value", array(1,3,5), 'IN') + ->condition("id.%delta", 0, '=') + ->sort('id') + ->execute(); + $this->assertResult(1, 3, 5); + $this->queryResults = $this->factory->get('entity_test_mulrev') + ->condition("id.%delta.value", array(1,3,5), 'IN') + ->condition("id.%delta", 1, '=') + ->sort('id') + ->execute(); + $this->assertResult(); + } protected function assertResult() {