3 namespace Drupal\KernelTests\Core\Entity;
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\entity_test\Entity\EntityTest;
7 use Drupal\entity_test\Entity\EntityTestMulRev;
8 use Drupal\field\Entity\FieldConfig;
9 use Drupal\field\Entity\FieldStorageConfig;
10 use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
11 use Drupal\language\Entity\ConfigurableLanguage;
12 use Drupal\taxonomy\Entity\Term;
13 use Drupal\taxonomy\Entity\Vocabulary;
14 use Symfony\Component\HttpFoundation\Request;
17 * Tests Entity Query functionality.
21 class EntityQueryTest extends EntityKernelTestBase {
23 use EntityReferenceTestTrait;
30 public static $modules = ['field_test', 'language'];
35 protected $queryResults;
38 * @var \Drupal\Core\Entity\Query\QueryFactory
43 * A list of bundle machine names created for this test.
50 * Field name for the greetings field.
57 * Field name for the figures field.
63 protected function setUp() {
66 $this->installEntitySchema('entity_test_mulrev');
68 $this->installConfig(['language']);
70 $figures = Unicode::strtolower($this->randomMachineName());
71 $greetings = Unicode::strtolower($this->randomMachineName());
72 foreach ([$figures => 'shape', $greetings => 'text'] as $field_name => $field_type) {
73 $field_storage = FieldStorageConfig::create([
74 'field_name' => $field_name,
75 'entity_type' => 'entity_test_mulrev',
76 'type' => $field_type,
79 $field_storage->save();
80 $field_storages[] = $field_storage;
83 for ($i = 0; $i < 2; $i++) {
84 // For the sake of tablesort, make sure the second bundle is higher than
85 // the first one. Beware: MySQL is not case sensitive.
87 $bundle = $this->randomMachineName();
88 } while ($bundles && strtolower($bundles[0]) >= strtolower($bundle));
89 entity_test_create_bundle($bundle);
90 foreach ($field_storages as $field_storage) {
92 'field_storage' => $field_storage,
98 // Each unit is a list of field name, langcode and a column-value array.
99 $units[] = [$figures, 'en', [
101 'shape' => 'triangle',
104 $units[] = [$figures, 'en', [
109 // To make it easier to test sorting, the greetings get formats according
110 // to their langcode.
111 $units[] = [$greetings, 'tr', [
112 'value' => 'merhaba',
113 'format' => 'format-tr',
116 $units[] = [$greetings, 'pl', [
118 'format' => 'format-pl',
121 // Make these languages available to the greetings field.
122 ConfigurableLanguage::createFromLangcode('tr')->save();
123 ConfigurableLanguage::createFromLangcode('pl')->save();
124 // Calculate the cartesian product of the unit array by looking at the
125 // bits of $i and add the unit at the bits that are 1. For example,
126 // decimal 13 is binary 1101 so unit 3,2 and 0 will be added to the
128 for ($i = 1; $i <= 15; $i++) {
129 $entity = EntityTestMulRev::create([
130 'type' => $bundles[$i & 1],
131 'name' => $this->randomMachineName(),
134 // Make sure the name is set for every language that we might create.
135 foreach (['tr', 'pl'] as $langcode) {
136 $entity->addTranslation($langcode)->name = $this->randomMachineName();
138 foreach (array_reverse(str_split(decbin($i))) as $key => $bit) {
140 list($field_name, $langcode, $values) = $units[$key];
141 $entity->getTranslation($langcode)->{$field_name}[] = $values;
146 $this->bundles = $bundles;
147 $this->figures = $figures;
148 $this->greetings = $greetings;
149 $this->factory = \Drupal::service('entity.query');
153 * Test basic functionality.
155 public function testEntityQuery() {
156 $greetings = $this->greetings;
157 $figures = $this->figures;
158 $this->queryResults = $this->factory->get('entity_test_mulrev')
159 ->exists($greetings, 'tr')
160 ->condition("$figures.color", 'red')
163 // As unit 0 was the red triangle and unit 2 was the turkish greeting,
164 // bit 0 and bit 2 needs to be set.
165 $this->assertResult(5, 7, 13, 15);
167 $query = $this->factory->get('entity_test_mulrev', 'OR')
168 ->exists($greetings, 'tr')
169 ->condition("$figures.color", 'red')
171 $count_query = clone $query;
172 $this->assertEqual(12, $count_query->count()->execute());
173 $this->queryResults = $query->execute();
174 // Now bit 0 (1, 3, 5, 7, 9, 11, 13, 15) or bit 2 (4, 5, 6, 7, 12, 13, 14,
175 // 15) needs to be set.
176 $this->assertResult(1, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15);
178 // Test cloning of query conditions.
179 $query = $this->factory->get('entity_test_mulrev')
180 ->condition("$figures.color", 'red')
182 $cloned_query = clone $query;
184 ->condition("$figures.shape", 'circle');
185 // Bit 0 (1, 3, 5, 7, 9, 11, 13, 15) needs to be set.
186 $this->queryResults = $query->execute();
187 $this->assertResult(1, 3, 5, 7, 9, 11, 13, 15);
188 // No red color has a circle shape.
189 $this->queryResults = $cloned_query->execute();
190 $this->assertResult();
192 $query = $this->factory->get('entity_test_mulrev');
193 $group = $query->orConditionGroup()
194 ->exists($greetings, 'tr')
195 ->condition("$figures.color", 'red');
196 $this->queryResults = $query
198 ->condition("$greetings.value", 'sie', 'STARTS_WITH')
199 ->sort('revision_id')
201 // Bit 3 and (bit 0 or 2) -- the above 8 part of the above.
202 $this->assertResult(9, 11, 12, 13, 14, 15);
204 // No figure has both the colors blue and red at the same time.
205 $this->queryResults = $this->factory->get('entity_test_mulrev')
206 ->condition("$figures.color", 'blue')
207 ->condition("$figures.color", 'red')
210 $this->assertResult();
212 // But an entity might have a red and a blue figure both.
213 $query = $this->factory->get('entity_test_mulrev');
214 $group_blue = $query->andConditionGroup()->condition("$figures.color", 'blue');
215 $group_red = $query->andConditionGroup()->condition("$figures.color", 'red');
216 $this->queryResults = $query
217 ->condition($group_blue)
218 ->condition($group_red)
219 ->sort('revision_id')
221 // Unit 0 and unit 1, so bits 0 1.
222 $this->assertResult(3, 7, 11, 15);
224 // Do the same test but with IN operator.
225 $query = $this->factory->get('entity_test_mulrev');
226 $group_blue = $query->andConditionGroup()->condition("$figures.color", ['blue'], 'IN');
227 $group_red = $query->andConditionGroup()->condition("$figures.color", ['red'], 'IN');
228 $this->queryResults = $query
229 ->condition($group_blue)
230 ->condition($group_red)
233 // Unit 0 and unit 1, so bits 0 1.
234 $this->assertResult(3, 7, 11, 15);
236 // An entity might have either red or blue figure.
237 $this->queryResults = $this->factory->get('entity_test_mulrev')
238 ->condition("$figures.color", ['blue', 'red'], 'IN')
242 $this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15);
244 $this->queryResults = $this->factory->get('entity_test_mulrev')
245 ->exists("$figures.color")
246 ->notExists("$greetings.value")
249 // Bit 0 or 1 is on but 2 and 3 are not.
250 $this->assertResult(1, 2, 3);
251 // Now update the 'merhaba' string to xsiemax which is not a meaningful
252 // word but allows us to test revisions and string operations.
253 $ids = $this->factory->get('entity_test_mulrev')
254 ->condition("$greetings.value", 'merhaba')
257 $entities = EntityTestMulRev::loadMultiple($ids);
258 $first_entity = reset($entities);
259 $old_name = $first_entity->name->value;
260 foreach ($entities as $entity) {
261 $entity->setNewRevision();
262 $entity->getTranslation('tr')->$greetings->value = 'xsiemax';
263 $entity->name->value .= 'x';
266 // We changed the entity names, so the current revision should not match.
267 $this->queryResults = $this->factory->get('entity_test_mulrev')
268 ->condition('name.value', $old_name)
270 $this->assertResult();
271 // Only if all revisions are queried, we find the old revision.
272 $this->queryResults = $this->factory->get('entity_test_mulrev')
273 ->condition('name.value', $old_name)
275 ->sort('revision_id')
277 $this->assertRevisionResult([$first_entity->id()], [$first_entity->id()]);
278 // When querying current revisions, this string is no longer found.
279 $this->queryResults = $this->factory->get('entity_test_mulrev')
280 ->condition("$greetings.value", 'merhaba')
282 $this->assertResult();
283 $this->queryResults = $this->factory->get('entity_test_mulrev')
284 ->condition("$greetings.value", 'merhaba')
286 ->sort('revision_id')
288 // The query only matches the original revisions.
289 $this->assertRevisionResult([4, 5, 6, 7, 12, 13, 14, 15], [4, 5, 6, 7, 12, 13, 14, 15]);
290 $results = $this->factory->get('entity_test_mulrev')
291 ->condition("$greetings.value", 'siema', 'CONTAINS')
294 // This matches both the original and new current revisions, multiple
295 // revisions are returned for some entities.
296 $assert = [16 => '4', 17 => '5', 18 => '6', 19 => '7', 8 => '8', 9 => '9', 10 => '10', 11 => '11', 20 => '12', 21 => '13', 22 => '14', 23 => '15'];
297 $this->assertIdentical($results, $assert);
298 $results = $this->factory->get('entity_test_mulrev')
299 ->condition("$greetings.value", 'siema', 'STARTS_WITH')
300 ->sort('revision_id')
302 // Now we only get the ones that originally were siema, entity id 8 and
304 $this->assertIdentical($results, array_slice($assert, 4, 8, TRUE));
305 $results = $this->factory->get('entity_test_mulrev')
306 ->condition("$greetings.value", 'a', 'ENDS_WITH')
307 ->sort('revision_id')
309 // It is very important that we do not get the ones which only have
310 // xsiemax despite originally they were merhaba, ie. ended with a.
311 $this->assertIdentical($results, array_slice($assert, 4, 8, TRUE));
312 $results = $this->factory->get('entity_test_mulrev')
313 ->condition("$greetings.value", 'a', 'ENDS_WITH')
316 ->sort('revision_id')
318 // Now we get everything.
319 $assert = [4 => '4', 5 => '5', 6 => '6', 7 => '7', 8 => '8', 9 => '9', 10 => '10', 11 => '11', 12 => '12', 20 => '12', 13 => '13', 21 => '13', 14 => '14', 22 => '14', 15 => '15', 23 => '15'];
320 $this->assertIdentical($results, $assert);
322 // Check that a query on the latest revisions without any condition returns
323 // the correct results.
324 $results = $this->factory->get('entity_test_mulrev')
327 ->sort('revision_id')
329 $expected = [1 => '1', 2 => '2', 3 => '3', 16 => '4', 17 => '5', 18 => '6', 19 => '7', 8 => '8', 9 => '9', 10 => '10', 11 => '11', 20 => '12', 21 => '13', 22 => '14', 23 => '15'];
330 $this->assertSame($expected, $results);
336 * Warning: this is complicated.
338 public function testSort() {
339 $greetings = $this->greetings;
340 $figures = $this->figures;
341 // Order up and down on a number.
342 $this->queryResults = $this->factory->get('entity_test_mulrev')
345 $this->assertResult(range(1, 15));
346 $this->queryResults = $this->factory->get('entity_test_mulrev')
349 $this->assertResult(range(15, 1));
350 $query = $this->factory->get('entity_test_mulrev')
351 ->sort("$figures.color")
352 ->sort("$greetings.format")
354 // As we do not have any conditions, here are the possible colors and
355 // language codes, already in order, with the first occurrence of the
356 // entity id marked with *:
388 $count_query = clone $query;
389 $this->assertEqual(15, $count_query->count()->execute());
390 $this->queryResults = $query->execute();
391 $this->assertResult(8, 12, 4, 2, 3, 10, 11, 14, 15, 6, 7, 1, 9, 13, 5);
393 // Test the pager by setting element #1 to page 2 with a page size of 4.
394 // Results will be #8-12 from above.
395 $request = Request::createFromGlobals();
396 $request->query->replace([
399 \Drupal::getContainer()->get('request_stack')->push($request);
400 $this->queryResults = $this->factory->get('entity_test_mulrev')
401 ->sort("$figures.color")
402 ->sort("$greetings.format")
406 $this->assertResult(15, 6, 7, 1);
408 // Now test the reversed order.
409 $query = $this->factory->get('entity_test_mulrev')
410 ->sort("$figures.color", 'DESC')
411 ->sort("$greetings.format", 'DESC')
412 ->sort('id', 'DESC');
413 $count_query = clone $query;
414 $this->assertEqual(15, $count_query->count()->execute());
415 $this->queryResults = $query->execute();
416 $this->assertResult(15, 13, 7, 5, 11, 9, 3, 1, 14, 6, 10, 2, 12, 4, 8);
422 public function testTableSort() {
423 // While ordering on bundles do not give us a definite order, we can still
424 // assert that all entities from one bundle are after the other as the
426 $request = Request::createFromGlobals();
427 $request->query->replace([
431 \Drupal::getContainer()->get('request_stack')->push($request);
434 'id' => ['data' => 'Id', 'specifier' => 'id'],
435 'type' => ['data' => 'Type', 'specifier' => 'type'],
438 $this->queryResults = array_values($this->factory->get('entity_test_mulrev')
441 $this->assertBundleOrder('asc');
443 $request->query->add([
446 \Drupal::getContainer()->get('request_stack')->push($request);
449 'id' => ['data' => 'Id', 'specifier' => 'id'],
450 'type' => ['data' => 'Type', 'specifier' => 'type'],
452 $this->queryResults = array_values($this->factory->get('entity_test_mulrev')
455 $this->assertBundleOrder('desc');
457 // Ordering on ID is definite, however.
458 $request->query->add([
461 \Drupal::getContainer()->get('request_stack')->push($request);
462 $this->queryResults = $this->factory->get('entity_test_mulrev')
465 $this->assertResult(range(15, 1));
469 * Test that count queries are separated across entity types.
471 public function testCount() {
472 // Create a field with the same name in a different entity type.
473 $field_name = $this->figures;
474 $field_storage = FieldStorageConfig::create([
475 'field_name' => $field_name,
476 'entity_type' => 'entity_test',
479 'translatable' => TRUE,
481 $field_storage->save();
482 $bundle = $this->randomMachineName();
483 FieldConfig::create([
484 'field_storage' => $field_storage,
488 $entity = EntityTest::create([
492 $entity->enforceIsNew();
495 // As the single entity of this type we just saved does not have a value
496 // in the color field, the result should be 0.
497 $count = $this->factory->get('entity_test')
498 ->exists("$field_name.color")
501 $this->assertFalse($count);
505 * Tests that nested condition groups work as expected.
507 public function testNestedConditionGroups() {
508 // Query for all entities of the first bundle that have either a red
509 // triangle as a figure or the Turkish greeting as a greeting.
510 $query = $this->factory->get('entity_test_mulrev');
512 $first_and = $query->andConditionGroup()
513 ->condition($this->figures . '.color', 'red')
514 ->condition($this->figures . '.shape', 'triangle');
515 $second_and = $query->andConditionGroup()
516 ->condition($this->greetings . '.value', 'merhaba')
517 ->condition($this->greetings . '.format', 'format-tr');
519 $or = $query->orConditionGroup()
520 ->condition($first_and)
521 ->condition($second_and);
523 $this->queryResults = $query
525 ->condition('type', reset($this->bundles))
529 $this->assertResult(6, 14);
533 * Test queries with delta conditions.
535 public function testDelta() {
536 $figures = $this->figures;
537 // Test numeric delta value in field condition.
538 $this->queryResults = $this->factory->get('entity_test_mulrev')
539 ->condition("$figures.0.color", 'red')
542 // As unit 0 at delta 0 was the red triangle bit 0 needs to be set.
543 $this->assertResult(1, 3, 5, 7, 9, 11, 13, 15);
545 $this->queryResults = $this->factory->get('entity_test_mulrev')
546 ->condition("$figures.1.color", 'red')
549 // Delta 1 is not red.
550 $this->assertResult();
552 // Test on two different deltas.
553 $query = $this->factory->get('entity_test_mulrev');
554 $or = $query->andConditionGroup()
555 ->condition("$figures.0.color", 'red')
556 ->condition("$figures.1.color", 'blue');
557 $this->queryResults = $query
561 $this->assertResult(3, 7, 11, 15);
563 // Test the delta range condition.
564 $this->queryResults = $this->factory->get('entity_test_mulrev')
565 ->condition("$figures.%delta.color", ['blue', 'red'], 'IN')
566 ->condition("$figures.%delta", [0, 1], 'IN')
569 // Figure delta 0 or 1 can be blue or red, this matches a lot of entities.
570 $this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15);
572 // Test the delta range condition without conditions on the value.
573 $this->queryResults = $this->factory->get('entity_test_mulrev')
574 ->condition("$figures.%delta", 1)
577 // Entity needs to have atleast two figures.
578 $this->assertResult(3, 7, 11, 15);
580 // Numeric delta on single value base field should return results only if
581 // the first item is being targeted.
582 $this->queryResults = $this->factory->get('entity_test_mulrev')
583 ->condition("id.0.value", [1, 3, 5], 'IN')
586 $this->assertResult(1, 3, 5);
587 $this->queryResults = $this->factory->get('entity_test_mulrev')
588 ->condition("id.1.value", [1, 3, 5], 'IN')
591 $this->assertResult();
593 // Delta range condition on single value base field should return results
594 // only if just the field value is targeted.
595 $this->queryResults = $this->factory->get('entity_test_mulrev')
596 ->condition("id.%delta.value", [1, 3, 5], 'IN')
599 $this->assertResult(1, 3, 5);
600 $this->queryResults = $this->factory->get('entity_test_mulrev')
601 ->condition("id.%delta.value", [1, 3, 5], 'IN')
602 ->condition("id.%delta", 0, '=')
605 $this->assertResult(1, 3, 5);
606 $this->queryResults = $this->factory->get('entity_test_mulrev')
607 ->condition("id.%delta.value", [1, 3, 5], 'IN')
608 ->condition("id.%delta", 1, '=')
611 $this->assertResult();
615 protected function assertResult() {
617 $expected = func_get_args();
618 if ($expected && is_array($expected[0])) {
619 $expected = $expected[0];
621 foreach ($expected as $binary) {
622 $assert[$binary] = strval($binary);
624 $this->assertIdentical($this->queryResults, $assert);
627 protected function assertRevisionResult($keys, $expected) {
629 foreach ($expected as $key => $binary) {
630 $assert[$keys[$key]] = strval($binary);
632 $this->assertIdentical($this->queryResults, $assert);
636 protected function assertBundleOrder($order) {
637 // This loop is for bundle1 entities.
638 for ($i = 1; $i <= 15; $i += 2) {
640 $index1 = array_search($i, $this->queryResults);
641 $this->assertNotIdentical($index1, FALSE, "$i found at $index1.");
642 // This loop is for bundle2 entities.
643 for ($j = 2; $j <= 15; $j += 2) {
645 if ($order == 'asc') {
646 $ok = $index1 > array_search($j, $this->queryResults);
649 $ok = $index1 < array_search($j, $this->queryResults);
653 $this->assertTrue($ok, "$i is after all entities in bundle2");
658 * Test adding a tag and metadata to the Entity query object.
660 * The tags and metadata should propagate to the SQL query object.
662 public function testMetaData() {
663 $query = \Drupal::entityQuery('entity_test_mulrev');
665 ->addTag('efq_metadata_test')
666 ->addMetaData('foo', 'bar')
669 global $efq_test_metadata;
670 $this->assertEqual($efq_test_metadata, 'bar', 'Tag and metadata propagated to the SQL query object.');
674 * Test case sensitive and in-sensitive query conditions.
676 public function testCaseSensitivity() {
677 $bundle = $this->randomMachineName();
679 $field_storage = FieldStorageConfig::create([
680 'field_name' => 'field_ci',
681 'entity_type' => 'entity_test_mulrev',
684 'translatable' => FALSE,
686 'case_sensitive' => FALSE,
689 $field_storage->save();
691 FieldConfig::create([
692 'field_storage' => $field_storage,
696 $field_storage = FieldStorageConfig::create([
697 'field_name' => 'field_cs',
698 'entity_type' => 'entity_test_mulrev',
701 'translatable' => FALSE,
703 'case_sensitive' => TRUE,
706 $field_storage->save();
708 FieldConfig::create([
709 'field_storage' => $field_storage,
715 for ($i = 0; $i < 2; $i++) {
716 // If the last 4 of the string are all numbers, then there is no
717 // difference between upper and lowercase and the case sensitive CONTAINS
718 // test will fail. Ensure that can not happen by appending a non-numeric
719 // character. See https://www.drupal.org/node/2397297.
720 $string = $this->randomMachineName(7) . 'a';
722 'original' => $string,
723 'uppercase' => Unicode::strtoupper($string),
724 'lowercase' => Unicode::strtolower($string),
728 EntityTestMulRev::create([
730 'name' => $this->randomMachineName(),
732 'field_ci' => $fixtures[0]['uppercase'] . $fixtures[1]['lowercase'],
733 'field_cs' => $fixtures[0]['uppercase'] . $fixtures[1]['lowercase']
736 // Check the case insensitive field, = operator.
737 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
738 'field_ci', $fixtures[0]['lowercase'] . $fixtures[1]['lowercase']
740 $this->assertIdentical(count($result), 1, 'Case insensitive, lowercase');
742 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
743 'field_ci', $fixtures[0]['uppercase'] . $fixtures[1]['uppercase']
745 $this->assertIdentical(count($result), 1, 'Case insensitive, uppercase');
747 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
748 'field_ci', $fixtures[0]['uppercase'] . $fixtures[1]['lowercase']
750 $this->assertIdentical(count($result), 1, 'Case insensitive, mixed.');
752 // Check the case sensitive field, = operator.
753 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
754 'field_cs', $fixtures[0]['lowercase'] . $fixtures[1]['lowercase']
756 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase.');
758 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
759 'field_cs', $fixtures[0]['uppercase'] . $fixtures[1]['uppercase']
761 $this->assertIdentical(count($result), 0, 'Case sensitive, uppercase.');
763 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
764 'field_cs', $fixtures[0]['uppercase'] . $fixtures[1]['lowercase']
766 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
768 // Check the case insensitive field, IN operator.
769 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
770 'field_ci', [$fixtures[0]['lowercase'] . $fixtures[1]['lowercase']], 'IN'
772 $this->assertIdentical(count($result), 1, 'Case insensitive, lowercase');
774 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
775 'field_ci', [$fixtures[0]['uppercase'] . $fixtures[1]['uppercase']], 'IN'
777 $this->assertIdentical(count($result), 1, 'Case insensitive, uppercase');
779 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
780 'field_ci', [$fixtures[0]['uppercase'] . $fixtures[1]['lowercase']], 'IN'
782 $this->assertIdentical(count($result), 1, 'Case insensitive, mixed');
784 // Check the case sensitive field, IN operator.
785 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
786 'field_cs', [$fixtures[0]['lowercase'] . $fixtures[1]['lowercase']], 'IN'
788 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase');
790 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
791 'field_cs', [$fixtures[0]['uppercase'] . $fixtures[1]['uppercase']], 'IN'
793 $this->assertIdentical(count($result), 0, 'Case sensitive, uppercase');
795 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
796 'field_cs', [$fixtures[0]['uppercase'] . $fixtures[1]['lowercase']], 'IN'
798 $this->assertIdentical(count($result), 1, 'Case sensitive, mixed');
800 // Check the case insensitive field, STARTS_WITH operator.
801 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
802 'field_ci', $fixtures[0]['lowercase'], 'STARTS_WITH'
804 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
806 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
807 'field_ci', $fixtures[0]['uppercase'], 'STARTS_WITH'
809 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
811 // Check the case sensitive field, STARTS_WITH operator.
812 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
813 'field_cs', $fixtures[0]['lowercase'], 'STARTS_WITH'
815 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase.');
817 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
818 'field_cs', $fixtures[0]['uppercase'], 'STARTS_WITH'
820 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
822 // Check the case insensitive field, ENDS_WITH operator.
823 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
824 'field_ci', $fixtures[1]['lowercase'], 'ENDS_WITH'
826 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
828 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
829 'field_ci', $fixtures[1]['uppercase'], 'ENDS_WITH'
831 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
833 // Check the case sensitive field, ENDS_WITH operator.
834 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
835 'field_cs', $fixtures[1]['lowercase'], 'ENDS_WITH'
837 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
839 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
840 'field_cs', $fixtures[1]['uppercase'], 'ENDS_WITH'
842 $this->assertIdentical(count($result), 0, 'Case sensitive, exact match.');
844 // Check the case insensitive field, CONTAINS operator, use the inner 8
845 // characters of the uppercase and lowercase strings.
846 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
847 'field_ci', Unicode::substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8), 'CONTAINS'
849 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
851 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
852 'field_ci', Unicode::strtolower(Unicode::substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8)), 'CONTAINS'
854 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
856 // Check the case sensitive field, CONTAINS operator.
857 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
858 'field_cs', Unicode::substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8), 'CONTAINS'
860 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
862 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
863 'field_cs', Unicode::strtolower(Unicode::substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8)), 'CONTAINS'
865 $this->assertIdentical(count($result), 0, 'Case sensitive, exact match.');
870 * Test base fields with multiple columns.
872 public function testBaseFieldMultipleColumns() {
873 $this->enableModules(['taxonomy']);
874 $this->installEntitySchema('taxonomy_term');
876 Vocabulary::create(['vid' => 'tags']);
878 $term1 = Term::create([
879 'name' => $this->randomMachineName(),
882 'value' => $this->randomString(),
883 'format' => 'format1',
888 $term2 = Term::create([
889 'name' => $this->randomMachineName(),
892 'value' => $this->randomString(),
893 'format' => 'format2',
898 $ids = \Drupal::entityQuery('taxonomy_term')
899 ->condition('description.format', 'format1')
902 $this->assertEqual(count($ids), 1);
903 $this->assertEqual($term1->id(), reset($ids));
907 * Test pending revisions.
909 public function testPendingRevisions() {
910 // Ensure entity 14 is returned.
911 $result = \Drupal::entityQuery('entity_test_mulrev')
912 ->condition('id', [14], 'IN')
914 $this->assertEqual(count($result), 1);
916 // Set a revision on entity 14 that isn't the current default.
917 $entity = EntityTestMulRev::load(14);
918 $current_values = $entity->{$this->figures}->getValue();
920 $entity->setNewRevision(TRUE);
921 $entity->isDefaultRevision(FALSE);
922 $entity->{$this->figures}->setValue([
928 // Entity query should still return entity 14.
929 $result = \Drupal::entityQuery('entity_test_mulrev')
930 ->condition('id', [14], 'IN')
932 $this->assertEqual(count($result), 1);
934 // Verify that field conditions on the default and pending revision are
936 $result = \Drupal::entityQuery('entity_test_mulrev')
937 ->condition('id', [14], 'IN')
938 ->condition("$this->figures.color", $current_values[0]['color'])
940 $this->assertEqual($result, [14 => '14']);
941 $result = $this->factory->get('entity_test_mulrev')
942 ->condition('id', [14], 'IN')
943 ->condition("$this->figures.color", 'red')
946 $this->assertEqual($result, [16 => '14']);
948 // Add another pending revision on the same entity and repeat the checks.
949 $entity->setNewRevision(TRUE);
950 $entity->isDefaultRevision(FALSE);
951 $entity->{$this->figures}->setValue([
957 // A non-revisioned entity query should still return entity 14.
958 $result = $this->factory->get('entity_test_mulrev')
959 ->condition('id', [14], 'IN')
961 $this->assertCount(1, $result);
962 $this->assertSame([14 => '14'], $result);
964 // Now check an entity query on the latest revision.
965 $result = $this->factory->get('entity_test_mulrev')
966 ->condition('id', [14], 'IN')
969 $this->assertCount(1, $result);
970 $this->assertSame([17 => '14'], $result);
972 // Verify that field conditions on the default and pending revision still
974 $result = $this->factory->get('entity_test_mulrev')
975 ->condition('id', [14], 'IN')
976 ->condition("$this->figures.color", $current_values[0]['color'])
978 $this->assertSame([14 => '14'], $result);
980 // Now there are two revisions with same value for the figure color.
981 $result = $this->factory->get('entity_test_mulrev')
982 ->condition('id', [14], 'IN')
983 ->condition("$this->figures.color", 'red')
986 $this->assertSame([16 => '14', 17 => '14'], $result);
988 // Check that querying for the latest revision returns the correct one.
989 $result = $this->factory->get('entity_test_mulrev')
990 ->condition('id', [14], 'IN')
991 ->condition("$this->figures.color", 'red')
994 $this->assertSame([17 => '14'], $result);
998 * Test against SQL inject of condition field. This covers a
999 * database driver's EntityQuery\Condition class.
1001 public function testInjectionInCondition() {
1003 $this->queryResults = $this->factory->get('entity_test_mulrev')
1004 ->condition('1 ; -- ', [0, 1], 'IN')
1007 $this->fail('SQL Injection attempt in Entity Query condition in operator should result in an exception.');
1009 catch (\Exception $e) {
1010 $this->pass('SQL Injection attempt in Entity Query condition in operator should result in an exception.');
1015 * Tests that EntityQuery works when querying the same entity from two fields.
1017 public function testWithTwoEntityReferenceFieldsToSameEntityType() {
1018 // Create two entity reference fields referring 'entity_test' entities.
1019 $this->createEntityReferenceField('entity_test', 'entity_test', 'ref1', $this->randomMachineName(), 'entity_test');
1020 $this->createEntityReferenceField('entity_test', 'entity_test', 'ref2', $this->randomMachineName(), 'entity_test');
1022 // Create two entities to be referred.
1023 $ref1 = EntityTest::create(['type' => 'entity_test']);
1025 $ref2 = EntityTest::create(['type' => 'entity_test']);
1028 // Create a main entity referring the previous created entities.
1029 $entity = EntityTest::create([
1030 'type' => 'entity_test',
1031 'ref1' => $ref1->id(),
1032 'ref2' => $ref2->id(),
1036 // Check that works when referring with "{$field_name}".
1037 $result = $this->factory->get('entity_test')
1038 ->condition('type', 'entity_test')
1039 ->condition('ref1', $ref1->id())
1040 ->condition('ref2', $ref2->id())
1042 $this->assertCount(1, $result);
1043 $this->assertEquals($entity->id(), reset($result));
1045 // Check that works when referring with "{$field_name}.target_id".
1046 $result = $this->factory->get('entity_test')
1047 ->condition('type', 'entity_test')
1048 ->condition('ref1.target_id', $ref1->id())
1049 ->condition('ref2.target_id', $ref2->id())
1051 $this->assertCount(1, $result);
1052 $this->assertEquals($entity->id(), reset($result));
1054 // Check that works when referring with "{$field_name}.entity.id".
1055 $result = $this->factory->get('entity_test')
1056 ->condition('type', 'entity_test')
1057 ->condition('ref1.entity.id', $ref1->id())
1058 ->condition('ref2.entity.id', $ref2->id())
1060 $this->assertCount(1, $result);
1061 $this->assertEquals($entity->id(), reset($result));