3 namespace Drupal\KernelTests\Core\Entity;
5 use Drupal\entity_test\Entity\EntityTest;
6 use Drupal\entity_test\Entity\EntityTestMulRev;
7 use Drupal\field\Entity\FieldConfig;
8 use Drupal\field\Entity\FieldStorageConfig;
9 use Drupal\language\Entity\ConfigurableLanguage;
10 use Drupal\taxonomy\Entity\Term;
11 use Drupal\taxonomy\Entity\Vocabulary;
12 use Drupal\Tests\field\Traits\EntityReferenceTestTrait;
13 use Symfony\Component\HttpFoundation\Request;
16 * Tests Entity Query functionality.
20 class EntityQueryTest extends EntityKernelTestBase {
22 use EntityReferenceTestTrait;
29 public static $modules = ['field_test', 'language'];
34 protected $queryResults;
37 * A list of bundle machine names created for this test.
44 * Field name for the greetings field.
51 * Field name for the figures field.
58 * The entity_test_mulrev entity storage.
60 * @var \Drupal\Core\Entity\EntityStorageInterface
64 protected function setUp() {
67 $this->installEntitySchema('entity_test_mulrev');
69 $this->installConfig(['language']);
71 $figures = mb_strtolower($this->randomMachineName());
72 $greetings = mb_strtolower($this->randomMachineName());
73 foreach ([$figures => 'shape', $greetings => 'text'] as $field_name => $field_type) {
74 $field_storage = FieldStorageConfig::create([
75 'field_name' => $field_name,
76 'entity_type' => 'entity_test_mulrev',
77 'type' => $field_type,
80 $field_storage->save();
81 $field_storages[] = $field_storage;
84 for ($i = 0; $i < 2; $i++) {
85 // For the sake of tablesort, make sure the second bundle is higher than
86 // the first one. Beware: MySQL is not case sensitive.
88 $bundle = $this->randomMachineName();
89 } while ($bundles && strtolower($bundles[0]) >= strtolower($bundle));
90 entity_test_create_bundle($bundle);
91 foreach ($field_storages as $field_storage) {
93 'field_storage' => $field_storage,
99 // Each unit is a list of field name, langcode and a column-value array.
100 $units[] = [$figures, 'en', [
102 'shape' => 'triangle',
105 $units[] = [$figures, 'en', [
110 // To make it easier to test sorting, the greetings get formats according
111 // to their langcode.
112 $units[] = [$greetings, 'tr', [
113 'value' => 'merhaba',
114 'format' => 'format-tr',
117 $units[] = [$greetings, 'pl', [
119 'format' => 'format-pl',
122 // Make these languages available to the greetings field.
123 ConfigurableLanguage::createFromLangcode('tr')->save();
124 ConfigurableLanguage::createFromLangcode('pl')->save();
125 // Calculate the cartesian product of the unit array by looking at the
126 // bits of $i and add the unit at the bits that are 1. For example,
127 // decimal 13 is binary 1101 so unit 3,2 and 0 will be added to the
129 for ($i = 1; $i <= 15; $i++) {
130 $entity = EntityTestMulRev::create([
131 'type' => $bundles[$i & 1],
132 'name' => $this->randomMachineName(),
135 // Make sure the name is set for every language that we might create.
136 foreach (['tr', 'pl'] as $langcode) {
137 $entity->addTranslation($langcode)->name = $this->randomMachineName();
139 foreach (array_reverse(str_split(decbin($i))) as $key => $bit) {
141 list($field_name, $langcode, $values) = $units[$key];
142 $entity->getTranslation($langcode)->{$field_name}[] = $values;
147 $this->bundles = $bundles;
148 $this->figures = $figures;
149 $this->greetings = $greetings;
150 $this->storage = $this->container->get('entity_type.manager')->getStorage('entity_test_mulrev');
154 * Test basic functionality.
156 public function testEntityQuery() {
157 $greetings = $this->greetings;
158 $figures = $this->figures;
159 $this->queryResults = $this->storage
161 ->exists($greetings, 'tr')
162 ->condition("$figures.color", 'red')
165 // As unit 0 was the red triangle and unit 2 was the turkish greeting,
166 // bit 0 and bit 2 needs to be set.
167 $this->assertResult(5, 7, 13, 15);
169 $query = $this->storage
171 ->exists($greetings, 'tr')
172 ->condition("$figures.color", 'red')
174 $count_query = clone $query;
175 $this->assertEqual(12, $count_query->count()->execute());
176 $this->queryResults = $query->execute();
177 // Now bit 0 (1, 3, 5, 7, 9, 11, 13, 15) or bit 2 (4, 5, 6, 7, 12, 13, 14,
178 // 15) needs to be set.
179 $this->assertResult(1, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15);
181 // Test cloning of query conditions.
182 $query = $this->storage
184 ->condition("$figures.color", 'red')
186 $cloned_query = clone $query;
188 ->condition("$figures.shape", 'circle');
189 // Bit 0 (1, 3, 5, 7, 9, 11, 13, 15) needs to be set.
190 $this->queryResults = $query->execute();
191 $this->assertResult(1, 3, 5, 7, 9, 11, 13, 15);
192 // No red color has a circle shape.
193 $this->queryResults = $cloned_query->execute();
194 $this->assertResult();
196 $query = $this->storage->getQuery();
197 $group = $query->orConditionGroup()
198 ->exists($greetings, 'tr')
199 ->condition("$figures.color", 'red');
200 $this->queryResults = $query
202 ->condition("$greetings.value", 'sie', 'STARTS_WITH')
203 ->sort('revision_id')
205 // Bit 3 and (bit 0 or 2) -- the above 8 part of the above.
206 $this->assertResult(9, 11, 12, 13, 14, 15);
208 // No figure has both the colors blue and red at the same time.
209 $this->queryResults = $this->storage
211 ->condition("$figures.color", 'blue')
212 ->condition("$figures.color", 'red')
215 $this->assertResult();
217 // But an entity might have a red and a blue figure both.
218 $query = $this->storage->getQuery();
219 $group_blue = $query->andConditionGroup()->condition("$figures.color", 'blue');
220 $group_red = $query->andConditionGroup()->condition("$figures.color", 'red');
221 $this->queryResults = $query
222 ->condition($group_blue)
223 ->condition($group_red)
224 ->sort('revision_id')
226 // Unit 0 and unit 1, so bits 0 1.
227 $this->assertResult(3, 7, 11, 15);
229 // Do the same test but with IN operator.
230 $query = $this->storage->getQuery();
231 $group_blue = $query->andConditionGroup()->condition("$figures.color", ['blue'], 'IN');
232 $group_red = $query->andConditionGroup()->condition("$figures.color", ['red'], 'IN');
233 $this->queryResults = $query
234 ->condition($group_blue)
235 ->condition($group_red)
238 // Unit 0 and unit 1, so bits 0 1.
239 $this->assertResult(3, 7, 11, 15);
241 // An entity might have either red or blue figure.
242 $this->queryResults = $this->storage
244 ->condition("$figures.color", ['blue', 'red'], 'IN')
248 $this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15);
250 $this->queryResults = $this->storage
252 ->exists("$figures.color")
253 ->notExists("$greetings.value")
256 // Bit 0 or 1 is on but 2 and 3 are not.
257 $this->assertResult(1, 2, 3);
258 // Now update the 'merhaba' string to xsiemax which is not a meaningful
259 // word but allows us to test revisions and string operations.
260 $ids = $this->storage
262 ->condition("$greetings.value", 'merhaba')
265 $entities = EntityTestMulRev::loadMultiple($ids);
266 $first_entity = reset($entities);
267 $old_name = $first_entity->name->value;
268 foreach ($entities as $entity) {
269 $entity->setNewRevision();
270 $entity->getTranslation('tr')->$greetings->value = 'xsiemax';
271 $entity->name->value .= 'x';
274 // We changed the entity names, so the current revision should not match.
275 $this->queryResults = $this->storage
277 ->condition('name.value', $old_name)
279 $this->assertResult();
280 // Only if all revisions are queried, we find the old revision.
281 $this->queryResults = $this->storage
283 ->condition('name.value', $old_name)
285 ->sort('revision_id')
287 $this->assertRevisionResult([$first_entity->id()], [$first_entity->id()]);
288 // When querying current revisions, this string is no longer found.
289 $this->queryResults = $this->storage
291 ->condition("$greetings.value", 'merhaba')
293 $this->assertResult();
294 $this->queryResults = $this->storage
296 ->condition("$greetings.value", 'merhaba')
298 ->sort('revision_id')
300 // The query only matches the original revisions.
301 $this->assertRevisionResult([4, 5, 6, 7, 12, 13, 14, 15], [4, 5, 6, 7, 12, 13, 14, 15]);
302 $results = $this->storage
304 ->condition("$greetings.value", 'siema', 'CONTAINS')
307 // This matches both the original and new current revisions, multiple
308 // revisions are returned for some entities.
309 $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'];
310 $this->assertIdentical($results, $assert);
311 $results = $this->storage
313 ->condition("$greetings.value", 'siema', 'STARTS_WITH')
314 ->sort('revision_id')
316 // Now we only get the ones that originally were siema, entity id 8 and
318 $this->assertIdentical($results, array_slice($assert, 4, 8, TRUE));
319 $results = $this->storage
321 ->condition("$greetings.value", 'a', 'ENDS_WITH')
322 ->sort('revision_id')
324 // It is very important that we do not get the ones which only have
325 // xsiemax despite originally they were merhaba, ie. ended with a.
326 $this->assertIdentical($results, array_slice($assert, 4, 8, TRUE));
327 $results = $this->storage
329 ->condition("$greetings.value", 'a', 'ENDS_WITH')
332 ->sort('revision_id')
334 // Now we get everything.
335 $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'];
336 $this->assertIdentical($results, $assert);
338 // Check that a query on the latest revisions without any condition returns
339 // the correct results.
340 $results = $this->storage
344 ->sort('revision_id')
346 $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'];
347 $this->assertSame($expected, $results);
353 * Warning: this is complicated.
355 public function testSort() {
356 $greetings = $this->greetings;
357 $figures = $this->figures;
358 // Order up and down on a number.
359 $this->queryResults = $this->storage
363 $this->assertResult(range(1, 15));
364 $this->queryResults = $this->storage
368 $this->assertResult(range(15, 1));
369 $query = $this->storage
371 ->sort("$figures.color")
372 ->sort("$greetings.format")
374 // As we do not have any conditions, here are the possible colors and
375 // language codes, already in order, with the first occurrence of the
376 // entity id marked with *:
408 $count_query = clone $query;
409 $this->assertEqual(15, $count_query->count()->execute());
410 $this->queryResults = $query->execute();
411 $this->assertResult(8, 12, 4, 2, 3, 10, 11, 14, 15, 6, 7, 1, 9, 13, 5);
413 // Test the pager by setting element #1 to page 2 with a page size of 4.
414 // Results will be #8-12 from above.
415 $request = Request::createFromGlobals();
416 $request->query->replace([
419 \Drupal::getContainer()->get('request_stack')->push($request);
420 $this->queryResults = $this->storage
422 ->sort("$figures.color")
423 ->sort("$greetings.format")
427 $this->assertResult(15, 6, 7, 1);
429 // Now test the reversed order.
430 $query = $this->storage
432 ->sort("$figures.color", 'DESC')
433 ->sort("$greetings.format", 'DESC')
434 ->sort('id', 'DESC');
435 $count_query = clone $query;
436 $this->assertEqual(15, $count_query->count()->execute());
437 $this->queryResults = $query->execute();
438 $this->assertResult(15, 13, 7, 5, 11, 9, 3, 1, 14, 6, 10, 2, 12, 4, 8);
444 public function testTableSort() {
445 // While ordering on bundles do not give us a definite order, we can still
446 // assert that all entities from one bundle are after the other as the
448 $request = Request::createFromGlobals();
449 $request->query->replace([
453 \Drupal::getContainer()->get('request_stack')->push($request);
456 'id' => ['data' => 'Id', 'specifier' => 'id'],
457 'type' => ['data' => 'Type', 'specifier' => 'type'],
460 $this->queryResults = array_values($this->storage
464 $this->assertBundleOrder('asc');
466 $request->query->add([
469 \Drupal::getContainer()->get('request_stack')->push($request);
472 'id' => ['data' => 'Id', 'specifier' => 'id'],
473 'type' => ['data' => 'Type', 'specifier' => 'type'],
475 $this->queryResults = array_values($this->storage
479 $this->assertBundleOrder('desc');
481 // Ordering on ID is definite, however.
482 $request->query->add([
485 \Drupal::getContainer()->get('request_stack')->push($request);
486 $this->queryResults = $this->storage
490 $this->assertResult(range(15, 1));
494 * Test that count queries are separated across entity types.
496 public function testCount() {
497 // Create a field with the same name in a different entity type.
498 $field_name = $this->figures;
499 $field_storage = FieldStorageConfig::create([
500 'field_name' => $field_name,
501 'entity_type' => 'entity_test',
504 'translatable' => TRUE,
506 $field_storage->save();
507 $bundle = $this->randomMachineName();
508 FieldConfig::create([
509 'field_storage' => $field_storage,
513 $entity = EntityTest::create([
517 $entity->enforceIsNew();
520 // As the single entity of this type we just saved does not have a value
521 // in the color field, the result should be 0.
522 $count = $this->container->get('entity_type.manager')
523 ->getStorage('entity_test')
525 ->exists("$field_name.color")
528 $this->assertFalse($count);
532 * Tests that nested condition groups work as expected.
534 public function testNestedConditionGroups() {
535 // Query for all entities of the first bundle that have either a red
536 // triangle as a figure or the Turkish greeting as a greeting.
537 $query = $this->storage->getQuery();
539 $first_and = $query->andConditionGroup()
540 ->condition($this->figures . '.color', 'red')
541 ->condition($this->figures . '.shape', 'triangle');
542 $second_and = $query->andConditionGroup()
543 ->condition($this->greetings . '.value', 'merhaba')
544 ->condition($this->greetings . '.format', 'format-tr');
546 $or = $query->orConditionGroup()
547 ->condition($first_and)
548 ->condition($second_and);
550 $this->queryResults = $query
552 ->condition('type', reset($this->bundles))
556 $this->assertResult(4, 6, 12, 14);
560 * Tests that condition count returns expected number of conditions.
562 public function testConditionCount() {
563 // Query for all entities of the first bundle that
564 // have red as a colour AND are triangle shaped.
565 $query = $this->storage->getQuery();
567 // Add an AND condition group with 2 conditions in it.
568 $and_condition_group = $query->andConditionGroup()
569 ->condition($this->figures . '.color', 'red')
570 ->condition($this->figures . '.shape', 'triangle');
572 // We added 2 conditions so count should be 2.
573 $this->assertEqual($and_condition_group->count(), 2);
575 // Add an OR condition group with 2 conditions in it.
576 $or_condition_group = $query->orConditionGroup()
577 ->condition($this->figures . '.color', 'red')
578 ->condition($this->figures . '.shape', 'triangle');
580 // We added 2 conditions so count should be 2.
581 $this->assertEqual($or_condition_group->count(), 2);
585 * Test queries with delta conditions.
587 public function testDelta() {
588 $figures = $this->figures;
589 // Test numeric delta value in field condition.
590 $this->queryResults = $this->storage
592 ->condition("$figures.0.color", 'red')
595 // As unit 0 at delta 0 was the red triangle bit 0 needs to be set.
596 $this->assertResult(1, 3, 5, 7, 9, 11, 13, 15);
598 $this->queryResults = $this->storage
600 ->condition("$figures.1.color", 'red')
603 // Delta 1 is not red.
604 $this->assertResult();
606 // Test on two different deltas.
607 $query = $this->storage->getQuery();
608 $or = $query->andConditionGroup()
609 ->condition("$figures.0.color", 'red')
610 ->condition("$figures.1.color", 'blue');
611 $this->queryResults = $query
615 $this->assertResult(3, 7, 11, 15);
617 // Test the delta range condition.
618 $this->queryResults = $this->storage
620 ->condition("$figures.%delta.color", ['blue', 'red'], 'IN')
621 ->condition("$figures.%delta", [0, 1], 'IN')
624 // Figure delta 0 or 1 can be blue or red, this matches a lot of entities.
625 $this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15);
627 // Test the delta range condition without conditions on the value.
628 $this->queryResults = $this->storage
630 ->condition("$figures.%delta", 1)
633 // Entity needs to have at least two figures.
634 $this->assertResult(3, 7, 11, 15);
636 // Numeric delta on single value base field should return results only if
637 // the first item is being targeted.
638 $this->queryResults = $this->storage
640 ->condition("id.0.value", [1, 3, 5], 'IN')
643 $this->assertResult(1, 3, 5);
644 $this->queryResults = $this->storage
646 ->condition("id.1.value", [1, 3, 5], 'IN')
649 $this->assertResult();
651 // Delta range condition on single value base field should return results
652 // only if just the field value is targeted.
653 $this->queryResults = $this->storage
655 ->condition("id.%delta.value", [1, 3, 5], 'IN')
658 $this->assertResult(1, 3, 5);
659 $this->queryResults = $this->storage
661 ->condition("id.%delta.value", [1, 3, 5], 'IN')
662 ->condition("id.%delta", 0, '=')
665 $this->assertResult(1, 3, 5);
666 $this->queryResults = $this->storage
668 ->condition("id.%delta.value", [1, 3, 5], 'IN')
669 ->condition("id.%delta", 1, '=')
672 $this->assertResult();
676 protected function assertResult() {
678 $expected = func_get_args();
679 if ($expected && is_array($expected[0])) {
680 $expected = $expected[0];
682 foreach ($expected as $binary) {
683 $assert[$binary] = strval($binary);
685 $this->assertIdentical($this->queryResults, $assert);
688 protected function assertRevisionResult($keys, $expected) {
690 foreach ($expected as $key => $binary) {
691 $assert[$keys[$key]] = strval($binary);
693 $this->assertIdentical($this->queryResults, $assert);
697 protected function assertBundleOrder($order) {
698 // This loop is for bundle1 entities.
699 for ($i = 1; $i <= 15; $i += 2) {
701 $index1 = array_search($i, $this->queryResults);
702 $this->assertNotIdentical($index1, FALSE, "$i found at $index1.");
703 // This loop is for bundle2 entities.
704 for ($j = 2; $j <= 15; $j += 2) {
706 if ($order == 'asc') {
707 $ok = $index1 > array_search($j, $this->queryResults);
710 $ok = $index1 < array_search($j, $this->queryResults);
714 $this->assertTrue($ok, "$i is after all entities in bundle2");
719 * Test adding a tag and metadata to the Entity query object.
721 * The tags and metadata should propagate to the SQL query object.
723 public function testMetaData() {
724 $query = $this->storage->getQuery();
726 ->addTag('efq_metadata_test')
727 ->addMetaData('foo', 'bar')
730 global $efq_test_metadata;
731 $this->assertEqual($efq_test_metadata, 'bar', 'Tag and metadata propagated to the SQL query object.');
735 * Test case sensitive and in-sensitive query conditions.
737 public function testCaseSensitivity() {
738 $bundle = $this->randomMachineName();
740 $field_storage = FieldStorageConfig::create([
741 'field_name' => 'field_ci',
742 'entity_type' => 'entity_test_mulrev',
745 'translatable' => FALSE,
747 'case_sensitive' => FALSE,
750 $field_storage->save();
752 FieldConfig::create([
753 'field_storage' => $field_storage,
757 $field_storage = FieldStorageConfig::create([
758 'field_name' => 'field_cs',
759 'entity_type' => 'entity_test_mulrev',
762 'translatable' => FALSE,
764 'case_sensitive' => TRUE,
767 $field_storage->save();
769 FieldConfig::create([
770 'field_storage' => $field_storage,
776 for ($i = 0; $i < 2; $i++) {
777 // If the last 4 of the string are all numbers, then there is no
778 // difference between upper and lowercase and the case sensitive CONTAINS
779 // test will fail. Ensure that can not happen by appending a non-numeric
780 // character. See https://www.drupal.org/node/2397297.
781 $string = $this->randomMachineName(7) . 'a';
783 'original' => $string,
784 'uppercase' => mb_strtoupper($string),
785 'lowercase' => mb_strtolower($string),
789 EntityTestMulRev::create([
791 'name' => $this->randomMachineName(),
793 'field_ci' => $fixtures[0]['uppercase'] . $fixtures[1]['lowercase'],
794 'field_cs' => $fixtures[0]['uppercase'] . $fixtures[1]['lowercase'],
797 // Check the case insensitive field, = operator.
798 $result = $this->storage
800 ->condition('field_ci', $fixtures[0]['lowercase'] . $fixtures[1]['lowercase'])
802 $this->assertIdentical(count($result), 1, 'Case insensitive, lowercase');
804 $result = $this->storage
806 ->condition('field_ci', $fixtures[0]['uppercase'] . $fixtures[1]['uppercase'])
808 $this->assertIdentical(count($result), 1, 'Case insensitive, uppercase');
810 $result = $this->storage
812 ->condition('field_ci', $fixtures[0]['uppercase'] . $fixtures[1]['lowercase'])
814 $this->assertIdentical(count($result), 1, 'Case insensitive, mixed.');
816 // Check the case sensitive field, = operator.
817 $result = $this->storage
819 ->condition('field_cs', $fixtures[0]['lowercase'] . $fixtures[1]['lowercase'])
821 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase.');
823 $result = $this->storage
825 ->condition('field_cs', $fixtures[0]['uppercase'] . $fixtures[1]['uppercase'])
827 $this->assertIdentical(count($result), 0, 'Case sensitive, uppercase.');
829 $result = $this->storage
831 ->condition('field_cs', $fixtures[0]['uppercase'] . $fixtures[1]['lowercase'])
833 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
835 // Check the case insensitive field, IN operator.
836 $result = $this->storage
838 ->condition('field_ci', [$fixtures[0]['lowercase'] . $fixtures[1]['lowercase']], 'IN')
840 $this->assertIdentical(count($result), 1, 'Case insensitive, lowercase');
842 $result = $this->storage
844 ->condition('field_ci', [$fixtures[0]['uppercase'] . $fixtures[1]['uppercase']], 'IN')->execute();
845 $this->assertIdentical(count($result), 1, 'Case insensitive, uppercase');
847 $result = $this->storage
849 ->condition('field_ci', [$fixtures[0]['uppercase'] . $fixtures[1]['lowercase']], 'IN')
851 $this->assertIdentical(count($result), 1, 'Case insensitive, mixed');
853 // Check the case sensitive field, IN operator.
854 $result = $this->storage
856 ->condition('field_cs', [$fixtures[0]['lowercase'] . $fixtures[1]['lowercase']], 'IN')
858 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase');
860 $result = $this->storage
862 ->condition('field_cs', [$fixtures[0]['uppercase'] . $fixtures[1]['uppercase']], 'IN')
864 $this->assertIdentical(count($result), 0, 'Case sensitive, uppercase');
866 $result = $this->storage
868 ->condition('field_cs', [$fixtures[0]['uppercase'] . $fixtures[1]['lowercase']], 'IN')
870 $this->assertIdentical(count($result), 1, 'Case sensitive, mixed');
872 // Check the case insensitive field, STARTS_WITH operator.
873 $result = $this->storage
875 ->condition('field_ci', $fixtures[0]['lowercase'], 'STARTS_WITH')
877 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
879 $result = $this->storage
881 ->condition('field_ci', $fixtures[0]['uppercase'], 'STARTS_WITH')
883 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
885 // Check the case sensitive field, STARTS_WITH operator.
886 $result = $this->storage
888 ->condition('field_cs', $fixtures[0]['lowercase'], 'STARTS_WITH')
890 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase.');
892 $result = $this->storage
894 ->condition('field_cs', $fixtures[0]['uppercase'], 'STARTS_WITH')
896 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
898 // Check the case insensitive field, ENDS_WITH operator.
899 $result = $this->storage
901 ->condition('field_ci', $fixtures[1]['lowercase'], 'ENDS_WITH')
903 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
905 $result = $this->storage
907 ->condition('field_ci', $fixtures[1]['uppercase'], 'ENDS_WITH')
909 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
911 // Check the case sensitive field, ENDS_WITH operator.
912 $result = $this->storage
914 ->condition('field_cs', $fixtures[1]['lowercase'], 'ENDS_WITH')
916 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
918 $result = $this->storage
920 ->condition('field_cs', $fixtures[1]['uppercase'], 'ENDS_WITH')
922 $this->assertIdentical(count($result), 0, 'Case sensitive, exact match.');
924 // Check the case insensitive field, CONTAINS operator, use the inner 8
925 // characters of the uppercase and lowercase strings.
926 $result = $this->storage
928 ->condition('field_ci', mb_substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8), 'CONTAINS')
930 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
932 $result = $this->storage
934 ->condition('field_ci', mb_strtolower(mb_substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8)), 'CONTAINS')
936 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
938 // Check the case sensitive field, CONTAINS operator.
939 $result = $this->storage
941 ->condition('field_cs', mb_substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8), 'CONTAINS')
943 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
945 $result = $this->storage
947 ->condition('field_cs', mb_strtolower(mb_substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8)), 'CONTAINS')
949 $this->assertIdentical(count($result), 0, 'Case sensitive, exact match.');
954 * Test base fields with multiple columns.
956 public function testBaseFieldMultipleColumns() {
957 $this->enableModules(['taxonomy']);
958 $this->installEntitySchema('taxonomy_term');
960 Vocabulary::create(['vid' => 'tags']);
962 $term1 = Term::create([
963 'name' => $this->randomMachineName(),
966 'value' => $this->randomString(),
967 'format' => 'format1',
972 $term2 = Term::create([
973 'name' => $this->randomMachineName(),
976 'value' => $this->randomString(),
977 'format' => 'format2',
982 $ids = $this->container->get('entity_type.manager')
983 ->getStorage('taxonomy_term')
985 ->condition('description.format', 'format1')
988 $this->assertEqual(count($ids), 1);
989 $this->assertEqual($term1->id(), reset($ids));
993 * Test pending revisions.
995 public function testPendingRevisions() {
996 // Ensure entity 14 is returned.
997 $result = $this->storage
999 ->condition('id', [14], 'IN')
1001 $this->assertEqual(count($result), 1);
1003 // Set a revision on entity 14 that isn't the current default.
1004 $entity = EntityTestMulRev::load(14);
1005 $current_values = $entity->{$this->figures}->getValue();
1007 $entity->setNewRevision(TRUE);
1008 $entity->isDefaultRevision(FALSE);
1009 $entity->{$this->figures}->setValue([
1011 'shape' => 'square',
1015 // Entity query should still return entity 14.
1016 $result = $this->storage
1018 ->condition('id', [14], 'IN')
1020 $this->assertEqual(count($result), 1);
1022 // Verify that field conditions on the default and pending revision are
1023 // work as expected.
1024 $result = $this->storage
1026 ->condition('id', [14], 'IN')
1027 ->condition("$this->figures.color", $current_values[0]['color'])
1029 $this->assertEqual($result, [14 => '14']);
1030 $result = $this->storage
1032 ->condition('id', [14], 'IN')
1033 ->condition("$this->figures.color", 'red')
1036 $this->assertEqual($result, [16 => '14']);
1038 // Add another pending revision on the same entity and repeat the checks.
1039 $entity->setNewRevision(TRUE);
1040 $entity->isDefaultRevision(FALSE);
1041 $entity->{$this->figures}->setValue([
1043 'shape' => 'square',
1047 // A non-revisioned entity query should still return entity 14.
1048 $result = $this->storage
1050 ->condition('id', [14], 'IN')
1052 $this->assertCount(1, $result);
1053 $this->assertSame([14 => '14'], $result);
1055 // Now check an entity query on the latest revision.
1056 $result = $this->storage
1058 ->condition('id', [14], 'IN')
1061 $this->assertCount(1, $result);
1062 $this->assertSame([17 => '14'], $result);
1064 // Verify that field conditions on the default and pending revision still
1065 // work as expected.
1066 $result = $this->storage
1068 ->condition('id', [14], 'IN')
1069 ->condition("$this->figures.color", $current_values[0]['color'])
1071 $this->assertSame([14 => '14'], $result);
1073 // Now there are two revisions with same value for the figure color.
1074 $result = $this->storage
1076 ->condition('id', [14], 'IN')
1077 ->condition("$this->figures.color", 'red')
1080 $this->assertSame([16 => '14', 17 => '14'], $result);
1082 // Check that querying for the latest revision returns the correct one.
1083 $result = $this->storage
1085 ->condition('id', [14], 'IN')
1086 ->condition("$this->figures.color", 'red')
1089 $this->assertSame([17 => '14'], $result);
1093 * Test against SQL inject of condition field. This covers a
1094 * database driver's EntityQuery\Condition class.
1096 public function testInjectionInCondition() {
1098 $this->queryResults = $this->storage
1100 ->condition('1 ; -- ', [0, 1], 'IN')
1103 $this->fail('SQL Injection attempt in Entity Query condition in operator should result in an exception.');
1105 catch (\Exception $e) {
1106 $this->pass('SQL Injection attempt in Entity Query condition in operator should result in an exception.');
1111 * Tests that EntityQuery works when querying the same entity from two fields.
1113 public function testWithTwoEntityReferenceFieldsToSameEntityType() {
1114 // Create two entity reference fields referring 'entity_test' entities.
1115 $this->createEntityReferenceField('entity_test', 'entity_test', 'ref1', $this->randomMachineName(), 'entity_test');
1116 $this->createEntityReferenceField('entity_test', 'entity_test', 'ref2', $this->randomMachineName(), 'entity_test');
1118 $storage = $this->container->get('entity_type.manager')
1119 ->getStorage('entity_test');
1121 // Create two entities to be referred.
1122 $ref1 = EntityTest::create(['type' => 'entity_test']);
1124 $ref2 = EntityTest::create(['type' => 'entity_test']);
1127 // Create a main entity referring the previous created entities.
1128 $entity = EntityTest::create([
1129 'type' => 'entity_test',
1130 'ref1' => $ref1->id(),
1131 'ref2' => $ref2->id(),
1135 // Check that works when referring with "{$field_name}".
1136 $result = $storage->getQuery()
1137 ->condition('type', 'entity_test')
1138 ->condition('ref1', $ref1->id())
1139 ->condition('ref2', $ref2->id())
1141 $this->assertCount(1, $result);
1142 $this->assertEquals($entity->id(), reset($result));
1144 // Check that works when referring with "{$field_name}.target_id".
1145 $result = $storage->getQuery()
1146 ->condition('type', 'entity_test')
1147 ->condition('ref1.target_id', $ref1->id())
1148 ->condition('ref2.target_id', $ref2->id())
1150 $this->assertCount(1, $result);
1151 $this->assertEquals($entity->id(), reset($result));
1153 // Check that works when referring with "{$field_name}.entity.id".
1154 $result = $storage->getQuery()
1155 ->condition('type', 'entity_test')
1156 ->condition('ref1.entity.id', $ref1->id())
1157 ->condition('ref2.entity.id', $ref2->id())
1159 $this->assertCount(1, $result);
1160 $this->assertEquals($entity->id(), reset($result));