Commit | Line | Data |
---|---|---|
2fe91f9d | 1 | <?php |
0eea664b | 2 | |
2fe91f9d | 3 | /** |
4 | * Include dataProvider for tests | |
acb109b7 | 5 | * @group headless |
2fe91f9d | 6 | */ |
7 | class CRM_Core_BAO_CustomQueryTest extends CiviUnitTestCase { | |
0e1544e7 | 8 | use CRMTraits_Custom_CustomDataTrait; |
2fe91f9d | 9 | |
10 | /** | |
11 | * Restore database to empty state. | |
12 | * | |
13 | * Note that rollback won't remove custom tables. | |
14 | * | |
15 | * @throws \Exception | |
16 | */ | |
17 | public function tearDown() { | |
9099cab3 | 18 | $tablesToTruncate = [ |
2fe91f9d | 19 | 'civicrm_contact', |
9099cab3 | 20 | ]; |
2fe91f9d | 21 | $this->quickCleanup($tablesToTruncate, TRUE); |
22 | parent::tearDown(); | |
23 | } | |
24 | ||
25 | /** | |
26 | * Test filtering by relative custom data dates. | |
0e1544e7 | 27 | * |
28 | * @throws \CRM_Core_Exception | |
2fe91f9d | 29 | */ |
30 | public function testSearchCustomDataDateRelative() { | |
31 | $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTestTest'); | |
9099cab3 | 32 | $dateCustomField = $this->customFieldCreate([ |
2fe91f9d | 33 | 'custom_group_id' => $ids['custom_group_id'], |
34 | 'label' => 'date field', | |
35 | 'data_type' => 'Date', | |
36 | 'html_type' => 'Select Date', | |
37 | 'default_value' => NULL, | |
9099cab3 | 38 | ]); |
2fe91f9d | 39 | $dateCustomFieldName = 'custom_' . $dateCustomField['id']; |
9099cab3 | 40 | $formValues = [ |
2fe91f9d | 41 | $dateCustomFieldName . '_relative' => 'this.year', |
42 | $dateCustomFieldName . '_from' => '', | |
43 | $dateCustomFieldName . '_to' => '', | |
9099cab3 | 44 | ]; |
2fe91f9d | 45 | // Assigning the relevant form value to be within a custom key is normally done in |
46 | // build field params. It would be better if it were all done in convertFormValues | |
47 | // but for now we just imitate it. | |
7f175707 | 48 | |
49 | $params = CRM_Contact_BAO_Query::convertFormValues($formValues); | |
50 | $queryObj = new CRM_Contact_BAO_Query($params); | |
2fe91f9d | 51 | $this->assertEquals( |
7f175707 | 52 | "civicrm_value_testsearchcus_1.date_field_2 BETWEEN '" . date('Y') . "0101000000' AND '" . date('Y') . "1231235959'", |
2fe91f9d | 53 | $queryObj->_where[0][0] |
54 | ); | |
cc3f334a | 55 | $this->assertEquals('date field is This calendar year (between January 1st, ' . date('Y') . " 12:00 AM and December 31st, " . date('Y') . " 11:59 PM)", $queryObj->_qill[0][0]); |
56 | $queryObj = new CRM_Contact_BAO_Query($params); | |
acd6c6ab | 57 | $this->assertEquals([ |
58 | 'id' => $dateCustomField['id'], | |
59 | 'label' => 'date field', | |
1f61a7b1 | 60 | 'extends' => 'Contact', |
acd6c6ab | 61 | 'data_type' => 'Date', |
62 | 'html_type' => 'Select Date', | |
63 | 'is_search_range' => '0', | |
64 | 'column_name' => 'date_field_' . $dateCustomField['id'], | |
65 | 'table_name' => 'civicrm_value_testsearchcus_' . $ids['custom_group_id'], | |
66 | 'option_group_id' => NULL, | |
1f61a7b1 | 67 | 'groupTitle' => 'testSearchCustomDataDateRelative', |
68 | 'default_value' => NULL, | |
69 | 'text_length' => NULL, | |
70 | 'options_per_line' => NULL, | |
71 | 'custom_group_id' => '1', | |
72 | 'extends_entity_column_value' => NULL, | |
73 | 'extends_entity_column_id' => NULL, | |
74 | 'is_view' => '0', | |
75 | 'is_multiple' => '0', | |
76 | 'date_format' => 'mm/dd/yy', | |
77 | 'time_format' => NULL, | |
78 | 'is_required' => '0', | |
79 | 'extends_table' => 'civicrm_contact', | |
80 | 'search_table' => 'contact_a', | |
cef2e96c | 81 | 'headerPattern' => '//', |
82 | 'title' => 'date field', | |
83 | 'custom_field_id' => $dateCustomField['id'], | |
84 | 'name' => 'custom_' . $dateCustomField['id'], | |
85 | 'type' => 4, | |
86 | 'where' => 'civicrm_value_testsearchcus_' . $ids['custom_group_id'] . '.date_field_' . $dateCustomField['id'], | |
cc3f334a | 87 | 'import' => 1, |
88 | ], $queryObj->getFieldSpec('custom_' . $dateCustomField['id'])); | |
acd6c6ab | 89 | |
2fe91f9d | 90 | } |
91 | ||
2206409b | 92 | /** |
93 | * Test filtering by the renamed custom date fields. | |
94 | * | |
95 | * The conversion to date picker will result int these fields | |
96 | * being renamed _high & _low and needing to return correctly. | |
97 | * | |
98 | * @throws \CRM_Core_Exception | |
99 | */ | |
100 | public function testSearchCustomDataDateHighLow() { | |
101 | $this->createCustomGroupWithFieldOfType([], 'date'); | |
102 | $dateCustomFieldName = $this->getCustomFieldName('date'); | |
103 | // Assigning the relevant form value to be within a custom key is normally done in | |
104 | // build field params. It would be better if it were all done in convertFormValues | |
105 | // but for now we just imitate it. | |
106 | $formValues = [ | |
107 | $dateCustomFieldName . '_low' => '2014-06-06', | |
108 | $dateCustomFieldName . '_high' => '2015-06-06', | |
109 | ]; | |
110 | ||
111 | $params = CRM_Contact_BAO_Query::convertFormValues($formValues); | |
112 | $queryObject = new CRM_Contact_BAO_Query($params); | |
113 | $queryObject->query(); | |
114 | $this->assertEquals( | |
115 | '( civicrm_value_group_with_fi_1.' . $this->getCustomFieldColumnName('date') . ' >= \'20140606000000\' ) AND | |
116 | ( civicrm_value_group_with_fi_1.' . $this->getCustomFieldColumnName('date') . ' <= \'20150606235959\' )', | |
117 | trim($queryObject->_where[0][0]) | |
118 | ); | |
119 | $this->assertEquals('Test Date - greater than or equal to "June 6th, 2014 12:00 AM" AND less than or equal to "June 6th, 2015 11:59 PM"', $queryObject->_qill[0][0]); | |
120 | $this->assertEquals(1, $queryObject->_whereTables['civicrm_contact']); | |
121 | $this->assertEquals('LEFT JOIN ' . $this->getCustomGroupTable() . ' ON ' . $this->getCustomGroupTable() . '.entity_id = `contact_a`.id', trim($queryObject->_whereTables[$this->getCustomGroupTable()])); | |
122 | } | |
123 | ||
56d1630d | 124 | /** |
125 | * Test filtering by the renamed custom date fields. | |
126 | * | |
127 | * The conversion to date picker will result int these fields | |
128 | * being renamed _high & _low and needing to return correctly. | |
129 | * | |
130 | * @throws \CRM_Core_Exception | |
131 | */ | |
132 | public function testSearchCustomDataDateLowWithPermsInPlay() { | |
133 | $this->createLoggedInUser(); | |
134 | CRM_Core_Config::singleton()->userPermissionClass->permissions = ['view all contacts', 'access all custom data']; | |
135 | $this->createCustomGroupWithFieldOfType([], 'date'); | |
136 | $dateCustomFieldName = $this->getCustomFieldName('date'); | |
137 | // Assigning the relevant form value to be within a custom key is normally done in | |
138 | // build field params. It would be better if it were all done in convertFormValues | |
139 | // but for now we just imitate it. | |
140 | $formValues = [ | |
141 | $dateCustomFieldName . '_low' => '2014-06-06', | |
142 | ]; | |
143 | ||
144 | $params = CRM_Contact_BAO_Query::convertFormValues($formValues); | |
145 | $queryObject = new CRM_Contact_BAO_Query($params); | |
146 | $queryObject->query(); | |
147 | $this->assertEquals( | |
148 | 'civicrm_value_group_with_fi_1.' . $this->getCustomFieldColumnName('date') . ' >= \'20140606000000\'', | |
149 | trim($queryObject->_where[0][0]) | |
150 | ); | |
151 | $this->assertEquals( | |
152 | 'FROM civicrm_contact contact_a LEFT JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id AND civicrm_address.is_primary = 1 ) LEFT JOIN civicrm_country ON ( civicrm_address.country_id = civicrm_country.id ) LEFT JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1) LEFT JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id AND civicrm_phone.is_primary = 1) LEFT JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id AND civicrm_im.is_primary = 1) LEFT JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id | |
153 | LEFT JOIN ' . $this->getCustomGroupTable() . ' ON ' . $this->getCustomGroupTable() . '.entity_id = `contact_a`.id', | |
154 | trim($queryObject->_fromClause) | |
155 | ); | |
156 | $this->assertEquals('Test Date - greater than or equal to "June 6th, 2014 12:00 AM"', $queryObject->_qill[0][0]); | |
157 | $this->assertEquals(1, $queryObject->_whereTables['civicrm_contact']); | |
158 | $this->assertEquals('LEFT JOIN ' . $this->getCustomGroupTable() . ' ON ' . $this->getCustomGroupTable() . '.entity_id = `contact_a`.id', trim($queryObject->_whereTables[$this->getCustomGroupTable()])); | |
159 | } | |
160 | ||
2fe91f9d | 161 | /** |
162 | * Test filtering by relative custom data dates. | |
0e1544e7 | 163 | * |
164 | * @throws \CRM_Core_Exception | |
2fe91f9d | 165 | */ |
166 | public function testSearchCustomDataDateFromTo() { | |
167 | $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTestTest'); | |
9099cab3 | 168 | $dateCustomField = $this->customFieldCreate([ |
2fe91f9d | 169 | 'custom_group_id' => $ids['custom_group_id'], |
170 | 'label' => 'date field', | |
171 | 'data_type' => 'Date', | |
172 | 'html_type' => 'Select Date', | |
173 | 'default_value' => NULL, | |
9099cab3 | 174 | ]); |
2fe91f9d | 175 | $dateCustomFieldName = 'custom_' . $dateCustomField['id']; |
176 | // Assigning the relevant form value to be within a custom key is normally done in | |
177 | // build field params. It would be better if it were all done in convertFormValues | |
178 | // but for now we just imitate it. | |
9099cab3 | 179 | $formValues = [ |
2fe91f9d | 180 | $dateCustomFieldName . '_from' => '2014-06-06', |
181 | $dateCustomFieldName . '_to' => '2015-06-06', | |
9099cab3 | 182 | ]; |
2fe91f9d | 183 | |
cc3f334a | 184 | $params = CRM_Contact_BAO_Query::convertFormValues($formValues); |
185 | $queryObj = new CRM_Contact_BAO_Query($params); | |
0e1544e7 | 186 | $queryObj->query(); |
2fe91f9d | 187 | $this->assertEquals( |
188 | 'civicrm_value_testsearchcus_1.date_field_2 BETWEEN "20140606000000" AND "20150606235959"', | |
189 | $queryObj->_where[0][0] | |
190 | ); | |
191 | $this->assertEquals($queryObj->_qill[0][0], "date field BETWEEN 'June 6th, 2014 12:00 AM AND June 6th, 2015 11:59 PM'"); | |
c65ec456 JP |
192 | |
193 | //CRM-17236 - Test custom date is correctly displayed without time. | |
194 | $formattedValue = CRM_Core_BAO_CustomField::displayValue(date('Ymdhms'), $dateCustomField['id']); | |
195 | $this->assertEquals(date('m/d/Y'), $formattedValue); | |
2fe91f9d | 196 | } |
197 | ||
198 | /** | |
199 | * Test filtering by relative custom data. | |
cc3f334a | 200 | * |
201 | * @throws \CRM_Core_Exception | |
2fe91f9d | 202 | */ |
203 | public function testSearchCustomDataFromTo() { | |
204 | $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTestTest'); | |
9099cab3 | 205 | $datas = [ |
2fe91f9d | 206 | 'Int' => 2, |
207 | 'Float' => 12.123, | |
208 | 'Money' => 91.21, | |
9099cab3 | 209 | ]; |
2fe91f9d | 210 | foreach ($datas as $type => $data) { |
211 | $customField = $this->customFieldCreate( | |
9099cab3 | 212 | [ |
2fe91f9d | 213 | 'custom_group_id' => $ids['custom_group_id'], |
214 | 'label' => "$type field", | |
215 | 'data_type' => $type, | |
216 | 'html_type' => 'Text', | |
217 | 'default_value' => NULL, | |
9099cab3 | 218 | ] |
2fe91f9d | 219 | ); |
220 | $customFieldName = 'custom_' . $customField['id']; | |
221 | // Assigning the relevant form value to be within a custom key is normally done in | |
222 | // build field params. It would be better if it were all done in convertFormValues | |
223 | // but for now we just imitate it. | |
224 | $from = $data - 1; | |
225 | $to = $data; | |
9099cab3 | 226 | $formValues = [ |
2fe91f9d | 227 | $customFieldName . '_from' => $from, |
228 | $customFieldName . '_to' => $to, | |
9099cab3 | 229 | ]; |
2fe91f9d | 230 | |
cc3f334a | 231 | $params = CRM_Contact_BAO_Query::convertFormValues($formValues); |
232 | $queryObj = new CRM_Contact_BAO_Query($params); | |
0e1544e7 | 233 | $queryObj->query(); |
2fe91f9d | 234 | $this->assertEquals( |
cc3f334a | 235 | 'civicrm_value_testsearchcus_1.' . strtolower($type) . "_field_{$customField['id']} BETWEEN \"$from\" AND \"$to\"", |
2fe91f9d | 236 | $queryObj->_where[0][0] |
237 | ); | |
238 | $this->assertEquals($queryObj->_qill[0][0], "$type field BETWEEN $from, $to"); | |
239 | } | |
240 | } | |
241 | ||
242 | /** | |
243 | * Test filtering by relative custom data. | |
cc3f334a | 244 | * |
245 | * @throws \CRM_Core_Exception | |
2fe91f9d | 246 | */ |
247 | public function testSearchCustomDataFromAndTo() { | |
248 | $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTestTest'); | |
b23b546c | 249 | $dataSet = [ |
250 | 'Date' => ['value' => '2015-06-06', 'sql_string' => '"20150606235959"', 'qill_string' => "'June 6th, 2015 11:59 PM'", 'qill_string_greater' => "'June 6th, 2015 12:00 AM'"], | |
251 | // @todo - investigate the impact of using quotes on what should be an integer field. | |
252 | 'Int' => ['value' => 2, 'sql_string' => '"2"'], | |
253 | 'Float' => ['value' => 12.123, 'sql_string' => '"12.123"'], | |
254 | 'Money' => ['value' => 91.21], | |
9099cab3 | 255 | ]; |
b23b546c | 256 | foreach ($dataSet as $type => $values) { |
257 | $data = $values['value']; | |
2fe91f9d | 258 | $isDate = ($type === 'Date'); |
259 | $customField = $this->customFieldCreate( | |
9099cab3 | 260 | [ |
2fe91f9d | 261 | 'custom_group_id' => $ids['custom_group_id'], |
262 | 'label' => "$type field", | |
263 | 'data_type' => $type, | |
264 | 'html_type' => ($isDate) ? 'Select Date' : 'Text', | |
265 | 'default_value' => NULL, | |
9099cab3 | 266 | ] |
2fe91f9d | 267 | ); |
268 | $customFieldName = 'custom_' . $customField['id']; | |
269 | ||
b23b546c | 270 | $expectedValue = $values['sql_string'] ?? $data; |
271 | $expectedQillValue = $values['qill_string'] ?? $data; | |
272 | $toQillValue = chr(226) . chr(137) . chr(164) . ' ' . $expectedQillValue; | |
273 | $fromQillValue = chr(226) . chr(137) . chr(165) . ' ' . ($values['qill_string_greater'] ?? $expectedQillValue); | |
2fe91f9d | 274 | |
275 | // Assigning the relevant form value to be within a custom key is normally done in | |
276 | // build field params. It would be better if it were all done in convertFormValues | |
277 | // but for now we just imitate it. | |
278 | ||
b23b546c | 279 | //Scenario 2 : TO date filter |
9099cab3 | 280 | $formValues = [ |
2fe91f9d | 281 | $customFieldName . '_to' => $data, |
9099cab3 | 282 | ]; |
2fe91f9d | 283 | |
cc3f334a | 284 | $params = CRM_Contact_BAO_Query::convertFormValues($formValues); |
285 | $queryObj = new CRM_Contact_BAO_Query($params); | |
0e1544e7 | 286 | $queryObj->query(); |
2fe91f9d | 287 | |
288 | $this->assertEquals( | |
b23b546c | 289 | 'civicrm_value_testsearchcus_1.' . strtolower($type) . "_field_{$customField['id']} <= $expectedValue", |
2fe91f9d | 290 | $queryObj->_where[0][0] |
291 | ); | |
292 | $this->assertEquals($queryObj->_qill[0][0], | |
b23b546c | 293 | "$type field $toQillValue" |
2fe91f9d | 294 | ); |
295 | ||
b23b546c | 296 | //Scenario 2 : FROM date filter |
9099cab3 | 297 | $formValues = [ |
b23b546c | 298 | $customFieldName . '_from' => $values['value'], |
9099cab3 | 299 | ]; |
2fe91f9d | 300 | |
cc3f334a | 301 | $params = CRM_Contact_BAO_Query::convertFormValues($formValues); |
302 | $queryObj = new CRM_Contact_BAO_Query($params); | |
0e1544e7 | 303 | $queryObj->query(); |
2fe91f9d | 304 | |
305 | $expectedValue = ($isDate) ? '"20150606000000"' : $expectedValue; | |
2fe91f9d | 306 | $this->assertEquals( |
b23b546c | 307 | 'civicrm_value_testsearchcus_1.' . strtolower($type) . "_field_{$customField['id']} >= $expectedValue", |
2fe91f9d | 308 | $queryObj->_where[0][0] |
309 | ); | |
b23b546c | 310 | $this->assertEquals( |
311 | "$type field $fromQillValue", | |
312 | $queryObj->_qill[0][0] | |
2fe91f9d | 313 | ); |
314 | } | |
315 | } | |
316 | ||
317 | /** | |
318 | * Test filtering by relative custom data dates. | |
0e1544e7 | 319 | * |
320 | * @throws \CRM_Core_Exception | |
2fe91f9d | 321 | */ |
322 | public function testSearchCustomDataDateEquals() { | |
323 | $ids = $this->entityCustomGroupWithSingleFieldCreate(__FUNCTION__, 'ContactTestTest'); | |
9099cab3 | 324 | $dateCustomField = $this->customFieldCreate([ |
2fe91f9d | 325 | 'custom_group_id' => $ids['custom_group_id'], |
326 | 'label' => 'date field', | |
327 | 'data_type' => 'Date', | |
328 | 'html_type' => 'Select Date', | |
329 | 'default_value' => NULL, | |
9099cab3 | 330 | ]); |
2fe91f9d | 331 | $dateCustomFieldName = 'custom_' . $dateCustomField['id']; |
9099cab3 | 332 | $this->individualCreate([$dateCustomFieldName => "2015-01-01"]); |
2fe91f9d | 333 | // Assigning the relevant form value to be within a custom key is normally done in |
334 | // build field params. It would be better if it were all done in convertFormValues | |
335 | // but for now we just imitate it. | |
9099cab3 | 336 | $formValues = [$dateCustomFieldName => '2015-06-06']; |
cc3f334a | 337 | $params = CRM_Contact_BAO_Query::convertFormValues($formValues); |
338 | $queryObj = new CRM_Contact_BAO_Query($params); | |
0e1544e7 | 339 | $queryObj->query(); |
2fe91f9d | 340 | |
341 | $this->assertEquals( | |
342 | "civicrm_value_testsearchcus_1.date_field_2 = '2015-06-06'", | |
343 | $queryObj->_where[0][0] | |
344 | ); | |
345 | $this->assertEquals($queryObj->_qill[0][0], "date field = 'June 6th, 2015'"); | |
346 | } | |
347 | ||
0e1544e7 | 348 | /** |
349 | * Test search builder style query including custom address fields. | |
350 | * | |
351 | * @throws \CRM_Core_Exception | |
352 | */ | |
353 | public function testAddressCustomFields() { | |
354 | $this->createCustomGroupWithFieldOfType(['extends' => 'Address'], 'int'); | |
355 | $individualID = $this->individualCreate(); | |
356 | $this->callAPISuccess('Address', 'create', [ | |
357 | 'contact_id' => $individualID, | |
358 | 'street_address' => '10 Downing Street', | |
359 | 'location_type_id' => 'Home', | |
360 | $this->getCustomFieldName('int') => 5, | |
361 | ]); | |
362 | ||
363 | $queryObject = new CRM_Contact_BAO_Query( | |
364 | [[$this->getCustomFieldName('int') . '-1', '=', 5, 1, 0]], | |
365 | ['contact_type' => 1, 'location' => ['Home' => ['location_type' => 1, $this->getCustomFieldName('int') => 1]]] | |
366 | ); | |
367 | $queryObject->query(); | |
368 | $tableName = $this->getCustomGroupTable(); | |
369 | $fieldName = $this->getCustomFieldColumnName('int'); | |
370 | ||
371 | $this->assertEquals([], $queryObject->_where[0]); | |
372 | $this->assertEquals($tableName . '.' . $fieldName . ' = 5', implode(', ', $queryObject->_where[1])); | |
373 | $this->assertEquals(1, $queryObject->_whereTables['civicrm_contact']); | |
374 | $this->assertEquals('LEFT JOIN civicrm_address `Home-address` ON (`Home-address`.contact_id = contact_a.id AND `Home-address`.location_type_id = 1)', trim($queryObject->_whereTables['Home-address'])); | |
375 | $this->assertEquals("LEFT JOIN {$tableName} ON {$tableName}.entity_id = `Home-address`.id", trim($queryObject->_whereTables[$tableName])); | |
376 | $this->assertEquals([], $queryObject->_qill[0]); | |
377 | $this->assertEquals(['Enter integer here = 5'], $queryObject->_qill[1]); | |
378 | } | |
379 | ||
2fe91f9d | 380 | } |