Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
16 | */ |
17 | class CRM_Contact_BAO_Contact_Utils { | |
18 | ||
19 | /** | |
67d19299 | 20 | * Given a contact type, get the contact image. |
6a488035 | 21 | * |
77c5b619 TO |
22 | * @param string $contactType |
23 | * Contact type. | |
24 | * @param bool $urlOnly | |
25 | * If we need to return only image url. | |
26 | * @param int $contactId | |
27 | * Contact id. | |
28 | * @param bool $addProfileOverlay | |
29 | * If profile overlay class should be added. | |
6a488035 TO |
30 | * |
31 | * @return string | |
0d32dc8c | 32 | * @throws \CRM_Core_Exception |
6a488035 | 33 | */ |
00be9182 | 34 | public static function getImage($contactType, $urlOnly = FALSE, $contactId = NULL, $addProfileOverlay = TRUE) { |
be2fb01f | 35 | static $imageInfo = []; |
6a488035 | 36 | |
7a0bea5c | 37 | $contactType = CRM_Utils_Array::explodePadded($contactType); |
6a488035 TO |
38 | $contactType = $contactType[0]; |
39 | ||
40 | if (!array_key_exists($contactType, $imageInfo)) { | |
be2fb01f | 41 | $imageInfo[$contactType] = []; |
6a488035 | 42 | |
be2fb01f CW |
43 | $typeInfo = []; |
44 | $params = ['name' => $contactType]; | |
6a488035 TO |
45 | CRM_Contact_BAO_ContactType::retrieve($params, $typeInfo); |
46 | ||
a7488080 | 47 | if (!empty($typeInfo['image_URL'])) { |
6a488035 TO |
48 | $imageUrl = $typeInfo['image_URL']; |
49 | $config = CRM_Core_Config::singleton(); | |
50 | ||
51 | if (!preg_match("/^(\/|(http(s)?:)).+$/i", $imageUrl)) { | |
52 | $imageUrl = $config->resourceBase . $imageUrl; | |
53 | } | |
54 | $imageInfo[$contactType]['image'] = "<div class=\"icon crm-icon {$typeInfo['name']}-icon\" style=\"background: url('{$imageUrl}')\" title=\"{$contactType}\"></div>"; | |
55 | $imageInfo[$contactType]['url'] = $imageUrl; | |
56 | } | |
57 | else { | |
58 | $isSubtype = (array_key_exists('parent_id', $typeInfo) && | |
59 | $typeInfo['parent_id'] | |
60 | ) ? TRUE : FALSE; | |
61 | ||
62 | if ($isSubtype) { | |
63 | $type = CRM_Contact_BAO_ContactType::getBasicType($typeInfo['name']) . '-subtype'; | |
64 | } | |
65 | else { | |
66 | $type = CRM_Utils_Array::value('name', $typeInfo); | |
67 | } | |
68 | ||
69 | // do not add title since it hides contact name | |
70 | if ($addProfileOverlay) { | |
71 | $imageInfo[$contactType]['image'] = "<div class=\"icon crm-icon {$type}-icon\"></div>"; | |
72 | } | |
92e4c2a5 | 73 | else { |
6a488035 TO |
74 | $imageInfo[$contactType]['image'] = "<div class=\"icon crm-icon {$type}-icon\" title=\"{$contactType}\"></div>"; |
75 | } | |
76 | $imageInfo[$contactType]['url'] = NULL; | |
77 | } | |
78 | } | |
79 | ||
80 | if ($addProfileOverlay) { | |
81 | static $summaryOverlayProfileId = NULL; | |
82 | if (!$summaryOverlayProfileId) { | |
83 | $summaryOverlayProfileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', 'summary_overlay', 'id', 'name'); | |
84 | } | |
85 | ||
86 | $profileURL = CRM_Utils_System::url('civicrm/profile/view', | |
87 | "reset=1&gid={$summaryOverlayProfileId}&id={$contactId}&snippet=4" | |
88 | ); | |
89 | ||
90 | $imageInfo[$contactType]['summary-link'] = '<a href="' . $profileURL . '" class="crm-summary-link">' . $imageInfo[$contactType]['image'] . '</a>'; | |
91 | } | |
92 | else { | |
93 | $imageInfo[$contactType]['summary-link'] = $imageInfo[$contactType]['image']; | |
94 | } | |
95 | ||
96 | return $urlOnly ? $imageInfo[$contactType]['url'] : $imageInfo[$contactType]['summary-link']; | |
97 | } | |
98 | ||
99 | /** | |
100fef9d | 100 | * Function check for mix contact ids(individual+household etc...) |
6a488035 | 101 | * |
77c5b619 TO |
102 | * @param array $contactIds |
103 | * Array of contact ids. | |
6a488035 | 104 | * |
72b3a70c CW |
105 | * @return bool |
106 | * true if mix contact array else false | |
6a488035 | 107 | * |
6a488035 TO |
108 | */ |
109 | public static function checkContactType(&$contactIds) { | |
110 | if (empty($contactIds)) { | |
111 | return FALSE; | |
112 | } | |
113 | ||
114 | $idString = implode(',', $contactIds); | |
115 | $query = " | |
116 | SELECT count( DISTINCT contact_type ) | |
117 | FROM civicrm_contact | |
118 | WHERE id IN ( $idString ) | |
119 | "; | |
e03e1641 | 120 | $count = CRM_Core_DAO::singleValueQuery($query); |
6a488035 TO |
121 | return $count > 1 ? TRUE : FALSE; |
122 | } | |
123 | ||
124 | /** | |
c57f36a1 | 125 | * Generate a checksum for a $entityId of type $entityType |
6a488035 | 126 | * |
fd31fa4c | 127 | * @param int $entityId |
77c5b619 TO |
128 | * @param int $ts |
129 | * Timestamp that checksum was generated. | |
130 | * @param int $live | |
131 | * Life of this checksum in hours/ 'inf' for infinite. | |
132 | * @param string $hash | |
133 | * Contact hash, if sent, prevents a query in inner loop. | |
fd31fa4c EM |
134 | * |
135 | * @param string $entityType | |
136 | * @param null $hashSize | |
6a488035 | 137 | * |
a6c01b45 CW |
138 | * @return array |
139 | * ( $cs, $ts, $live ) | |
0d32dc8c | 140 | * @throws \CRM_Core_Exception |
6a488035 | 141 | */ |
00be9182 | 142 | public static function generateChecksum($entityId, $ts = NULL, $live = NULL, $hash = NULL, $entityType = 'contact', $hashSize = NULL) { |
c57f36a1 | 143 | // return a warning message if we dont get a entityId |
6a488035 TO |
144 | // this typically happens when we do a message preview |
145 | // or an anon mailing view - CRM-8298 | |
c57f36a1 | 146 | if (!$entityId) { |
6a488035 TO |
147 | return 'invalidChecksum'; |
148 | } | |
149 | ||
150 | if (!$hash) { | |
c57f36a1 PJ |
151 | if ($entityType == 'contact') { |
152 | $hash = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', | |
153 | $entityId, 'hash' | |
154 | ); | |
155 | } | |
156 | elseif ($entityType == 'mailing') { | |
157 | $hash = CRM_Core_DAO::getFieldValue('CRM_Mailing_DAO_Mailing', | |
158 | $entityId, 'hash' | |
159 | ); | |
160 | } | |
6a488035 TO |
161 | } |
162 | ||
163 | if (!$hash) { | |
164 | $hash = md5(uniqid(rand(), TRUE)); | |
c57f36a1 PJ |
165 | if ($hashSize) { |
166 | $hash = substr($hash, 0, $hashSize); | |
167 | } | |
168 | ||
169 | if ($entityType == 'contact') { | |
170 | CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_Contact', | |
171 | $entityId, | |
172 | 'hash', $hash | |
173 | ); | |
174 | } | |
175 | elseif ($entityType == 'mailing') { | |
176 | CRM_Core_DAO::setFieldValue('CRM_Mailing_DAO_Mailing', | |
177 | $entityId, | |
178 | 'hash', $hash | |
179 | ); | |
180 | } | |
6a488035 TO |
181 | } |
182 | ||
183 | if (!$ts) { | |
184 | $ts = time(); | |
185 | } | |
186 | ||
187 | if (!$live) { | |
92a8de72 | 188 | $days = Civi::settings()->get('checksum_timeout'); |
6a488035 TO |
189 | $live = 24 * $days; |
190 | } | |
191 | ||
c57f36a1 | 192 | $cs = md5("{$hash}_{$entityId}_{$ts}_{$live}"); |
6a488035 TO |
193 | return "{$cs}_{$ts}_{$live}"; |
194 | } | |
195 | ||
196 | /** | |
fe482240 | 197 | * Make sure the checksum is valid for the passed in contactID. |
6a488035 | 198 | * |
77c5b619 TO |
199 | * @param int $contactID |
200 | * @param string $inputCheck | |
201 | * Checksum to match against. | |
6a488035 | 202 | * |
ae5ffbb7 | 203 | * @return bool |
a6c01b45 | 204 | * true if valid, else false |
0d32dc8c | 205 | * |
206 | * @throws \CRM_Core_Exception | |
6a488035 | 207 | */ |
00be9182 | 208 | public static function validChecksum($contactID, $inputCheck) { |
6a488035 TO |
209 | |
210 | $input = CRM_Utils_System::explode('_', $inputCheck, 3); | |
211 | ||
212 | $inputCS = CRM_Utils_Array::value(0, $input); | |
213 | $inputTS = CRM_Utils_Array::value(1, $input); | |
214 | $inputLF = CRM_Utils_Array::value(2, $input); | |
215 | ||
216 | $check = self::generateChecksum($contactID, $inputTS, $inputLF); | |
d1b47a06 | 217 | // Joomla_11 - If $inputcheck is null without explicitly casting to a string |
218 | // you get an error. | |
219 | if (!hash_equals($check, (string) $inputCheck)) { | |
6a488035 TO |
220 | return FALSE; |
221 | } | |
222 | ||
223 | // no life limit for checksum | |
224 | if ($inputLF == 'inf') { | |
225 | return TRUE; | |
226 | } | |
227 | ||
228 | // checksum matches so now check timestamp | |
229 | $now = time(); | |
230 | return ($inputTS + ($inputLF * 60 * 60) >= $now); | |
231 | } | |
232 | ||
6a488035 | 233 | /** |
fe482240 | 234 | * Create Current employer relationship for a individual. |
6a488035 | 235 | * |
77c5b619 TO |
236 | * @param int $contactID |
237 | * Contact id of the individual. | |
238 | * @param $organization | |
239 | * (id or name). | |
c490a46a CW |
240 | * @param int $previousEmployerID |
241 | * @param bool $newContact | |
6a488035 | 242 | * |
0d32dc8c | 243 | * @throws \CRM_Core_Exception |
244 | * @throws \CiviCRM_API3_Exception | |
6a488035 | 245 | */ |
00be9182 | 246 | public static function createCurrentEmployerRelationship($contactID, $organization, $previousEmployerID = NULL, $newContact = FALSE) { |
157e4ab5 | 247 | //if organization name is passed. CRM-15368,CRM-15547 |
248 | if ($organization && !is_numeric($organization)) { | |
be2fb01f | 249 | $dupeIDs = CRM_Contact_BAO_Contact::getDuplicateContacts(['organization_name' => $organization], 'Organization', 'Unsupervised', [], FALSE); |
d477e9fa | 250 | |
251 | if (is_array($dupeIDs) && !empty($dupeIDs)) { | |
252 | // we should create relationship only w/ first org CRM-4193 | |
253 | foreach ($dupeIDs as $orgId) { | |
254 | $organization = $orgId; | |
255 | break; | |
256 | } | |
257 | } | |
258 | else { | |
259 | //create new organization | |
be2fb01f | 260 | $newOrg = [ |
d477e9fa | 261 | 'contact_type' => 'Organization', |
262 | 'organization_name' => $organization, | |
be2fb01f | 263 | ]; |
d477e9fa | 264 | $org = CRM_Contact_BAO_Contact::create($newOrg); |
265 | $organization = $org->id; | |
266 | } | |
267 | } | |
268 | ||
269 | if ($organization && is_numeric($organization)) { | |
be2fb01f | 270 | $cid = ['contact' => $contactID]; |
6a488035 TO |
271 | |
272 | // get the relationship type id of "Employee of" | |
273 | $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', 'Employee of', 'id', 'name_a_b'); | |
274 | if (!$relTypeId) { | |
0d32dc8c | 275 | throw new CRM_Core_Exception(ts("You seem to have deleted the relationship type 'Employee of'")); |
6a488035 TO |
276 | } |
277 | ||
278 | // create employee of relationship | |
be2fb01f | 279 | $relationshipParams = [ |
6a488035 TO |
280 | 'is_active' => TRUE, |
281 | 'relationship_type_id' => $relTypeId . '_a_b', | |
be2fb01f CW |
282 | 'contact_check' => [$organization => TRUE], |
283 | ]; | |
ae5ffbb7 | 284 | list($valid, $invalid, $duplicate, $saved, $relationshipIds) |
2da59b29 | 285 | = CRM_Contact_BAO_Relationship::legacyCreateMultiple($relationshipParams, $cid); |
6a488035 | 286 | |
6eae3162 | 287 | // In case we change employer, clean previous employer related records. |
288 | if (!$previousEmployerID && !$newContact) { | |
90f0b591 | 289 | $previousEmployerID = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactID, 'employer_id'); |
290 | } | |
6a488035 | 291 | if ($previousEmployerID && |
d477e9fa | 292 | $previousEmployerID != $organization |
6a488035 TO |
293 | ) { |
294 | self::clearCurrentEmployer($contactID, $previousEmployerID); | |
295 | } | |
296 | ||
297 | // set current employer | |
be2fb01f | 298 | self::setCurrentEmployer([$contactID => $organization]); |
6a488035 TO |
299 | |
300 | $relationshipParams['relationship_ids'] = $relationshipIds; | |
2001204e | 301 | // Handle related memberships. CRM-3792 |
d477e9fa | 302 | self::currentEmployerRelatedMembership($contactID, $organization, $relationshipParams, $duplicate, $previousEmployerID); |
6a488035 TO |
303 | } |
304 | } | |
305 | ||
306 | /** | |
fe482240 | 307 | * Create related memberships for current employer. |
6a488035 | 308 | * |
77c5b619 TO |
309 | * @param int $contactID |
310 | * Contact id of the individual. | |
311 | * @param int $employerID | |
312 | * Contact id of the organization. | |
313 | * @param array $relationshipParams | |
314 | * Relationship params. | |
315 | * @param bool $duplicate | |
316 | * Are we triggered existing relationship. | |
2a6da8d7 | 317 | * |
100fef9d | 318 | * @param int $previousEmpID |
6a488035 | 319 | * |
2a6da8d7 | 320 | * @throws CiviCRM_API3_Exception |
0d32dc8c | 321 | * @throws \CRM_Core_Exception |
6a488035 | 322 | */ |
00be9182 | 323 | public static function currentEmployerRelatedMembership($contactID, $employerID, $relationshipParams, $duplicate = FALSE, $previousEmpID = NULL) { |
be2fb01f | 324 | $ids = []; |
6a488035 TO |
325 | $action = CRM_Core_Action::ADD; |
326 | ||
327 | //we do not know that triggered relationship record is active. | |
328 | if ($duplicate) { | |
329 | $relationship = new CRM_Contact_DAO_Relationship(); | |
330 | $relationship->contact_id_a = $contactID; | |
331 | $relationship->contact_id_b = $employerID; | |
332 | $relationship->relationship_type_id = $relationshipParams['relationship_type_id']; | |
333 | if ($relationship->find(TRUE)) { | |
334 | $action = CRM_Core_Action::UPDATE; | |
335 | $ids['contact'] = $contactID; | |
336 | $ids['contactTarget'] = $employerID; | |
337 | $ids['relationship'] = $relationship->id; | |
338 | CRM_Contact_BAO_Relationship::setIsActive($relationship->id, TRUE); | |
339 | } | |
6a488035 TO |
340 | } |
341 | ||
342 | //need to handle related meberships. CRM-3792 | |
90f0b591 | 343 | if ($previousEmpID != $employerID) { |
344 | CRM_Contact_BAO_Relationship::relatedMemberships($contactID, $relationshipParams, $ids, $action); | |
345 | } | |
6a488035 TO |
346 | } |
347 | ||
348 | /** | |
fe482240 | 349 | * Set current employer id and organization name. |
6a488035 | 350 | * |
77c5b619 TO |
351 | * @param array $currentEmployerParams |
352 | * Associated array of contact id and its employer id. | |
6a488035 | 353 | */ |
00be9182 | 354 | public static function setCurrentEmployer($currentEmployerParams) { |
6a488035 TO |
355 | foreach ($currentEmployerParams as $contactId => $orgId) { |
356 | $query = "UPDATE civicrm_contact contact_a,civicrm_contact contact_b | |
357 | SET contact_a.employer_id=contact_b.id, contact_a.organization_name=contact_b.organization_name | |
358 | WHERE contact_a.id ={$contactId} AND contact_b.id={$orgId}; "; | |
f42bcfb1 | 359 | CRM_Core_DAO::executeQuery($query); |
6a488035 TO |
360 | } |
361 | } | |
362 | ||
363 | /** | |
fe482240 | 364 | * Update cached current employer name. |
6a488035 | 365 | * |
77c5b619 TO |
366 | * @param int $organizationId |
367 | * Current employer id. | |
6a488035 | 368 | */ |
00be9182 | 369 | public static function updateCurrentEmployer($organizationId) { |
6a488035 TO |
370 | $query = "UPDATE civicrm_contact contact_a,civicrm_contact contact_b |
371 | SET contact_a.organization_name=contact_b.organization_name | |
372 | WHERE contact_a.employer_id=contact_b.id AND contact_b.id={$organizationId}; "; | |
373 | ||
91c00d11 | 374 | CRM_Core_DAO::executeQuery($query); |
6a488035 TO |
375 | } |
376 | ||
377 | /** | |
fe482240 | 378 | * Clear cached current employer name. |
6a488035 | 379 | * |
77c5b619 TO |
380 | * @param int $contactId |
381 | * Contact id ( mostly individual contact id). | |
382 | * @param int $employerId | |
383 | * Contact id ( mostly organization contact id). | |
0d32dc8c | 384 | * |
385 | * @throws \CRM_Core_Exception | |
386 | * @throws \CiviCRM_API3_Exception | |
6a488035 | 387 | */ |
00be9182 | 388 | public static function clearCurrentEmployer($contactId, $employerId = NULL) { |
6a488035 TO |
389 | $query = "UPDATE civicrm_contact |
390 | SET organization_name=NULL, employer_id = NULL | |
391 | WHERE id={$contactId}; "; | |
392 | ||
393 | $dao = CRM_Core_DAO::executeQuery($query); | |
394 | ||
395 | // need to handle related meberships. CRM-3792 | |
396 | if ($employerId) { | |
397 | //1. disable corresponding relationship. | |
398 | //2. delete related membership. | |
399 | ||
400 | //get the relationship type id of "Employee of" | |
401 | $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', 'Employee of', 'id', 'name_a_b'); | |
402 | if (!$relTypeId) { | |
0d32dc8c | 403 | throw new CRM_Core_Exception(ts("You seem to have deleted the relationship type 'Employee of'")); |
6a488035 TO |
404 | } |
405 | $relMembershipParams['relationship_type_id'] = $relTypeId . '_a_b'; | |
406 | $relMembershipParams['contact_check'][$employerId] = 1; | |
407 | ||
408 | //get relationship id. | |
409 | if (CRM_Contact_BAO_Relationship::checkDuplicateRelationship($relMembershipParams, $contactId, $employerId)) { | |
410 | $relationship = new CRM_Contact_DAO_Relationship(); | |
411 | $relationship->contact_id_a = $contactId; | |
412 | $relationship->contact_id_b = $employerId; | |
413 | $relationship->relationship_type_id = $relTypeId; | |
414 | ||
415 | if ($relationship->find(TRUE)) { | |
416 | CRM_Contact_BAO_Relationship::setIsActive($relationship->id, FALSE); | |
417 | CRM_Contact_BAO_Relationship::relatedMemberships($contactId, $relMembershipParams, | |
be2fb01f | 418 | $ids = [], |
d3e86119 | 419 | CRM_Core_Action::DELETE |
6a488035 TO |
420 | ); |
421 | } | |
6a488035 TO |
422 | } |
423 | } | |
424 | } | |
425 | ||
426 | /** | |
100fef9d | 427 | * Build form for related contacts / on behalf of organization. |
6a488035 | 428 | * |
c490a46a | 429 | * @param CRM_Core_Form $form |
5a4f6742 CW |
430 | * @param string $contactType |
431 | * contact type. | |
100fef9d CW |
432 | * @param int $countryID |
433 | * @param int $stateID | |
5a4f6742 CW |
434 | * @param string $title |
435 | * fieldset title. | |
6a488035 | 436 | * |
0d32dc8c | 437 | * @throws \CiviCRM_API3_Exception |
6a488035 | 438 | */ |
00be9182 | 439 | public static function buildOnBehalfForm(&$form, $contactType, $countryID, $stateID, $title) { |
6a488035 TO |
440 | $form->assign('contact_type', $contactType); |
441 | $form->assign('fieldSetTitle', $title); | |
0949913f | 442 | $form->assign('contactEditMode', TRUE); |
6a488035 TO |
443 | |
444 | $attributes = CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact'); | |
445 | if ($form->_contactId) { | |
446 | $form->assign('orgId', $form->_contactId); | |
447 | } | |
448 | ||
449 | switch ($contactType) { | |
450 | case 'Organization': | |
d5f1ee75 | 451 | $form->add('text', 'organization_name', ts('Organization Name'), $attributes['organization_name'], TRUE); |
6a488035 TO |
452 | break; |
453 | ||
454 | case 'Household': | |
353ffa53 | 455 | $form->add('text', 'household_name', ts('Household Name'), $attributes['household_name']); |
6a488035 TO |
456 | break; |
457 | ||
458 | default: | |
459 | // individual | |
460 | $form->addElement('select', 'prefix_id', ts('Prefix'), | |
be2fb01f | 461 | ['' => ts('- prefix -')] + CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'prefix_id') |
6a488035 TO |
462 | ); |
463 | $form->addElement('text', 'first_name', ts('First Name'), | |
464 | $attributes['first_name'] | |
465 | ); | |
466 | $form->addElement('text', 'middle_name', ts('Middle Name'), | |
467 | $attributes['middle_name'] | |
468 | ); | |
469 | $form->addElement('text', 'last_name', ts('Last Name'), | |
470 | $attributes['last_name'] | |
471 | ); | |
472 | $form->addElement('select', 'suffix_id', ts('Suffix'), | |
be2fb01f | 473 | ['' => ts('- suffix -')] + CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'suffix_id') |
6a488035 TO |
474 | ); |
475 | } | |
476 | ||
9b118398 | 477 | $addressSequence = CRM_Utils_Address::sequence(\Civi::settings()->get('address_format')); |
6a488035 TO |
478 | $form->assign('addressSequence', array_fill_keys($addressSequence, 1)); |
479 | ||
480 | //Primary Phone | |
481 | $form->addElement('text', | |
482 | 'phone[1][phone]', | |
483 | ts('Primary Phone'), | |
484 | CRM_Core_DAO::getAttribute('CRM_Core_DAO_Phone', | |
485 | 'phone' | |
486 | ) | |
487 | ); | |
488 | //Primary Email | |
489 | $form->addElement('text', | |
490 | 'email[1][email]', | |
491 | ts('Primary Email'), | |
492 | CRM_Core_DAO::getAttribute('CRM_Core_DAO_Email', | |
493 | 'email' | |
494 | ) | |
495 | ); | |
496 | //build the address block | |
497 | CRM_Contact_Form_Edit_Address::buildQuickForm($form); | |
6a488035 TO |
498 | } |
499 | ||
500 | /** | |
100fef9d | 501 | * Clear cache employer name and employer id |
6a488035 TO |
502 | * of all employee when employer get deleted. |
503 | * | |
77c5b619 TO |
504 | * @param int $employerId |
505 | * Contact id of employer ( organization id ). | |
6a488035 | 506 | */ |
00be9182 | 507 | public static function clearAllEmployee($employerId) { |
6a488035 TO |
508 | $query = " |
509 | UPDATE civicrm_contact | |
510 | SET organization_name=NULL, employer_id = NULL | |
511 | WHERE employer_id={$employerId}; "; | |
512 | ||
33621c4f | 513 | $dao = CRM_Core_DAO::executeQuery($query); |
6a488035 TO |
514 | } |
515 | ||
516 | /** | |
fe482240 | 517 | * Given an array of contact ids this function will return array with links to view contact page. |
6a488035 | 518 | * |
77c5b619 TO |
519 | * @param array $contactIDs |
520 | * Associated contact id's. | |
2a6da8d7 EM |
521 | * @param bool $addViewLink |
522 | * @param bool $addEditLink | |
77c5b619 TO |
523 | * @param int $originalId |
524 | * Associated with the contact which is edited. | |
6a488035 TO |
525 | * |
526 | * | |
a6c01b45 CW |
527 | * @return array |
528 | * returns array with links to contact view | |
6a488035 | 529 | */ |
00be9182 | 530 | public static function formatContactIDSToLinks($contactIDs, $addViewLink = TRUE, $addEditLink = TRUE, $originalId = NULL) { |
be2fb01f | 531 | $contactLinks = []; |
6a488035 TO |
532 | if (!is_array($contactIDs) || empty($contactIDs)) { |
533 | return $contactLinks; | |
534 | } | |
535 | ||
536 | // does contact has sufficient permissions. | |
be2fb01f | 537 | $permissions = [ |
6a488035 TO |
538 | 'view' => 'view all contacts', |
539 | 'edit' => 'edit all contacts', | |
540 | 'merge' => 'merge duplicate contacts', | |
be2fb01f | 541 | ]; |
6a488035 | 542 | |
be2fb01f | 543 | $permissionedContactIds = []; |
6a488035 TO |
544 | foreach ($permissions as $task => $permission) { |
545 | // give permission. | |
546 | if (CRM_Core_Permission::check($permission)) { | |
547 | foreach ($contactIDs as $contactId) { | |
548 | $permissionedContactIds[$contactId][$task] = TRUE; | |
549 | } | |
550 | continue; | |
551 | } | |
552 | ||
553 | // check permission on acl basis. | |
be2fb01f | 554 | if (in_array($task, [ |
353ffa53 | 555 | 'view', |
ae5ffbb7 | 556 | 'edit', |
be2fb01f | 557 | ])) { |
6a488035 TO |
558 | $aclPermission = CRM_Core_Permission::VIEW; |
559 | if ($task == 'edit') { | |
560 | $aclPermission = CRM_Core_Permission::EDIT; | |
561 | } | |
562 | foreach ($contactIDs as $contactId) { | |
563 | if (CRM_Contact_BAO_Contact_Permission::allow($contactId, $aclPermission)) { | |
564 | $permissionedContactIds[$contactId][$task] = TRUE; | |
565 | } | |
566 | } | |
567 | } | |
568 | } | |
569 | ||
570 | // retrieve display names for all contacts | |
571 | $query = ' | |
572 | SELECT c.id, c.display_name, c.contact_type, ce.email | |
573 | FROM civicrm_contact c | |
574 | LEFT JOIN civicrm_email ce ON ( ce.contact_id=c.id AND ce.is_primary = 1 ) | |
575 | WHERE c.id IN (' . implode(',', $contactIDs) . ' ) LIMIT 20'; | |
576 | ||
577 | $dao = CRM_Core_DAO::executeQuery($query); | |
578 | ||
579 | $contactLinks['msg'] = NULL; | |
580 | $i = 0; | |
581 | while ($dao->fetch()) { | |
582 | ||
583 | $contactLinks['rows'][$i]['display_name'] = $dao->display_name; | |
584 | $contactLinks['rows'][$i]['primary_email'] = $dao->email; | |
585 | ||
586 | // get the permission for current contact id. | |
587 | $hasPermissions = CRM_Utils_Array::value($dao->id, $permissionedContactIds); | |
588 | if (!is_array($hasPermissions) || empty($hasPermissions)) { | |
589 | $i++; | |
590 | continue; | |
591 | } | |
592 | ||
593 | // do check for view. | |
594 | if (array_key_exists('view', $hasPermissions)) { | |
a1c7d42f | 595 | $contactLinks['rows'][$i]['view'] = '<a class="action-item" href="' . CRM_Utils_System::url('civicrm/contact/view', 'reset=1&cid=' . $dao->id) . '" target="_blank">' . ts('View') . '</a>'; |
6a488035 TO |
596 | if (!$contactLinks['msg']) { |
597 | $contactLinks['msg'] = 'view'; | |
598 | } | |
599 | } | |
600 | if (array_key_exists('edit', $hasPermissions)) { | |
601 | $contactLinks['rows'][$i]['edit'] = '<a class="action-item" href="' . CRM_Utils_System::url('civicrm/contact/add', 'reset=1&action=update&cid=' . $dao->id) . '" target="_blank">' . ts('Edit') . '</a>'; | |
602 | if (!$contactLinks['msg'] || $contactLinks['msg'] != 'merge') { | |
603 | $contactLinks['msg'] = 'edit'; | |
604 | } | |
605 | } | |
606 | if (!empty($originalId) && array_key_exists('merge', $hasPermissions)) { | |
353ffa53 | 607 | $rgBao = new CRM_Dedupe_BAO_RuleGroup(); |
6a488035 | 608 | $rgBao->contact_type = $dao->contact_type; |
353ffa53 | 609 | $rgBao->used = 'Supervised'; |
6a488035 TO |
610 | if ($rgBao->find(TRUE)) { |
611 | $rgid = $rgBao->id; | |
612 | } | |
613 | if ($rgid && isset($dao->id)) { | |
614 | //get an url to merge the contact | |
615 | $contactLinks['rows'][$i]['merge'] = '<a class="action-item" href="' . CRM_Utils_System::url('civicrm/contact/merge', "reset=1&cid=" . $originalId . '&oid=' . $dao->id . '&action=update&rgid=' . $rgid) . '">' . ts('Merge') . '</a>'; | |
616 | $contactLinks['msg'] = 'merge'; | |
617 | } | |
618 | } | |
619 | ||
620 | $i++; | |
621 | } | |
622 | ||
623 | return $contactLinks; | |
624 | } | |
625 | ||
626 | /** | |
627 | * This function retrieve component related contact information. | |
628 | * | |
77c5b619 TO |
629 | * @param array $componentIds |
630 | * Array of component Ids. | |
100fef9d | 631 | * @param string $componentName |
77c5b619 TO |
632 | * @param array $returnProperties |
633 | * Array of return elements. | |
6a488035 | 634 | * |
a6c01b45 CW |
635 | * @return array |
636 | * array of contact info. | |
6a488035 | 637 | */ |
be2fb01f CW |
638 | public static function contactDetails($componentIds, $componentName, $returnProperties = []) { |
639 | $contactDetails = []; | |
6a488035 | 640 | if (empty($componentIds) || |
be2fb01f | 641 | !in_array($componentName, ['CiviContribute', 'CiviMember', 'CiviEvent', 'Activity', 'CiviCase']) |
6a488035 TO |
642 | ) { |
643 | return $contactDetails; | |
644 | } | |
645 | ||
646 | if (empty($returnProperties)) { | |
647 | $autocompleteContactSearch = CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME, | |
648 | 'contact_autocomplete_options' | |
649 | ); | |
be2fb01f | 650 | $returnProperties = array_fill_keys(array_merge(['sort_name'], |
353ffa53 TO |
651 | array_keys($autocompleteContactSearch) |
652 | ), 1); | |
6a488035 TO |
653 | } |
654 | ||
655 | $compTable = NULL; | |
656 | if ($componentName == 'CiviContribute') { | |
657 | $compTable = 'civicrm_contribution'; | |
658 | } | |
659 | elseif ($componentName == 'CiviMember') { | |
660 | $compTable = 'civicrm_membership'; | |
661 | } | |
662 | elseif ($componentName == 'Activity') { | |
663 | $compTable = 'civicrm_activity'; | |
44f817d4 | 664 | $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate'); |
6a488035 | 665 | } |
888da08c MW |
666 | elseif ($componentName == 'CiviCase') { |
667 | $compTable = 'civicrm_case'; | |
668 | } | |
6a488035 TO |
669 | else { |
670 | $compTable = 'civicrm_participant'; | |
671 | } | |
672 | ||
be2fb01f | 673 | $select = $from = []; |
6a488035 | 674 | foreach ($returnProperties as $property => $ignore) { |
be2fb01f | 675 | $value = (in_array($property, [ |
353ffa53 | 676 | 'city', |
ae5ffbb7 | 677 | 'street_address', |
4959114b | 678 | 'postal_code', |
be2fb01f | 679 | ])) ? 'address' : $property; |
6a488035 TO |
680 | switch ($property) { |
681 | case 'sort_name': | |
682 | if ($componentName == 'Activity') { | |
f0385140 | 683 | $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts); |
684 | $select[] = "contact.$property as $property"; | |
685 | $from[$value] = " | |
686 | INNER JOIN civicrm_activity_contact acs ON (acs.activity_id = {$compTable}.id AND acs.record_type_id = {$sourceID}) | |
687 | INNER JOIN civicrm_contact contact ON ( contact.id = acs.contact_id )"; | |
888da08c MW |
688 | } |
689 | elseif ($componentName == 'CiviCase') { | |
690 | $select[] = "contact.$property as $property"; | |
691 | $from[$value] = " | |
692 | INNER JOIN civicrm_case_contact ccs ON (ccs.case_id = {$compTable}.id) | |
693 | INNER JOIN civicrm_contact contact ON ( contact.id = ccs.contact_id )"; | |
6a488035 TO |
694 | } |
695 | else { | |
696 | $select[] = "$property as $property"; | |
697 | $from[$value] = "INNER JOIN civicrm_contact contact ON ( contact.id = $compTable.contact_id )"; | |
698 | } | |
699 | break; | |
700 | ||
701 | case 'target_sort_name': | |
f0385140 | 702 | $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts); |
6a488035 | 703 | $select[] = "contact_target.sort_name as $property"; |
91da6cd5 | 704 | $from[$value] = " |
f0385140 | 705 | INNER JOIN civicrm_activity_contact act ON (act.activity_id = {$compTable}.id AND act.record_type_id = {$targetID}) |
706 | INNER JOIN civicrm_contact contact_target ON ( contact_target.id = act.contact_id )"; | |
6a488035 TO |
707 | break; |
708 | ||
709 | case 'email': | |
710 | case 'phone': | |
711 | case 'city': | |
712 | case 'street_address': | |
4959114b | 713 | case 'postal_code': |
6a488035 TO |
714 | $select[] = "$property as $property"; |
715 | // Grab target contact properties if this is for activity | |
716 | if ($componentName == 'Activity') { | |
717 | $from[$value] = "LEFT JOIN civicrm_{$value} {$value} ON ( contact_target.id = {$value}.contact_id AND {$value}.is_primary = 1 ) "; | |
718 | } | |
719 | else { | |
720 | $from[$value] = "LEFT JOIN civicrm_{$value} {$value} ON ( contact.id = {$value}.contact_id AND {$value}.is_primary = 1 ) "; | |
721 | } | |
722 | break; | |
723 | ||
724 | case 'country': | |
725 | case 'state_province': | |
726 | $select[] = "{$property}.name as $property"; | |
727 | if (!in_array('address', $from)) { | |
728 | // Grab target contact properties if this is for activity | |
729 | if ($componentName == 'Activity') { | |
730 | $from['address'] = 'LEFT JOIN civicrm_address address ON ( contact_target.id = address.contact_id AND address.is_primary = 1) '; | |
731 | } | |
732 | else { | |
733 | $from['address'] = 'LEFT JOIN civicrm_address address ON ( contact.id = address.contact_id AND address.is_primary = 1) '; | |
734 | } | |
735 | } | |
736 | $from[$value] = " LEFT JOIN civicrm_{$value} {$value} ON ( address.{$value}_id = {$value}.id ) "; | |
737 | break; | |
738 | } | |
739 | } | |
740 | ||
741 | //finally retrieve contact details. | |
742 | if (!empty($select) && !empty($from)) { | |
353ffa53 | 743 | $fromClause = implode(' ', $from); |
6a488035 | 744 | $selectClause = implode(', ', $select); |
353ffa53 | 745 | $whereClause = "{$compTable}.id IN (" . implode(',', $componentIds) . ')'; |
be2fb01f | 746 | $groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($select, ["{$compTable}.id", 'contact.id']); |
6a488035 TO |
747 | |
748 | $query = " | |
749 | SELECT contact.id as contactId, $compTable.id as componentId, $selectClause | |
750 | FROM $compTable as $compTable $fromClause | |
751 | WHERE $whereClause | |
dc852c7b | 752 | {$groupBy}"; |
6a488035 TO |
753 | |
754 | $contact = CRM_Core_DAO::executeQuery($query); | |
755 | while ($contact->fetch()) { | |
756 | $contactDetails[$contact->componentId]['contact_id'] = $contact->contactId; | |
757 | foreach ($returnProperties as $property => $ignore) { | |
758 | $contactDetails[$contact->componentId][$property] = $contact->$property; | |
759 | } | |
760 | } | |
6a488035 TO |
761 | } |
762 | ||
763 | return $contactDetails; | |
764 | } | |
765 | ||
766 | /** | |
fe482240 | 767 | * Function handles shared contact address processing. |
6a488035 TO |
768 | * In this function we just modify submitted values so that new address created for the user |
769 | * has same address as shared contact address. We copy the address so that search etc will be | |
e60b6e52 | 770 | * much more efficient. |
6a488035 | 771 | * |
77c5b619 TO |
772 | * @param array $address |
773 | * This is associated array which contains submitted form values. | |
6a488035 | 774 | */ |
00be9182 | 775 | public static function processSharedAddress(&$address) { |
6a488035 TO |
776 | if (!is_array($address)) { |
777 | return; | |
778 | } | |
779 | ||
e60b6e52 D |
780 | // In create mode sharing a contact's address is pretty straight forward. |
781 | // In update mode we should check if the user stops sharing. If yes: | |
782 | // - Set the master_id to an empty value | |
783 | // Normal update process will automatically create new address with submitted values | |
6a488035 | 784 | |
e60b6e52 | 785 | // 1. loop through entire submitted address array |
653e401d | 786 | $skipFields = ['is_primary', 'location_type_id', 'is_billing', 'master_id', 'add_relationship', 'id', 'contact_id']; |
6a488035 | 787 | foreach ($address as & $values) { |
e60b6e52 D |
788 | // 2. check if "Use another contact's address" is checked, if not continue |
789 | // Additionally, if master_id is set (address was shared), set master_id to empty value. | |
790 | if (empty($values['use_shared_address'])) { | |
791 | if (!empty($values['master_id'])) { | |
792 | $values['master_id'] = ''; | |
793 | } | |
6a488035 TO |
794 | continue; |
795 | } | |
796 | ||
1e2c74e1 SV |
797 | // Set add_relationship checkbox value |
798 | $values['add_relationship'] = !empty($values['add_relationship']); | |
e0fb9216 | 799 | |
6a488035 TO |
800 | // 3. get the address details for master_id |
801 | $masterAddress = new CRM_Core_BAO_Address(); | |
802 | $masterAddress->id = CRM_Utils_Array::value('master_id', $values); | |
803 | $masterAddress->find(TRUE); | |
804 | ||
653e401d | 805 | // 4. CRM-10336: Empty all fields (execept the fields to skip) |
6a488035 | 806 | foreach ($values as $field => $submittedValue) { |
653e401d AF |
807 | if (!in_array($field, $skipFields)) { |
808 | $values[$field] = ''; | |
809 | } | |
810 | } | |
811 | ||
812 | // 5. update address params to match shared address | |
813 | // make sure you preserve specific form values like location type, is_primary_ is_billing, master_id | |
814 | foreach ($masterAddress as $field => $value) { | |
9b873358 | 815 | if (!in_array($field, $skipFields)) { |
6a488035 | 816 | if (isset($masterAddress->$field)) { |
353ffa53 | 817 | $values[$field] = $masterAddress->$field; |
0db6c3e1 | 818 | } |
6a488035 TO |
819 | } |
820 | } | |
821 | } | |
822 | } | |
6a488035 TO |
823 | |
824 | /** | |
fe482240 | 825 | * Get the list of contact name give address associated array. |
6a488035 | 826 | * |
77c5b619 TO |
827 | * @param array $addresses |
828 | * Associated array of. | |
6a488035 | 829 | * |
a6c01b45 CW |
830 | * @return array |
831 | * associated array of contact names | |
6a488035 | 832 | */ |
00be9182 | 833 | public static function getAddressShareContactNames(&$addresses) { |
be2fb01f | 834 | $contactNames = []; |
6a488035 | 835 | // get the list of master id's for address |
be2fb01f | 836 | $masterAddressIds = []; |
6a488035 | 837 | foreach ($addresses as $key => $addressValue) { |
a7488080 | 838 | if (!empty($addressValue['master_id'])) { |
6a488035 TO |
839 | $masterAddressIds[] = $addressValue['master_id']; |
840 | } | |
841 | } | |
842 | ||
843 | if (!empty($masterAddressIds)) { | |
844 | $query = 'SELECT ca.id, cc.display_name, cc.id as cid, cc.is_deleted | |
845 | FROM civicrm_contact cc | |
846 | INNER JOIN civicrm_address ca ON cc.id = ca.contact_id | |
847 | WHERE ca.id IN ( ' . implode(',', $masterAddressIds) . ')'; | |
848 | $dao = CRM_Core_DAO::executeQuery($query); | |
849 | ||
850 | while ($dao->fetch()) { | |
851 | $contactViewUrl = CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$dao->cid}"); | |
be2fb01f | 852 | $contactNames[$dao->id] = [ |
6a488035 TO |
853 | 'name' => "<a href='{$contactViewUrl}'>{$dao->display_name}</a>", |
854 | 'is_deleted' => $dao->is_deleted, | |
88820b18 | 855 | 'contact_id' => $dao->cid, |
be2fb01f | 856 | ]; |
6a488035 TO |
857 | } |
858 | } | |
859 | return $contactNames; | |
860 | } | |
861 | ||
862 | /** | |
863 | * Clear the contact cache so things are kosher. We started off being super aggressive with clearing | |
864 | * caches, but are backing off from this with every release. Compromise between ease of coding versus | |
865 | * performance versus being accurate at that very instant | |
866 | * | |
0626851e | 867 | * @param bool $isEmptyPrevNextTable |
868 | * Should the civicrm_prev_next table be cleared of any contact entries. | |
869 | * This is currently done from import but not other places and would | |
870 | * likely affect user experience in unexpected ways. Existing behaviour retained | |
871 | * ... reluctantly. | |
6a488035 | 872 | */ |
0626851e | 873 | public static function clearContactCaches($isEmptyPrevNextTable = FALSE) { |
874 | if (!CRM_Core_Config::isPermitCacheFlushMode()) { | |
875 | return; | |
876 | } | |
877 | if ($isEmptyPrevNextTable) { | |
744b4e34 TO |
878 | // These two calls are redundant in default deployments, but they're |
879 | // meaningful if "prevnext" is memory-backed. | |
880 | Civi::service('prevnext')->deleteItem(); | |
6a488035 TO |
881 | CRM_Core_BAO_PrevNextCache::deleteItem(); |
882 | } | |
0626851e | 883 | // clear acl cache if any. |
884 | CRM_ACL_BAO_Cache::resetCache(); | |
2b68a50c | 885 | CRM_Contact_BAO_GroupContactCache::opportunisticCacheFlush(); |
6a488035 TO |
886 | } |
887 | ||
86538308 | 888 | /** |
c490a46a | 889 | * @param array $params |
86538308 EM |
890 | * |
891 | * @throws Exception | |
892 | */ | |
6a488035 TO |
893 | public static function updateGreeting($params) { |
894 | $contactType = $params['ct']; | |
353ffa53 TO |
895 | $greeting = $params['gt']; |
896 | $valueID = $id = CRM_Utils_Array::value('id', $params); | |
897 | $force = CRM_Utils_Array::value('force', $params); | |
898 | $limit = CRM_Utils_Array::value('limit', $params); | |
6a488035 TO |
899 | |
900 | // if valueID is not passed use default value | |
901 | if (!$valueID) { | |
902 | $valueID = $id = self::defaultGreeting($contactType, $greeting); | |
903 | } | |
904 | ||
be2fb01f | 905 | $filter = [ |
6a488035 TO |
906 | 'contact_type' => $contactType, |
907 | 'greeting_type' => $greeting, | |
be2fb01f | 908 | ]; |
6a488035 TO |
909 | |
910 | $allGreetings = CRM_Core_PseudoConstant::greeting($filter); | |
911 | $originalGreetingString = $greetingString = CRM_Utils_Array::value($valueID, $allGreetings); | |
912 | if (!$greetingString) { | |
0d32dc8c | 913 | throw new CRM_Core_Exception(ts('Incorrect greeting value id %1, or no default greeting for this contact type and greeting type.', [1 => $valueID])); |
6a488035 TO |
914 | } |
915 | ||
916 | // build return properties based on tokens | |
917 | $greetingTokens = CRM_Utils_Token::getTokens($greetingString); | |
918 | $tokens = CRM_Utils_Array::value('contact', $greetingTokens); | |
be2fb01f | 919 | $greetingsReturnProperties = []; |
6a488035 TO |
920 | if (is_array($tokens)) { |
921 | $greetingsReturnProperties = array_fill_keys(array_values($tokens), 1); | |
922 | } | |
923 | ||
924 | // Process ALL contacts only when force=1 or force=2 is passed. Else only contacts with NULL greeting or addressee value are updated. | |
925 | $processAll = $processOnlyIdSet = FALSE; | |
926 | if ($force == 1) { | |
927 | $processAll = TRUE; | |
928 | } | |
929 | elseif ($force == 2) { | |
930 | $processOnlyIdSet = TRUE; | |
931 | } | |
932 | ||
933 | //FIXME : apiQuery should handle these clause. | |
be2fb01f | 934 | $filterContactFldIds = $filterIds = []; |
6a488035 TO |
935 | $idFldName = $displayFldName = NULL; |
936 | if (in_array($greeting, CRM_Contact_BAO_Contact::$_greetingTypes)) { | |
937 | $idFldName = $greeting . '_id'; | |
938 | $displayFldName = $greeting . '_display'; | |
939 | } | |
940 | ||
941 | if ($idFldName) { | |
be2fb01f | 942 | $queryParams = [1 => [$contactType, 'String']]; |
30b0cb91 | 943 | |
6a488035 TO |
944 | // if $force == 1 then update all contacts else only |
945 | // those with NULL greeting or addressee value CRM-9476 | |
946 | if ($processAll) { | |
947 | $sql = "SELECT DISTINCT id, $idFldName FROM civicrm_contact WHERE contact_type = %1 "; | |
948 | } | |
949 | else { | |
a39ef8af E |
950 | $sql = " |
951 | SELECT DISTINCT id, $idFldName | |
952 | FROM civicrm_contact | |
953 | WHERE contact_type = %1 | |
954 | AND ({$idFldName} IS NULL | |
955 | OR ( {$idFldName} IS NOT NULL AND ({$displayFldName} IS NULL OR {$displayFldName} = '')) )"; | |
6a488035 TO |
956 | } |
957 | ||
24f77640 | 958 | if ($limit) { |
30b0cb91 | 959 | $sql .= " LIMIT 0, %2"; |
be2fb01f | 960 | $queryParams += [2 => [$limit, 'Integer']]; |
24f77640 | 961 | } |
962 | ||
30b0cb91 | 963 | $dao = CRM_Core_DAO::executeQuery($sql, $queryParams); |
6a488035 TO |
964 | while ($dao->fetch()) { |
965 | $filterContactFldIds[$dao->id] = $dao->$idFldName; | |
966 | ||
967 | if (!CRM_Utils_System::isNull($dao->$idFldName)) { | |
968 | $filterIds[$dao->id] = $dao->$idFldName; | |
969 | } | |
970 | } | |
971 | } | |
972 | ||
973 | if (empty($filterContactFldIds)) { | |
974 | $filterContactFldIds[] = 0; | |
975 | } | |
976 | ||
977 | // retrieve only required contact information | |
be2fb01f | 978 | $extraParams[] = ['contact_type', '=', $contactType, 0, 0]; |
6a488035 TO |
979 | // we do token replacement in the replaceGreetingTokens hook |
980 | list($greetingDetails) = CRM_Utils_Token::getTokenDetails(array_keys($filterContactFldIds), | |
981 | $greetingsReturnProperties, | |
982 | FALSE, FALSE, $extraParams | |
983 | ); | |
984 | // perform token replacement and build update SQL | |
be2fb01f | 985 | $contactIds = []; |
6a488035 TO |
986 | $cacheFieldQuery = "UPDATE civicrm_contact SET {$greeting}_display = CASE id "; |
987 | foreach ($greetingDetails as $contactID => $contactDetails) { | |
988 | if (!$processAll && | |
989 | !array_key_exists($contactID, $filterContactFldIds) | |
990 | ) { | |
991 | continue; | |
992 | } | |
993 | ||
994 | if ($processOnlyIdSet && !array_key_exists($contactID, $filterIds)) { | |
995 | continue; | |
996 | } | |
997 | ||
998 | if ($id) { | |
999 | $greetingString = $originalGreetingString; | |
1000 | $contactIds[] = $contactID; | |
1001 | } | |
1002 | else { | |
1003 | if ($greetingBuffer = CRM_Utils_Array::value($filterContactFldIds[$contactID], $allGreetings)) { | |
1004 | $greetingString = $greetingBuffer; | |
1005 | } | |
1006 | } | |
1007 | ||
73d64eb6 | 1008 | self::processGreetingTemplate($greetingString, $contactDetails, $contactID, 'CRM_UpdateGreeting'); |
6a488035 TO |
1009 | $greetingString = CRM_Core_DAO::escapeString($greetingString); |
1010 | $cacheFieldQuery .= " WHEN {$contactID} THEN '{$greetingString}' "; | |
1011 | ||
1012 | $allContactIds[] = $contactID; | |
1013 | } | |
1014 | ||
1015 | if (!empty($allContactIds)) { | |
1016 | $cacheFieldQuery .= " ELSE {$greeting}_display | |
1017 | END;"; | |
1018 | if (!empty($contactIds)) { | |
1019 | // need to update greeting _id field. | |
1020 | // reset greeting _custom | |
1021 | $resetCustomGreeting = ''; | |
1022 | if ($valueID != 4) { | |
1023 | $resetCustomGreeting = ", {$greeting}_custom = NULL "; | |
1024 | } | |
1025 | ||
1026 | $queryString = " | |
1027 | UPDATE civicrm_contact | |
1028 | SET {$greeting}_id = {$valueID} | |
1029 | {$resetCustomGreeting} | |
1030 | WHERE id IN (" . implode(',', $contactIds) . ")"; | |
1031 | CRM_Core_DAO::executeQuery($queryString); | |
1032 | } | |
1033 | ||
1034 | // now update cache field | |
1035 | CRM_Core_DAO::executeQuery($cacheFieldQuery); | |
1036 | } | |
1037 | } | |
1038 | ||
1039 | /** | |
fe482240 | 1040 | * Fetch the default greeting for a given contact type. |
6a488035 | 1041 | * |
77c5b619 TO |
1042 | * @param string $contactType |
1043 | * Contact type. | |
1044 | * @param string $greetingType | |
1045 | * Greeting type. | |
6a488035 | 1046 | * |
e97c66ff | 1047 | * @return int|null |
6a488035 | 1048 | */ |
00be9182 | 1049 | public static function defaultGreeting($contactType, $greetingType) { |
be2fb01f | 1050 | $contactTypeFilters = [ |
ae5ffbb7 TO |
1051 | 'Individual' => 1, |
1052 | 'Household' => 2, | |
1053 | 'Organization' => 3, | |
be2fb01f | 1054 | ]; |
6a488035 | 1055 | if (!isset($contactTypeFilters[$contactType])) { |
ae5ffbb7 | 1056 | return NULL; |
6a488035 TO |
1057 | } |
1058 | $filter = $contactTypeFilters[$contactType]; | |
1059 | ||
1060 | $id = CRM_Core_OptionGroup::values($greetingType, NULL, NULL, NULL, | |
1061 | " AND is_default = 1 AND (filter = {$filter} OR filter = 0)", | |
1062 | 'value' | |
1063 | ); | |
1064 | if (!empty($id)) { | |
1065 | return current($id); | |
1066 | } | |
1067 | } | |
73d64eb6 | 1068 | |
63b7d442 AS |
1069 | /** |
1070 | * Get the tokens that will need to be resolved to populate the contact's greetings. | |
1071 | * | |
1072 | * @param array $contactParams | |
1073 | * | |
1074 | * @return array | |
1075 | * Array of tokens. The ALL ke | |
1076 | */ | |
1077 | public static function getTokensRequiredForContactGreetings($contactParams) { | |
be2fb01f CW |
1078 | $tokens = []; |
1079 | foreach (['addressee', 'email_greeting', 'postal_greeting'] as $greeting) { | |
63b7d442 AS |
1080 | $string = ''; |
1081 | if (!empty($contactParams[$greeting . '_id'])) { | |
1082 | $string = CRM_Core_PseudoConstant::getLabel('CRM_Contact_BAO_Contact', $greeting . '_id', $contactParams[$greeting . '_id']); | |
1083 | } | |
1084 | $string = isset($contactParams[$greeting . '_custom']) ? $contactParams[$greeting . '_custom'] : $string; | |
1085 | if (empty($string)) { | |
be2fb01f | 1086 | $tokens[$greeting] = []; |
63b7d442 AS |
1087 | } |
1088 | else { | |
1089 | $tokens[$greeting] = CRM_Utils_Token::getTokens($string); | |
1090 | } | |
1091 | } | |
1092 | $allTokens = array_merge_recursive($tokens['addressee'], $tokens['email_greeting'], $tokens['postal_greeting']); | |
1093 | $tokens['all'] = $allTokens; | |
1094 | return $tokens; | |
1095 | } | |
1096 | ||
73d64eb6 OB |
1097 | /** |
1098 | * Process a greeting template string to produce the individualised greeting text. | |
1099 | * | |
1100 | * This works just like message templates for mailings: | |
1101 | * the template is processed with the token substitution mechanism, | |
1102 | * to supply the individual contact data; | |
1103 | * and it is also processed with Smarty, | |
1104 | * to allow for conditionals etc. based on the contact data. | |
1105 | * | |
1106 | * Note: We don't pass any variables to Smarty -- | |
1107 | * all variable data is inserted into the input string | |
1108 | * by the token substitution mechanism, | |
1109 | * before Smarty is invoked. | |
1110 | * | |
77c5b619 TO |
1111 | * @param string $templateString |
1112 | * The greeting template string with contact tokens + Smarty syntax. | |
73d64eb6 | 1113 | * |
67d19299 | 1114 | * @param array $contactDetails |
100fef9d CW |
1115 | * @param int $contactID |
1116 | * @param string $className | |
73d64eb6 | 1117 | */ |
00be9182 | 1118 | public static function processGreetingTemplate(&$templateString, $contactDetails, $contactID, $className) { |
73d64eb6 OB |
1119 | CRM_Utils_Token::replaceGreetingTokens($templateString, $contactDetails, $contactID, $className, TRUE); |
1120 | ||
1121 | $smarty = CRM_Core_Smarty::singleton(); | |
1122 | $templateString = $smarty->fetch("string:$templateString"); | |
1123 | } | |
96025800 | 1124 | |
055f6c27 TO |
1125 | /** |
1126 | * Determine if a contact ID is real/valid. | |
1127 | * | |
1128 | * @param int $contactId | |
1129 | * The hypothetical contact ID | |
0d32dc8c | 1130 | * |
055f6c27 | 1131 | * @return bool |
0d32dc8c | 1132 | * @throws \CRM_Core_Exception |
055f6c27 TO |
1133 | */ |
1134 | public static function isContactId($contactId) { | |
1135 | if ($contactId) { | |
1136 | // ensure that this is a valid contact id (for session inconsistency rules) | |
1137 | $cid = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', | |
1138 | $contactId, | |
1139 | 'id', | |
1140 | 'id' | |
1141 | ); | |
1142 | if ($cid) { | |
1143 | return TRUE; | |
1144 | } | |
1145 | } | |
1146 | return FALSE; | |
1147 | } | |
1148 | ||
6a488035 | 1149 | } |