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\language\Entity\ConfigurableLanguage;
11 use Drupal\taxonomy\Entity\Term;
12 use Drupal\taxonomy\Entity\Vocabulary;
13 use Symfony\Component\HttpFoundation\Request;
16 * Tests Entity Query functionality.
20 class EntityQueryTest extends EntityKernelTestBase {
27 public static $modules = ['field_test', 'language'];
32 protected $queryResults;
35 * @var \Drupal\Core\Entity\Query\QueryFactory
40 * A list of bundle machine names created for this test.
47 * Field name for the greetings field.
54 * Field name for the figures field.
60 protected function setUp() {
63 $this->installEntitySchema('entity_test_mulrev');
65 $this->installConfig(['language']);
67 $figures = Unicode::strtolower($this->randomMachineName());
68 $greetings = Unicode::strtolower($this->randomMachineName());
69 foreach ([$figures => 'shape', $greetings => 'text'] as $field_name => $field_type) {
70 $field_storage = FieldStorageConfig::create([
71 'field_name' => $field_name,
72 'entity_type' => 'entity_test_mulrev',
73 'type' => $field_type,
76 $field_storage->save();
77 $field_storages[] = $field_storage;
80 for ($i = 0; $i < 2; $i++) {
81 // For the sake of tablesort, make sure the second bundle is higher than
82 // the first one. Beware: MySQL is not case sensitive.
84 $bundle = $this->randomMachineName();
85 } while ($bundles && strtolower($bundles[0]) >= strtolower($bundle));
86 entity_test_create_bundle($bundle);
87 foreach ($field_storages as $field_storage) {
89 'field_storage' => $field_storage,
95 // Each unit is a list of field name, langcode and a column-value array.
96 $units[] = [$figures, 'en', [
98 'shape' => 'triangle',
100 $units[] = [$figures, 'en', [
104 // To make it easier to test sorting, the greetings get formats according
105 // to their langcode.
106 $units[] = [$greetings, 'tr', [
107 'value' => 'merhaba',
108 'format' => 'format-tr'
110 $units[] = [$greetings, 'pl', [
112 'format' => 'format-pl'
114 // Make these languages available to the greetings field.
115 ConfigurableLanguage::createFromLangcode('tr')->save();
116 ConfigurableLanguage::createFromLangcode('pl')->save();
117 // Calculate the cartesian product of the unit array by looking at the
118 // bits of $i and add the unit at the bits that are 1. For example,
119 // decimal 13 is binary 1101 so unit 3,2 and 0 will be added to the
121 for ($i = 1; $i <= 15; $i++) {
122 $entity = EntityTestMulRev::create([
123 'type' => $bundles[$i & 1],
124 'name' => $this->randomMachineName(),
127 // Make sure the name is set for every language that we might create.
128 foreach (['tr', 'pl'] as $langcode) {
129 $entity->addTranslation($langcode)->name = $this->randomMachineName();
131 foreach (array_reverse(str_split(decbin($i))) as $key => $bit) {
133 list($field_name, $langcode, $values) = $units[$key];
134 $entity->getTranslation($langcode)->{$field_name}[] = $values;
139 $this->bundles = $bundles;
140 $this->figures = $figures;
141 $this->greetings = $greetings;
142 $this->factory = \Drupal::service('entity.query');
146 * Test basic functionality.
148 public function testEntityQuery() {
149 $greetings = $this->greetings;
150 $figures = $this->figures;
151 $this->queryResults = $this->factory->get('entity_test_mulrev')
152 ->exists($greetings, 'tr')
153 ->condition("$figures.color", 'red')
156 // As unit 0 was the red triangle and unit 2 was the turkish greeting,
157 // bit 0 and bit 2 needs to be set.
158 $this->assertResult(5, 7, 13, 15);
160 $query = $this->factory->get('entity_test_mulrev', 'OR')
161 ->exists($greetings, 'tr')
162 ->condition("$figures.color", 'red')
164 $count_query = clone $query;
165 $this->assertEqual(12, $count_query->count()->execute());
166 $this->queryResults = $query->execute();
167 // Now bit 0 (1, 3, 5, 7, 9, 11, 13, 15) or bit 2 (4, 5, 6, 7, 12, 13, 14,
168 // 15) needs to be set.
169 $this->assertResult(1, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 15);
171 // Test cloning of query conditions.
172 $query = $this->factory->get('entity_test_mulrev')
173 ->condition("$figures.color", 'red')
175 $cloned_query = clone $query;
177 ->condition("$figures.shape", 'circle');
178 // Bit 0 (1, 3, 5, 7, 9, 11, 13, 15) needs to be set.
179 $this->queryResults = $query->execute();
180 $this->assertResult(1, 3, 5, 7, 9, 11, 13, 15);
181 // No red color has a circle shape.
182 $this->queryResults = $cloned_query->execute();
183 $this->assertResult();
185 $query = $this->factory->get('entity_test_mulrev');
186 $group = $query->orConditionGroup()
187 ->exists($greetings, 'tr')
188 ->condition("$figures.color", 'red');
189 $this->queryResults = $query
191 ->condition("$greetings.value", 'sie', 'STARTS_WITH')
192 ->sort('revision_id')
194 // Bit 3 and (bit 0 or 2) -- the above 8 part of the above.
195 $this->assertResult(9, 11, 12, 13, 14, 15);
197 // No figure has both the colors blue and red at the same time.
198 $this->queryResults = $this->factory->get('entity_test_mulrev')
199 ->condition("$figures.color", 'blue')
200 ->condition("$figures.color", 'red')
203 $this->assertResult();
205 // But an entity might have a red and a blue figure both.
206 $query = $this->factory->get('entity_test_mulrev');
207 $group_blue = $query->andConditionGroup()->condition("$figures.color", 'blue');
208 $group_red = $query->andConditionGroup()->condition("$figures.color", 'red');
209 $this->queryResults = $query
210 ->condition($group_blue)
211 ->condition($group_red)
212 ->sort('revision_id')
214 // Unit 0 and unit 1, so bits 0 1.
215 $this->assertResult(3, 7, 11, 15);
217 // Do the same test but with IN operator.
218 $query = $this->factory->get('entity_test_mulrev');
219 $group_blue = $query->andConditionGroup()->condition("$figures.color", ['blue'], 'IN');
220 $group_red = $query->andConditionGroup()->condition("$figures.color", ['red'], 'IN');
221 $this->queryResults = $query
222 ->condition($group_blue)
223 ->condition($group_red)
226 // Unit 0 and unit 1, so bits 0 1.
227 $this->assertResult(3, 7, 11, 15);
229 // An entity might have either red or blue figure.
230 $this->queryResults = $this->factory->get('entity_test_mulrev')
231 ->condition("$figures.color", ['blue', 'red'], 'IN')
235 $this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15);
237 $this->queryResults = $this->factory->get('entity_test_mulrev')
238 ->exists("$figures.color")
239 ->notExists("$greetings.value")
242 // Bit 0 or 1 is on but 2 and 3 are not.
243 $this->assertResult(1, 2, 3);
244 // Now update the 'merhaba' string to xsiemax which is not a meaningful
245 // word but allows us to test revisions and string operations.
246 $ids = $this->factory->get('entity_test_mulrev')
247 ->condition("$greetings.value", 'merhaba')
250 $entities = EntityTestMulRev::loadMultiple($ids);
251 $first_entity = reset($entities);
252 $old_name = $first_entity->name->value;
253 foreach ($entities as $entity) {
254 $entity->setNewRevision();
255 $entity->getTranslation('tr')->$greetings->value = 'xsiemax';
256 $entity->name->value .= 'x';
259 // We changed the entity names, so the current revision should not match.
260 $this->queryResults = $this->factory->get('entity_test_mulrev')
261 ->condition('name.value', $old_name)
263 $this->assertResult();
264 // Only if all revisions are queried, we find the old revision.
265 $this->queryResults = $this->factory->get('entity_test_mulrev')
266 ->condition('name.value', $old_name)
268 ->sort('revision_id')
270 $this->assertRevisionResult([$first_entity->id()], [$first_entity->id()]);
271 // When querying current revisions, this string is no longer found.
272 $this->queryResults = $this->factory->get('entity_test_mulrev')
273 ->condition("$greetings.value", 'merhaba')
275 $this->assertResult();
276 $this->queryResults = $this->factory->get('entity_test_mulrev')
277 ->condition("$greetings.value", 'merhaba')
279 ->sort('revision_id')
281 // The query only matches the original revisions.
282 $this->assertRevisionResult([4, 5, 6, 7, 12, 13, 14, 15], [4, 5, 6, 7, 12, 13, 14, 15]);
283 $results = $this->factory->get('entity_test_mulrev')
284 ->condition("$greetings.value", 'siema', 'CONTAINS')
287 // This matches both the original and new current revisions, multiple
288 // revisions are returned for some entities.
289 $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'];
290 $this->assertIdentical($results, $assert);
291 $results = $this->factory->get('entity_test_mulrev')
292 ->condition("$greetings.value", 'siema', 'STARTS_WITH')
293 ->sort('revision_id')
295 // Now we only get the ones that originally were siema, entity id 8 and
297 $this->assertIdentical($results, array_slice($assert, 4, 8, TRUE));
298 $results = $this->factory->get('entity_test_mulrev')
299 ->condition("$greetings.value", 'a', 'ENDS_WITH')
300 ->sort('revision_id')
302 // It is very important that we do not get the ones which only have
303 // xsiemax despite originally they were merhaba, ie. ended with a.
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')
309 ->sort('revision_id')
311 // Now we get everything.
312 $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'];
313 $this->assertIdentical($results, $assert);
319 * Warning: this is complicated.
321 public function testSort() {
322 $greetings = $this->greetings;
323 $figures = $this->figures;
324 // Order up and down on a number.
325 $this->queryResults = $this->factory->get('entity_test_mulrev')
328 $this->assertResult(range(1, 15));
329 $this->queryResults = $this->factory->get('entity_test_mulrev')
332 $this->assertResult(range(15, 1));
333 $query = $this->factory->get('entity_test_mulrev')
334 ->sort("$figures.color")
335 ->sort("$greetings.format")
337 // As we do not have any conditions, here are the possible colors and
338 // language codes, already in order, with the first occurrence of the
339 // entity id marked with *:
371 $count_query = clone $query;
372 $this->assertEqual(15, $count_query->count()->execute());
373 $this->queryResults = $query->execute();
374 $this->assertResult(8, 12, 4, 2, 3, 10, 11, 14, 15, 6, 7, 1, 9, 13, 5);
376 // Test the pager by setting element #1 to page 2 with a page size of 4.
377 // Results will be #8-12 from above.
378 $request = Request::createFromGlobals();
379 $request->query->replace([
382 \Drupal::getContainer()->get('request_stack')->push($request);
383 $this->queryResults = $this->factory->get('entity_test_mulrev')
384 ->sort("$figures.color")
385 ->sort("$greetings.format")
389 $this->assertResult(15, 6, 7, 1);
391 // Now test the reversed order.
392 $query = $this->factory->get('entity_test_mulrev')
393 ->sort("$figures.color", 'DESC')
394 ->sort("$greetings.format", 'DESC')
395 ->sort('id', 'DESC');
396 $count_query = clone $query;
397 $this->assertEqual(15, $count_query->count()->execute());
398 $this->queryResults = $query->execute();
399 $this->assertResult(15, 13, 7, 5, 11, 9, 3, 1, 14, 6, 10, 2, 12, 4, 8);
405 public function testTableSort() {
406 // While ordering on bundles do not give us a definite order, we can still
407 // assert that all entities from one bundle are after the other as the
409 $request = Request::createFromGlobals();
410 $request->query->replace([
414 \Drupal::getContainer()->get('request_stack')->push($request);
417 'id' => ['data' => 'Id', 'specifier' => 'id'],
418 'type' => ['data' => 'Type', 'specifier' => 'type'],
421 $this->queryResults = array_values($this->factory->get('entity_test_mulrev')
424 $this->assertBundleOrder('asc');
426 $request->query->add([
429 \Drupal::getContainer()->get('request_stack')->push($request);
432 'id' => ['data' => 'Id', 'specifier' => 'id'],
433 'type' => ['data' => 'Type', 'specifier' => 'type'],
435 $this->queryResults = array_values($this->factory->get('entity_test_mulrev')
438 $this->assertBundleOrder('desc');
440 // Ordering on ID is definite, however.
441 $request->query->add([
444 \Drupal::getContainer()->get('request_stack')->push($request);
445 $this->queryResults = $this->factory->get('entity_test_mulrev')
448 $this->assertResult(range(15, 1));
452 * Test that count queries are separated across entity types.
454 public function testCount() {
455 // Create a field with the same name in a different entity type.
456 $field_name = $this->figures;
457 $field_storage = FieldStorageConfig::create([
458 'field_name' => $field_name,
459 'entity_type' => 'entity_test',
462 'translatable' => TRUE,
464 $field_storage->save();
465 $bundle = $this->randomMachineName();
466 FieldConfig::create([
467 'field_storage' => $field_storage,
471 $entity = EntityTest::create([
475 $entity->enforceIsNew();
478 // As the single entity of this type we just saved does not have a value
479 // in the color field, the result should be 0.
480 $count = $this->factory->get('entity_test')
481 ->exists("$field_name.color")
484 $this->assertFalse($count);
488 * Tests that nested condition groups work as expected.
490 public function testNestedConditionGroups() {
491 // Query for all entities of the first bundle that have either a red
492 // triangle as a figure or the Turkish greeting as a greeting.
493 $query = $this->factory->get('entity_test_mulrev');
495 $first_and = $query->andConditionGroup()
496 ->condition($this->figures . '.color', 'red')
497 ->condition($this->figures . '.shape', 'triangle');
498 $second_and = $query->andConditionGroup()
499 ->condition($this->greetings . '.value', 'merhaba')
500 ->condition($this->greetings . '.format', 'format-tr');
502 $or = $query->orConditionGroup()
503 ->condition($first_and)
504 ->condition($second_and);
506 $this->queryResults = $query
508 ->condition('type', reset($this->bundles))
512 $this->assertResult(6, 14);
516 * Test queries with delta conditions.
518 public function testDelta() {
519 $figures = $this->figures;
520 // Test numeric delta value in field condition.
521 $this->queryResults = $this->factory->get('entity_test_mulrev')
522 ->condition("$figures.0.color", 'red')
525 // As unit 0 at delta 0 was the red triangle bit 0 needs to be set.
526 $this->assertResult(1, 3, 5, 7, 9, 11, 13, 15);
528 $this->queryResults = $this->factory->get('entity_test_mulrev')
529 ->condition("$figures.1.color", 'red')
532 // Delta 1 is not red.
533 $this->assertResult();
535 // Test on two different deltas.
536 $query = $this->factory->get('entity_test_mulrev');
537 $or = $query->andConditionGroup()
538 ->condition("$figures.0.color", 'red')
539 ->condition("$figures.1.color", 'blue');
540 $this->queryResults = $query
544 $this->assertResult(3, 7, 11, 15);
546 // Test the delta range condition.
547 $this->queryResults = $this->factory->get('entity_test_mulrev')
548 ->condition("$figures.%delta.color", ['blue', 'red'], 'IN')
549 ->condition("$figures.%delta", [0, 1], 'IN')
552 // Figure delta 0 or 1 can be blue or red, this matches a lot of entities.
553 $this->assertResult(1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15);
555 // Test the delta range condition without conditions on the value.
556 $this->queryResults = $this->factory->get('entity_test_mulrev')
557 ->condition("$figures.%delta", 1)
560 // Entity needs to have atleast two figures.
561 $this->assertResult(3, 7, 11, 15);
563 // Numeric delta on single value base field should return results only if
564 // the first item is being targeted.
565 $this->queryResults = $this->factory->get('entity_test_mulrev')
566 ->condition("id.0.value", [1, 3, 5], 'IN')
569 $this->assertResult(1, 3, 5);
570 $this->queryResults = $this->factory->get('entity_test_mulrev')
571 ->condition("id.1.value", [1, 3, 5], 'IN')
574 $this->assertResult();
576 // Delta range condition on single value base field should return results
577 // only if just the field value is targeted.
578 $this->queryResults = $this->factory->get('entity_test_mulrev')
579 ->condition("id.%delta.value", [1, 3, 5], 'IN')
582 $this->assertResult(1, 3, 5);
583 $this->queryResults = $this->factory->get('entity_test_mulrev')
584 ->condition("id.%delta.value", [1, 3, 5], 'IN')
585 ->condition("id.%delta", 0, '=')
588 $this->assertResult(1, 3, 5);
589 $this->queryResults = $this->factory->get('entity_test_mulrev')
590 ->condition("id.%delta.value", [1, 3, 5], 'IN')
591 ->condition("id.%delta", 1, '=')
594 $this->assertResult();
598 protected function assertResult() {
600 $expected = func_get_args();
601 if ($expected && is_array($expected[0])) {
602 $expected = $expected[0];
604 foreach ($expected as $binary) {
605 $assert[$binary] = strval($binary);
607 $this->assertIdentical($this->queryResults, $assert);
610 protected function assertRevisionResult($keys, $expected) {
612 foreach ($expected as $key => $binary) {
613 $assert[$keys[$key]] = strval($binary);
615 $this->assertIdentical($this->queryResults, $assert);
619 protected function assertBundleOrder($order) {
620 // This loop is for bundle1 entities.
621 for ($i = 1; $i <= 15; $i += 2) {
623 $index1 = array_search($i, $this->queryResults);
624 $this->assertNotIdentical($index1, FALSE, "$i found at $index1.");
625 // This loop is for bundle2 entities.
626 for ($j = 2; $j <= 15; $j += 2) {
628 if ($order == 'asc') {
629 $ok = $index1 > array_search($j, $this->queryResults);
632 $ok = $index1 < array_search($j, $this->queryResults);
636 $this->assertTrue($ok, "$i is after all entities in bundle2");
641 * Test adding a tag and metadata to the Entity query object.
643 * The tags and metadata should propagate to the SQL query object.
645 public function testMetaData() {
646 $query = \Drupal::entityQuery('entity_test_mulrev');
648 ->addTag('efq_metadata_test')
649 ->addMetaData('foo', 'bar')
652 global $efq_test_metadata;
653 $this->assertEqual($efq_test_metadata, 'bar', 'Tag and metadata propagated to the SQL query object.');
657 * Test case sensitive and in-sensitive query conditions.
659 public function testCaseSensitivity() {
660 $bundle = $this->randomMachineName();
662 $field_storage = FieldStorageConfig::create([
663 'field_name' => 'field_ci',
664 'entity_type' => 'entity_test_mulrev',
667 'translatable' => FALSE,
669 'case_sensitive' => FALSE,
672 $field_storage->save();
674 FieldConfig::create([
675 'field_storage' => $field_storage,
679 $field_storage = FieldStorageConfig::create([
680 'field_name' => 'field_cs',
681 'entity_type' => 'entity_test_mulrev',
684 'translatable' => FALSE,
686 'case_sensitive' => TRUE,
689 $field_storage->save();
691 FieldConfig::create([
692 'field_storage' => $field_storage,
698 for ($i = 0; $i < 2; $i++) {
699 // If the last 4 of the string are all numbers, then there is no
700 // difference between upper and lowercase and the case sensitive CONTAINS
701 // test will fail. Ensure that can not happen by appending a non-numeric
702 // character. See https://www.drupal.org/node/2397297.
703 $string = $this->randomMachineName(7) . 'a';
705 'original' => $string,
706 'uppercase' => Unicode::strtoupper($string),
707 'lowercase' => Unicode::strtolower($string),
711 EntityTestMulRev::create([
713 'name' => $this->randomMachineName(),
715 'field_ci' => $fixtures[0]['uppercase'] . $fixtures[1]['lowercase'],
716 'field_cs' => $fixtures[0]['uppercase'] . $fixtures[1]['lowercase']
719 // Check the case insensitive field, = operator.
720 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
721 'field_ci', $fixtures[0]['lowercase'] . $fixtures[1]['lowercase']
723 $this->assertIdentical(count($result), 1, 'Case insensitive, lowercase');
725 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
726 'field_ci', $fixtures[0]['uppercase'] . $fixtures[1]['uppercase']
728 $this->assertIdentical(count($result), 1, 'Case insensitive, uppercase');
730 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
731 'field_ci', $fixtures[0]['uppercase'] . $fixtures[1]['lowercase']
733 $this->assertIdentical(count($result), 1, 'Case insensitive, mixed.');
735 // Check the case sensitive field, = operator.
736 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
737 'field_cs', $fixtures[0]['lowercase'] . $fixtures[1]['lowercase']
739 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase.');
741 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
742 'field_cs', $fixtures[0]['uppercase'] . $fixtures[1]['uppercase']
744 $this->assertIdentical(count($result), 0, 'Case sensitive, uppercase.');
746 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
747 'field_cs', $fixtures[0]['uppercase'] . $fixtures[1]['lowercase']
749 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
751 // Check the case insensitive field, IN operator.
752 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
753 'field_ci', [$fixtures[0]['lowercase'] . $fixtures[1]['lowercase']], 'IN'
755 $this->assertIdentical(count($result), 1, 'Case insensitive, lowercase');
757 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
758 'field_ci', [$fixtures[0]['uppercase'] . $fixtures[1]['uppercase']], 'IN'
760 $this->assertIdentical(count($result), 1, 'Case insensitive, uppercase');
762 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
763 'field_ci', [$fixtures[0]['uppercase'] . $fixtures[1]['lowercase']], 'IN'
765 $this->assertIdentical(count($result), 1, 'Case insensitive, mixed');
767 // Check the case sensitive field, IN operator.
768 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
769 'field_cs', [$fixtures[0]['lowercase'] . $fixtures[1]['lowercase']], 'IN'
771 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase');
773 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
774 'field_cs', [$fixtures[0]['uppercase'] . $fixtures[1]['uppercase']], 'IN'
776 $this->assertIdentical(count($result), 0, 'Case sensitive, uppercase');
778 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
779 'field_cs', [$fixtures[0]['uppercase'] . $fixtures[1]['lowercase']], 'IN'
781 $this->assertIdentical(count($result), 1, 'Case sensitive, mixed');
783 // Check the case insensitive field, STARTS_WITH operator.
784 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
785 'field_ci', $fixtures[0]['lowercase'], 'STARTS_WITH'
787 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
789 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
790 'field_ci', $fixtures[0]['uppercase'], 'STARTS_WITH'
792 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
794 // Check the case sensitive field, STARTS_WITH operator.
795 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
796 'field_cs', $fixtures[0]['lowercase'], 'STARTS_WITH'
798 $this->assertIdentical(count($result), 0, 'Case sensitive, lowercase.');
800 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
801 'field_cs', $fixtures[0]['uppercase'], 'STARTS_WITH'
803 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
806 // Check the case insensitive field, ENDS_WITH operator.
807 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
808 'field_ci', $fixtures[1]['lowercase'], 'ENDS_WITH'
810 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
812 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
813 'field_ci', $fixtures[1]['uppercase'], 'ENDS_WITH'
815 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
817 // Check the case sensitive field, ENDS_WITH operator.
818 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
819 'field_cs', $fixtures[1]['lowercase'], 'ENDS_WITH'
821 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
823 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
824 'field_cs', $fixtures[1]['uppercase'], 'ENDS_WITH'
826 $this->assertIdentical(count($result), 0, 'Case sensitive, exact match.');
829 // Check the case insensitive field, CONTAINS operator, use the inner 8
830 // characters of the uppercase and lowercase strings.
831 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
832 'field_ci', Unicode::substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8), 'CONTAINS'
834 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
836 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
837 'field_ci', Unicode::strtolower(Unicode::substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8)), 'CONTAINS'
839 $this->assertIdentical(count($result), 1, 'Case sensitive, exact match.');
841 // Check the case sensitive field, CONTAINS operator.
842 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
843 'field_cs', Unicode::substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8), 'CONTAINS'
845 $this->assertIdentical(count($result), 1, 'Case sensitive, lowercase.');
847 $result = \Drupal::entityQuery('entity_test_mulrev')->condition(
848 'field_cs', Unicode::strtolower(Unicode::substr($fixtures[0]['uppercase'] . $fixtures[1]['lowercase'], 4, 8)), 'CONTAINS'
850 $this->assertIdentical(count($result), 0, 'Case sensitive, exact match.');
855 * Test base fields with multiple columns.
857 public function testBaseFieldMultipleColumns() {
858 $this->enableModules(['taxonomy']);
859 $this->installEntitySchema('taxonomy_term');
861 Vocabulary::create(['vid' => 'tags']);
863 $term1 = Term::create([
864 'name' => $this->randomMachineName(),
867 'value' => $this->randomString(),
868 'format' => 'format1',
872 $term2 = Term::create([
873 'name' => $this->randomMachineName(),
876 'value' => $this->randomString(),
877 'format' => 'format2',
881 $ids = \Drupal::entityQuery('taxonomy_term')
882 ->condition('description.format', 'format1')
885 $this->assertEqual(count($ids), 1);
886 $this->assertEqual($term1->id(), reset($ids));
890 * Test forward-revisions.
892 public function testForwardRevisions() {
893 // Ensure entity 14 is returned.
894 $result = \Drupal::entityQuery('entity_test_mulrev')
895 ->condition('id', [14], 'IN')
897 $this->assertEqual(count($result), 1);
899 // Set a revision on entity 14 that isn't the current default.
900 $entity = EntityTestMulRev::load(14);
901 $current_values = $entity->{$this->figures}->getValue();
903 $entity->setNewRevision(TRUE);
904 $entity->isDefaultRevision(FALSE);
905 $entity->{$this->figures}->setValue([
911 // Entity query should still return entity 14.
912 $result = \Drupal::entityQuery('entity_test_mulrev')
913 ->condition('id', [14], 'IN')
915 $this->assertEqual(count($result), 1);
917 // Verify that field conditions on the default and forward revision are
919 $result = \Drupal::entityQuery('entity_test_mulrev')
920 ->condition('id', [14], 'IN')
921 ->condition("$this->figures.color", $current_values[0]['color'])
923 $this->assertEqual($result, [14 => '14']);
924 $result = $this->factory->get('entity_test_mulrev')
925 ->condition('id', [14], 'IN')
926 ->condition("$this->figures.color", 'red')
929 $this->assertEqual($result, [16 => '14']);
933 * Test against SQL inject of condition field. This covers a
934 * database driver's EntityQuery\Condition class.
936 public function testInjectionInCondition() {
938 $this->queryResults = $this->factory->get('entity_test_mulrev')
939 ->condition('1 ; -- ', [0, 1], 'IN')
942 $this->fail('SQL Injection attempt in Entity Query condition in operator should result in an exception.');
944 catch (\Exception $e) {
945 $this->pass('SQL Injection attempt in Entity Query condition in operator should result in an exception.');