APIv4 - Move list of accepted query operators to CoreUtil
[civicrm-core.git] / tests / phpunit / api / v4 / Action / FkJoinTest.php
CommitLineData
19b53e5b
C
1<?php
2
380f3545
TO
3/*
4 +--------------------------------------------------------------------+
7d61e75f 5 | Copyright CiviCRM LLC. All rights reserved. |
380f3545 6 | |
7d61e75f
TO
7 | This work is published under the GNU AGPLv3 license with some |
8 | permitted exceptions and without any warranty. For full license |
9 | and copyright information, see https://civicrm.org/licensing |
380f3545
TO
10 +--------------------------------------------------------------------+
11 */
12
13/**
14 *
15 * @package CRM
ca5cec67 16 * @copyright CiviCRM LLC https://civicrm.org/licensing
380f3545
TO
17 */
18
19
19b53e5b
C
20namespace api\v4\Action;
21
22use api\v4\UnitTestCase;
23use Civi\Api4\Activity;
24use Civi\Api4\Contact;
16f5a13d 25use Civi\Api4\Email;
90908aac 26use Civi\Api4\EntityTag;
16f5a13d 27use Civi\Api4\Phone;
90908aac 28use Civi\Api4\Tag;
19b53e5b
C
29
30/**
31 * @group headless
32 */
33class FkJoinTest extends UnitTestCase {
34
35 public function setUpHeadless() {
36 $relatedTables = [
37 'civicrm_activity',
38 'civicrm_phone',
39 'civicrm_activity_contact',
40 ];
41 $this->cleanup(['tablesToTruncate' => $relatedTables]);
42 $this->loadDataSet('DefaultDataSet');
43
44 return parent::setUpHeadless();
45 }
46
47 /**
48 * Fetch all phone call activities. Expects a single activity
49 * loaded from the data set.
50 */
51 public function testThreeLevelJoin() {
fe806431 52 $results = Activity::get(FALSE)
340afbdf 53 ->addWhere('activity_type_id:name', '=', 'Phone Call')
19b53e5b
C
54 ->execute();
55
56 $this->assertCount(1, $results);
57 }
58
16f5a13d
CW
59 public function testOptionalJoin() {
60 // DefaultDataSet includes 2 phones for contact 1, 0 for contact 2.
61 // We'll add one for contact 2 as a red herring to make sure we only get back the correct ones.
fe806431 62 Phone::create(FALSE)
16f5a13d
CW
63 ->setValues(['contact_id' => $this->getReference('test_contact_2')['id'], 'phone' => '123456'])
64 ->execute();
fe806431 65 $contacts = Contact::get(FALSE)
16f5a13d
CW
66 ->addJoin('Phone', FALSE)
67 ->addSelect('id', 'phone.phone')
68 ->addWhere('id', 'IN', [$this->getReference('test_contact_1')['id']])
69 ->addOrderBy('phone.id')
70 ->execute();
71 $this->assertCount(2, $contacts);
72 $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[0]['id']);
73 $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[1]['id']);
74 }
75
76 public function testRequiredJoin() {
77 // Joining with no condition
fe806431 78 $contacts = Contact::get(FALSE)
16f5a13d
CW
79 ->addSelect('id', 'phone.phone')
80 ->addJoin('Phone', TRUE)
81 ->addWhere('id', 'IN', [$this->getReference('test_contact_1')['id'], $this->getReference('test_contact_2')['id']])
82 ->addOrderBy('phone.id')
83 ->execute();
84 $this->assertCount(2, $contacts);
85 $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[0]['id']);
86 $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[1]['id']);
87
88 // Add is_primary condition, should result in only one record
fe806431 89 $contacts = Contact::get(FALSE)
16f5a13d
CW
90 ->addSelect('id', 'phone.phone', 'phone.location_type_id')
91 ->addJoin('Phone', TRUE, ['phone.is_primary', '=', TRUE])
92 ->addWhere('id', 'IN', [$this->getReference('test_contact_1')['id'], $this->getReference('test_contact_2')['id']])
93 ->addOrderBy('phone.id')
94 ->execute();
95 $this->assertCount(1, $contacts);
96 $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[0]['id']);
97 $this->assertEquals('+35355439483', $contacts[0]['phone.phone']);
98 $this->assertEquals('1', $contacts[0]['phone.location_type_id']);
99 }
100
101 public function testJoinToTheSameTableTwice() {
fe806431 102 $cid1 = Contact::create(FALSE)
16f5a13d
CW
103 ->addValue('first_name', 'Aaa')
104 ->addChain('email1', Email::create()->setValues(['email' => 'yoohoo@yahoo.test', 'contact_id' => '$id', 'location_type_id:name' => 'Home']))
105 ->addChain('email2', Email::create()->setValues(['email' => 'yahoo@yoohoo.test', 'contact_id' => '$id', 'location_type_id:name' => 'Work']))
106 ->execute()
107 ->first()['id'];
108
fe806431 109 $cid2 = Contact::create(FALSE)
16f5a13d
CW
110 ->addValue('first_name', 'Bbb')
111 ->addChain('email1', Email::create()->setValues(['email' => '1@test.test', 'contact_id' => '$id', 'location_type_id:name' => 'Home']))
112 ->addChain('email2', Email::create()->setValues(['email' => '2@test.test', 'contact_id' => '$id', 'location_type_id:name' => 'Work']))
113 ->addChain('email3', Email::create()->setValues(['email' => '3@test.test', 'contact_id' => '$id', 'location_type_id:name' => 'Other']))
114 ->execute()
115 ->first()['id'];
116
fe806431 117 $cid3 = Contact::create(FALSE)
16f5a13d
CW
118 ->addValue('first_name', 'Ccc')
119 ->execute()
120 ->first()['id'];
121
fe806431 122 $contacts = Contact::get(FALSE)
16f5a13d 123 ->addSelect('id', 'first_name', 'any_email.email', 'any_email.location_type_id:name', 'any_email.is_primary', 'primary_email.email')
90908aac
CW
124 ->setJoin([
125 ['Email AS any_email', TRUE, NULL],
126 ['Email AS primary_email', FALSE, ['primary_email.is_primary', '=', TRUE]],
127 ])
16f5a13d
CW
128 ->addWhere('id', 'IN', [$cid1, $cid2, $cid3])
129 ->addOrderBy('any_email.id')
130 ->setDebug(TRUE)
131 ->execute();
132 $this->assertCount(5, $contacts);
133 $this->assertEquals('Home', $contacts[0]['any_email.location_type_id:name']);
134 $this->assertEquals('yoohoo@yahoo.test', $contacts[1]['primary_email.email']);
135 $this->assertEquals('1@test.test', $contacts[2]['primary_email.email']);
136 $this->assertEquals('1@test.test', $contacts[3]['primary_email.email']);
137 $this->assertEquals('1@test.test', $contacts[4]['primary_email.email']);
138 }
139
90908aac
CW
140 public function testBridgeJoinTags() {
141 $tag1 = Tag::create()->setCheckPermissions(FALSE)
142 ->addValue('name', uniqid('join1'))
143 ->execute()
144 ->first()['name'];
145 $tag2 = Tag::create()->setCheckPermissions(FALSE)
146 ->addValue('name', uniqid('join2'))
147 ->execute()
148 ->first()['name'];
149 $tag3 = Tag::create()->setCheckPermissions(FALSE)
150 ->addValue('name', uniqid('join3'))
151 ->execute()
152 ->first()['name'];
153
154 $cid1 = Contact::create()->setCheckPermissions(FALSE)
155 ->addValue('first_name', 'Aaa')
156 ->addChain('tag1', EntityTag::create()->setValues(['entity_id' => '$id', 'tag_id:name' => $tag1]))
157 ->addChain('tag2', EntityTag::create()->setValues(['entity_id' => '$id', 'tag_id:name' => $tag2]))
158 ->execute()
159 ->first()['id'];
160 $cid2 = Contact::create()->setCheckPermissions(FALSE)
161 ->addValue('first_name', 'Bbb')
162 ->addChain('tag1', EntityTag::create()->setValues(['entity_id' => '$id', 'tag_id:name' => $tag1]))
163 ->addChain('tag3', EntityTag::create()->setValues(['entity_id' => '$id', 'tag_id:name' => $tag3]))
164 ->execute()
165 ->first()['id'];
166 $cid3 = Contact::create()->setCheckPermissions(FALSE)
167 ->addValue('first_name', 'Ccc')
168 ->execute()
169 ->first()['id'];
170
171 $required = Contact::get()->setCheckPermissions(FALSE)
172 ->addJoin('Tag', TRUE, 'EntityTag')
173 ->addSelect('first_name', 'tag.name')
174 ->addWhere('id', 'IN', [$cid1, $cid2, $cid3])
175 ->execute();
176 $this->assertCount(4, $required);
177
178 $optional = Contact::get()->setCheckPermissions(FALSE)
179 ->addJoin('Tag', FALSE, 'EntityTag', ['tag.name', 'IN', [$tag1, $tag2, $tag3]])
180 ->addSelect('first_name', 'tag.name')
181 ->addWhere('id', 'IN', [$cid1, $cid2, $cid3])
182 ->execute();
183 $this->assertCount(5, $optional);
184
185 $grouped = Contact::get()->setCheckPermissions(FALSE)
186 ->addJoin('Tag', FALSE, 'EntityTag', ['tag.name', 'IN', [$tag1, $tag3]])
187 ->addSelect('first_name', 'COUNT(tag.name) AS tags')
188 ->addWhere('id', 'IN', [$cid1, $cid2, $cid3])
189 ->addGroupBy('id')
190 ->execute()->indexBy('id');
191 $this->assertEquals(1, (int) $grouped[$cid1]['tags']);
192 $this->assertEquals(2, (int) $grouped[$cid2]['tags']);
193 $this->assertEquals(0, (int) $grouped[$cid3]['tags']);
194
195 $reverse = Tag::get()->setCheckPermissions(FALSE)
196 ->addJoin('Contact', FALSE, 'EntityTag', ['contact.id', 'IN', [$cid1, $cid2, $cid3]])
197 ->addGroupBy('id')
198 ->addSelect('name', 'COUNT(contact.id) AS contacts')
199 ->execute()->indexBy('name');
200 $this->assertEquals(2, (int) $reverse[$tag1]['contacts']);
201 $this->assertEquals(1, (int) $reverse[$tag2]['contacts']);
202 $this->assertEquals(1, (int) $reverse[$tag3]['contacts']);
203 }
204
19b53e5b 205}