Merge pull request #6457 from GinkgoFJG/angular_snippets
[civicrm-core.git] / CRM / Contact / BAO / Relationship.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 * Class CRM_Contact_BAO_Relationship.
30 */
31 class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
32
33 /**
34 * Various constants to indicate different type of relationships.
35 *
36 * @var int
37 */
38 const ALL = 0, PAST = 1, DISABLED = 2, CURRENT = 4, INACTIVE = 8;
39
40 /**
41 * Create function - use the API instead.
42 *
43 * Note that the previous create function has been renamed 'legacyCreateMultiple'
44 * and this is new in 4.6
45 * All existing calls have been changed to legacyCreateMultiple except the api call - however, it is recommended
46 * that you call that as the end to end testing here is based on the api & refactoring may still be done.
47 *
48 * @param array $params
49 *
50 * @return \CRM_Contact_BAO_Relationship
51 * @throws \CRM_Core_Exception
52 */
53 public static function create(&$params) {
54
55 $extendedParams = self::loadExistingRelationshipDetails($params);
56 // When id is specified we always wan't to update, so we don't need to
57 // check for duplicate relations.
58 if (!isset($params['id']) && self::checkDuplicateRelationship($extendedParams, $extendedParams['contact_id_a'], $extendedParams['contact_id_b'], CRM_Utils_Array::value('id', $extendedParams, 0))) {
59 throw new CRM_Core_Exception('Duplicate Relationship');
60 }
61 $params = $extendedParams;
62 if (self::checkValidRelationship($params, $params, 0)) {
63 throw new CRM_Core_Exception('Invalid Relationship');
64 }
65 $relationship = self::add($params);
66 if (!empty($params['contact_id_a'])) {
67 $ids = array(
68 'contactTarget' => $relationship->contact_id_b,
69 'contact' => $params['contact_id_a'],
70 );
71
72 //CRM-16087 removed additional call to function relatedMemberships which is already called by disableEnableRelationship
73 //resulting in membership being created twice
74 if (array_key_exists('is_active', $params) && empty($params['is_active'])) {
75 $action = CRM_Core_Action::DISABLE;
76 $active = FALSE;
77 }
78 else {
79 $action = CRM_Core_Action::ENABLE;
80 $active = TRUE;
81 }
82 $id = empty($params['id']) ? $relationship->id : $params['id'];
83 self::disableEnableRelationship($id, $action, $params, $ids, $active);
84 }
85
86 self::addRecent($params, $relationship);
87 return $relationship;
88 }
89
90 /**
91 * Create multiple relationships for one contact.
92 *
93 * The relationship details are the same for each relationship except the secondary contact
94 * id can be an array.
95 *
96 * @param array $params
97 * Parameters for creating multiple relationships.
98 * The parameters are the same as for relationship create function except that the non-primary
99 * end of the relationship should be an array of one or more contact IDs.
100 * @param string $primaryContactLetter
101 * a or b to denote the primary contact for this action. The secondary may be multiple contacts
102 * and should be an array.
103 *
104 * @return array
105 * @throws \CRM_Core_Exception
106 */
107 public static function createMultiple($params, $primaryContactLetter) {
108 $secondaryContactLetter = ($primaryContactLetter == 'a') ? 'b' : 'a';
109 $secondaryContactIDs = $params['contact_id_' . $secondaryContactLetter];
110 $valid = $invalid = $duplicate = $saved = 0;
111 $relationshipIDs = array();
112 foreach ($secondaryContactIDs as $secondaryContactID) {
113 try {
114 $params['contact_id_' . $secondaryContactLetter] = $secondaryContactID;
115 $relationship = civicrm_api3('relationship', 'create', $params);
116 $relationshipIDs[] = $relationship['id'];
117 $valid++;
118 }
119 catch (CiviCRM_API3_Exception $e) {
120 switch ($e->getMessage()) {
121 case 'Duplicate Relationship':
122 $duplicate++;
123 break;
124
125 case 'Invalid Relationship':
126 $invalid++;
127 break;
128
129 default:
130 throw new CRM_Core_Exception('unknown relationship create error ' . $e->getMessage());
131 }
132 }
133 }
134
135 return array(
136 'valid' => $valid,
137 'invalid' => $invalid,
138 'duplicate' => $duplicate,
139 'saved' => $saved,
140 'relationship_ids' => $relationshipIDs,
141 );
142 }
143
144 /**
145 * Takes an associative array and creates a relationship object.
146 * @deprecated For single creates use the api instead (it's tested).
147 * For multiple a new variant of this function needs to be written and migrated to as this is a bit
148 * nasty
149 *
150 * @param array $params
151 * (reference ) an assoc array of name/value pairs.
152 * @param array $ids
153 * The array that holds all the db ids.
154 * per http://wiki.civicrm.org/confluence/display/CRM/Database+layer
155 * "we are moving away from the $ids param "
156 *
157 * @return CRM_Contact_BAO_Relationship
158 */
159 public static function legacyCreateMultiple(&$params, $ids = array()) {
160 $valid = $invalid = $duplicate = $saved = 0;
161 $relationships = $relationshipIds = array();
162 $relationshipId = CRM_Utils_Array::value('relationship', $ids, CRM_Utils_Array::value('id', $params));
163
164 //CRM-9015 - the hooks are called here & in add (since add doesn't call create)
165 // but in future should be tidied per ticket
166 if (empty($relationshipId)) {
167 $hook = 'create';
168 }
169 else {
170 $hook = 'edit';
171 }
172
173 CRM_Utils_Hook::pre($hook, 'Relationship', $relationshipId, $params);
174
175 if (!$relationshipId) {
176 // creating a new relationship
177 $dataExists = self::dataExists($params);
178 if (!$dataExists) {
179 return array(FALSE, TRUE, FALSE, FALSE, NULL);
180 }
181 $relationshipIds = array();
182 foreach ($params['contact_check'] as $key => $value) {
183 // check if the relationship is valid between contacts.
184 // step 1: check if the relationship is valid if not valid skip and keep the count
185 // step 2: check the if two contacts already have a relationship if yes skip and keep the count
186 // step 3: if valid relationship then add the relation and keep the count
187
188 // step 1
189 $contactFields = self::setContactABFromIDs($params, $ids, $key);
190 $errors = self::checkValidRelationship($contactFields, $ids, $key);
191 if ($errors) {
192 $invalid++;
193 continue;
194 }
195
196 //CRM-16978:check duplicate relationship as per case id.
197 if ($caseId = CRM_Utils_Array::value('case_id', $params)) {
198 $contactFields['case_id'] = $caseId;
199 }
200 if (
201 self::checkDuplicateRelationship(
202 $contactFields,
203 CRM_Utils_Array::value('contact', $ids),
204 // step 2
205 $key
206 )
207 ) {
208 $duplicate++;
209 continue;
210 }
211
212 $singleInstanceParams = array_merge($params, $contactFields);
213 $relationship = self::add($singleInstanceParams);
214 $relationshipIds[] = $relationship->id;
215 $relationships[$relationship->id] = $relationship;
216 $valid++;
217 }
218 // editing the relationship
219 }
220 else {
221 // check for duplicate relationship
222 // @todo this code doesn't cope well with updates - causes e-Notices.
223 // API has a lot of code to work around
224 // this but should review this code & remove the extra handling from the api
225 // it seems doubtful any of this is relevant if the contact fields & relationship
226 // type fields are not set
227 if (
228 self::checkDuplicateRelationship(
229 $params,
230 CRM_Utils_Array::value('contact', $ids),
231 $ids['contactTarget'],
232 $relationshipId
233 )
234 ) {
235 $duplicate++;
236 return array($valid, $invalid, $duplicate, $saved, NULL);
237 }
238
239 $validContacts = TRUE;
240 //validate contacts in update mode also.
241 $contactFields = self::setContactABFromIDs($params, $ids, $ids['contactTarget']);
242 if (!empty($ids['contact']) && !empty($ids['contactTarget'])) {
243 if (self::checkValidRelationship($contactFields, $ids, $ids['contactTarget'])) {
244 $validContacts = FALSE;
245 $invalid++;
246 }
247 }
248 if ($validContacts) {
249 // editing an existing relationship
250 $singleInstanceParams = array_merge($params, $contactFields);
251 $relationship = self::add($singleInstanceParams, $ids, $ids['contactTarget']);
252 $relationshipIds[] = $relationship->id;
253 $relationships[$relationship->id] = $relationship;
254 $saved++;
255 }
256 }
257
258 // do not add to recent items for import, CRM-4399
259 if (!(!empty($params['skipRecentView']) || $invalid || $duplicate)) {
260 self::addRecent($params, $relationship);
261 }
262
263 return array($valid, $invalid, $duplicate, $saved, $relationshipIds, $relationships);
264 }
265
266 /**
267 * This is the function that check/add if the relationship created is valid.
268 *
269 * @param array $params
270 * (reference ) an assoc array of name/value pairs.
271 * @param array $ids
272 * The array that holds all the db ids.
273 * @param int $contactId
274 * This is contact id for adding relationship.
275 *
276 * @return CRM_Contact_BAO_Relationship
277 */
278 public static function add(&$params, $ids = array(), $contactId = NULL) {
279 $relationshipId = CRM_Utils_Array::value('relationship', $ids, CRM_Utils_Array::value('id', $params));
280
281 $hook = 'create';
282 if ($relationshipId) {
283 $hook = 'edit';
284 }
285 //@todo hook are called from create and add - remove one
286 CRM_Utils_Hook::pre($hook, 'Relationship', $relationshipId, $params);
287
288 $relationshipTypes = CRM_Utils_Array::value('relationship_type_id', $params);
289
290 // explode the string with _ to get the relationship type id
291 // and to know which contact has to be inserted in
292 // contact_id_a and which one in contact_id_b
293 list($type) = explode('_', $relationshipTypes);
294
295 // check if the relationship type is Head of Household then update the
296 // household's primary contact with this contact.
297 if ($type == 6) {
298 CRM_Contact_BAO_Household::updatePrimaryContact($params['contact_id_b'], $params['contact_id_a']);
299 }
300
301 $relationship = new CRM_Contact_BAO_Relationship();
302 //@todo this code needs to be updated for the possibility that not all fields are set
303 // by using $relationship->copyValues($params);
304 // (update)
305 $relationship->contact_id_b = $params['contact_id_b'];
306 $relationship->contact_id_a = $params['contact_id_a'];
307 $relationship->relationship_type_id = $type;
308 $relationship->id = $relationshipId;
309
310 $dateFields = array('end_date', 'start_date');
311
312 foreach (self::getdefaults() as $defaultField => $defaultValue) {
313 if (isset($params[$defaultField])) {
314 if (in_array($defaultField, $dateFields)) {
315 $relationship->$defaultField = CRM_Utils_Date::format(CRM_Utils_Array::value($defaultField, $params));
316 if (!$relationship->$defaultField) {
317 $relationship->$defaultField = 'NULL';
318 }
319 }
320 else {
321 $relationship->$defaultField = $params[$defaultField];
322 }
323 }
324 elseif (!$relationshipId) {
325 $relationship->$defaultField = $defaultValue;
326 }
327 }
328
329 $relationship->save();
330
331 // add custom field values
332 if (!empty($params['custom'])) {
333 CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_relationship', $relationship->id);
334 }
335
336 $relationship->free();
337
338 CRM_Utils_Hook::post($hook, 'Relationship', $relationship->id, $relationship);
339
340 return $relationship;
341 }
342
343 /**
344 * Add relationship to recent links.
345 *
346 * @param array $params
347 * @param CRM_Contact_DAO_Relationship $relationship
348 */
349 public static function addRecent($params, $relationship) {
350 $url = CRM_Utils_System::url('civicrm/contact/view/rel',
351 "action=view&reset=1&id={$relationship->id}&cid={$relationship->contact_id_a}&context=home"
352 );
353 $session = CRM_Core_Session::singleton();
354 $recentOther = array();
355 if (($session->get('userID') == $relationship->contact_id_a) ||
356 CRM_Contact_BAO_Contact_Permission::allow($relationship->contact_id_a, CRM_Core_Permission::EDIT)
357 ) {
358 $rType = substr(CRM_Utils_Array::value('relationship_type_id', $params), -3);
359 $recentOther = array(
360 'editUrl' => CRM_Utils_System::url('civicrm/contact/view/rel',
361 "action=update&reset=1&id={$relationship->id}&cid={$relationship->contact_id_a}&rtype={$rType}&context=home"
362 ),
363 'deleteUrl' => CRM_Utils_System::url('civicrm/contact/view/rel',
364 "action=delete&reset=1&id={$relationship->id}&cid={$relationship->contact_id_a}&rtype={$rType}&context=home"
365 ),
366 );
367 }
368 $title = CRM_Contact_BAO_Contact::displayName($relationship->contact_id_a) . ' (' . CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType',
369 $relationship->relationship_type_id, 'label_a_b'
370 ) . ' ' . CRM_Contact_BAO_Contact::displayName($relationship->contact_id_b) . ')';
371
372 CRM_Utils_Recent::add($title,
373 $url,
374 $relationship->id,
375 'Relationship',
376 $relationship->contact_id_a,
377 NULL,
378 $recentOther
379 );
380 }
381
382 /**
383 * Load contact ids and relationship type id when doing a create call if not provided.
384 *
385 * There are are various checks done in create which require this information which is optional
386 * when using id.
387 *
388 * @param array $params
389 * Parameters passed to create call.
390 *
391 * @return array
392 * Parameters with missing fields added if required.
393 */
394 public static function loadExistingRelationshipDetails($params) {
395 if (!empty($params['contact_id_a'])
396 && !empty($params['contact_id_b'])
397 && is_numeric($params['relationship_type_id'])) {
398 return $params;
399 }
400 if (empty($params['id'])) {
401 return $params;
402 }
403
404 $fieldsToFill = array('contact_id_a', 'contact_id_b', 'relationship_type_id');
405 $result = CRM_Core_DAO::executeQuery("SELECT " . implode(',', $fieldsToFill) . " FROM civicrm_relationship WHERE id = %1", array(
406 1 => array(
407 $params['id'],
408 'Integer',
409 ),
410 ));
411 while ($result->fetch()) {
412 foreach ($fieldsToFill as $field) {
413 $params[$field] = !empty($params[$field]) ? $params[$field] : $result->$field;
414 }
415 }
416 return $params;
417 }
418
419 /**
420 * Resolve passed in contact IDs to contact_id_a & contact_id_b.
421 *
422 * @param array $params
423 * @param array $ids
424 * @param null $contactID
425 *
426 * @return array
427 * @throws \CRM_Core_Exception
428 */
429 public static function setContactABFromIDs($params, $ids = array(), $contactID = NULL) {
430 $returnFields = array();
431
432 // $ids['contact'] is deprecated but comes from legacyCreateMultiple function.
433 if (empty($ids['contact'])) {
434 if (!empty($params['id'])) {
435 return self::loadExistingRelationshipDetails($params);
436 }
437 throw new CRM_Core_Exception('Cannot create relationship, insufficient contact IDs provided');
438 }
439 if (isset($params['relationship_type_id']) && !is_numeric($params['relationship_type_id'])) {
440 $relationshipTypes = CRM_Utils_Array::value('relationship_type_id', $params);
441 list($relationshipTypeID, $first) = explode('_', $relationshipTypes);
442 $returnFields['relationship_type_id'] = $relationshipTypeID;
443
444 foreach (array('a', 'b') as $contactLetter) {
445 if (empty($params['contact_' . $contactLetter])) {
446 if ($first == $contactLetter) {
447 $returnFields['contact_id_' . $contactLetter] = CRM_Utils_Array::value('contact', $ids);
448 }
449 else {
450 $returnFields['contact_id_' . $contactLetter] = $contactID;
451 }
452 }
453 }
454 }
455
456 return $returnFields;
457 }
458
459 /**
460 * Specify defaults for creating a relationship.
461 *
462 * @return array
463 * array of defaults for creating relationship
464 */
465 public static function getdefaults() {
466 return array(
467 'is_active' => 0,
468 'is_permission_a_b' => 0,
469 'is_permission_b_a' => 0,
470 'description' => '',
471 'start_date' => 'NULL',
472 'case_id' => NULL,
473 'end_date' => 'NULL',
474 );
475 }
476
477
478 /**
479 * Check if there is data to create the object.
480 *
481 * @param array $params
482 * (reference ) an assoc array of name/value pairs.
483 *
484 * @return bool
485 */
486 public static function dataExists(&$params) {
487 // return if no data present
488 if (!is_array(CRM_Utils_Array::value('contact_check', $params))) {
489 return FALSE;
490 }
491 return TRUE;
492 }
493
494 /**
495 * Get get list of relationship type based on the contact type.
496 *
497 * @param int $contactId
498 * This is the contact id of the current contact.
499 * @param null $contactSuffix
500 * @param string $relationshipId
501 * The id of the existing relationship if any.
502 * @param string $contactType
503 * Contact type.
504 * @param bool $all
505 * If true returns relationship types in both the direction.
506 * @param string $column
507 * Name/label that going to retrieve from db.
508 * @param bool $biDirectional
509 * @param string $contactSubType
510 * Includes relationship types between this subtype.
511 * @param bool $onlySubTypeRelationTypes
512 * If set only subtype which is passed by $contactSubType
513 * related relationship types get return
514 *
515 * @return array
516 * array reference of all relationship types with context to current contact.
517 */
518 public static function getContactRelationshipType(
519 $contactId = NULL,
520 $contactSuffix = NULL,
521 $relationshipId = NULL,
522 $contactType = NULL,
523 $all = FALSE,
524 $column = 'label',
525 $biDirectional = TRUE,
526 $contactSubType = NULL,
527 $onlySubTypeRelationTypes = FALSE
528 ) {
529
530 $relationshipType = array();
531 $allRelationshipType = CRM_Core_PseudoConstant::relationshipType($column);
532
533 $otherContactType = NULL;
534 if ($relationshipId) {
535 $relationship = new CRM_Contact_DAO_Relationship();
536 $relationship->id = $relationshipId;
537 if ($relationship->find(TRUE)) {
538 $contact = new CRM_Contact_DAO_Contact();
539 $contact->id = ($relationship->contact_id_a === $contactId) ? $relationship->contact_id_b : $relationship->contact_id_a;
540
541 if ($contact->find(TRUE)) {
542 $otherContactType = $contact->contact_type;
543 //CRM-5125 for contact subtype specific relationshiptypes
544 if ($contact->contact_sub_type) {
545 $otherContactSubType = $contact->contact_sub_type;
546 }
547 }
548 }
549 }
550
551 $contactSubType = array();
552 if ($contactId) {
553 $contactType = CRM_Contact_BAO_Contact::getContactType($contactId);
554 $contactSubType = CRM_Contact_BAO_Contact::getContactSubType($contactId);
555 }
556
557 foreach ($allRelationshipType as $key => $value) {
558 // the contact type is required or matches
559 if (((!$value['contact_type_a']) ||
560 $value['contact_type_a'] == $contactType
561 ) &&
562 // the other contact type is required or present or matches
563 ((!$value['contact_type_b']) ||
564 (!$otherContactType) ||
565 $value['contact_type_b'] == $otherContactType
566 ) &&
567 (in_array($value['contact_sub_type_a'], $contactSubType) ||
568 (!$value['contact_sub_type_a'] && !$onlySubTypeRelationTypes)
569 )
570 ) {
571 $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"];
572 }
573
574 if (((!$value['contact_type_b']) ||
575 $value['contact_type_b'] == $contactType
576 ) &&
577 ((!$value['contact_type_a']) ||
578 (!$otherContactType) ||
579 $value['contact_type_a'] == $otherContactType
580 ) &&
581 (in_array($value['contact_sub_type_b'], $contactSubType) ||
582 (!$value['contact_sub_type_b'] && !$onlySubTypeRelationTypes)
583 )
584 ) {
585 $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"];
586 }
587
588 if ($all) {
589 $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"];
590 $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"];
591 }
592 }
593
594 if ($biDirectional) {
595 // lets clean up the data and eliminate all duplicate values
596 // (i.e. the relationship is bi-directional)
597 $relationshipType = array_unique($relationshipType);
598 }
599
600 // sort the relationshipType in ascending order CRM-7736
601 asort($relationshipType);
602 return $relationshipType;
603 }
604
605 /**
606 * Delete current employer relationship.
607 *
608 * @param int $id
609 * @param int $action
610 *
611 * @return CRM_Contact_DAO_Relationship
612 */
613 public static function clearCurrentEmployer($id, $action) {
614 $relationship = new CRM_Contact_DAO_Relationship();
615 $relationship->id = $id;
616 $relationship->find(TRUE);
617
618 //to delete relationship between household and individual \
619 //or between individual and organization
620 if (($action & CRM_Core_Action::DISABLE) || ($action & CRM_Core_Action::DELETE)) {
621 $relTypes = CRM_Utils_Array::index(array('name_a_b'), CRM_Core_PseudoConstant::relationshipType('name'));
622 if ($relationship->relationship_type_id == $relTypes['Employee of']['id'] ||
623 $relationship->relationship_type_id == $relTypes['Household Member of']['id']
624 ) {
625 $sharedContact = new CRM_Contact_DAO_Contact();
626 $sharedContact->id = $relationship->contact_id_a;
627 $sharedContact->find(TRUE);
628
629 // CRM-15881 UPDATES
630 // changed FROM "...relationship->relationship_type_id == 4..." TO "...relationship->relationship_type_id == 5..."
631 // As the system should be looking for type "employer of" (id 5) and not "sibling of" (id 4)
632 // As suggested by @davecivicrm, the employee relationship type id is fetched using the CRM_Core_DAO::getFieldValue() class and method, since these ids differ from system to system.
633 $employerRelTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', 'Employee of', 'id', 'name_a_b');
634
635 if ($relationship->relationship_type_id == $employerRelTypeId && $relationship->contact_id_b == $sharedContact->employer_id) {
636 CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($relationship->contact_id_a);
637 }
638
639 }
640 }
641 return $relationship;
642 }
643
644 /**
645 * Delete the relationship.
646 *
647 * @param int $id
648 * Relationship id.
649 *
650 * @return null
651 */
652 public static function del($id) {
653 // delete from relationship table
654 CRM_Utils_Hook::pre('delete', 'Relationship', $id, CRM_Core_DAO::$_nullArray);
655
656 $relationship = self::clearCurrentEmployer($id, CRM_Core_Action::DELETE);
657 if (CRM_Core_Permission::access('CiviMember')) {
658 // create $params array which isrequired to delete memberships
659 // of the related contacts.
660 $params = array(
661 'relationship_type_id' => "{$relationship->relationship_type_id}_a_b",
662 'contact_check' => array($relationship->contact_id_b => 1),
663 );
664
665 $ids = array();
666 // calling relatedMemberships to delete the memberships of
667 // related contacts.
668 self::relatedMemberships($relationship->contact_id_a,
669 $params,
670 $ids,
671 CRM_Core_Action::DELETE,
672 FALSE
673 );
674 }
675
676 $relationship->delete();
677 CRM_Core_Session::setStatus(ts('Selected relationship has been deleted successfully.'), ts('Record Deleted'), 'success');
678
679 CRM_Utils_Hook::post('delete', 'Relationship', $id, $relationship);
680
681 // delete the recently created Relationship
682 $relationshipRecent = array(
683 'id' => $id,
684 'type' => 'Relationship',
685 );
686 CRM_Utils_Recent::del($relationshipRecent);
687
688 return $relationship;
689 }
690
691 /**
692 * Disable/enable the relationship.
693 *
694 * @param int $id
695 * Relationship id.
696 *
697 * @param int $action
698 * @param array $params
699 * @param array $ids
700 * @param bool $active
701 */
702 public static function disableEnableRelationship($id, $action, $params = array(), $ids = array(), $active = FALSE) {
703 $relationship = self::clearCurrentEmployer($id, $action);
704
705 if ($id) {
706 // create $params array which is required to delete memberships
707 // of the related contacts.
708 if (empty($params)) {
709 $params = array(
710 'relationship_type_id' => "{$relationship->relationship_type_id}_a_b",
711 'contact_check' => array($relationship->contact_id_b => 1),
712 );
713 }
714 $contact_id_a = empty($params['contact_id_a']) ? $relationship->contact_id_a : $params['contact_id_a'];
715 // calling relatedMemberships to delete/add the memberships of
716 // related contacts.
717 if ($action & CRM_Core_Action::DISABLE) {
718 CRM_Contact_BAO_Relationship::relatedMemberships($contact_id_a,
719 $params,
720 $ids,
721 CRM_Core_Action::DELETE,
722 $active
723 );
724 }
725 elseif ($action & CRM_Core_Action::ENABLE) {
726 $ids['contact'] = empty($ids['contact']) ? $contact_id_a : $ids['contact'];
727 CRM_Contact_BAO_Relationship::relatedMemberships($contact_id_a,
728 $params,
729 $ids,
730 empty($params['id']) ? CRM_Core_Action::ADD : CRM_Core_Action::UPDATE,
731 $active
732 );
733 }
734 }
735 }
736
737 /**
738 * Delete the object records that are associated with this contact.
739 *
740 * @param int $contactId
741 * Id of the contact to delete.
742 */
743 public static function deleteContact($contactId) {
744 $relationship = new CRM_Contact_DAO_Relationship();
745 $relationship->contact_id_a = $contactId;
746 $relationship->delete();
747
748 $relationship = new CRM_Contact_DAO_Relationship();
749 $relationship->contact_id_b = $contactId;
750 $relationship->delete();
751
752 CRM_Contact_BAO_Household::updatePrimaryContact(NULL, $contactId);
753 }
754
755 /**
756 * Get the other contact in a relationship.
757 *
758 * @param int $id
759 * Relationship id.
760 *
761 * $returns returns the contact ids in the realtionship
762 *
763 * @return \CRM_Contact_DAO_Relationship
764 */
765 public static function getRelationshipByID($id) {
766 $relationship = new CRM_Contact_DAO_Relationship();
767
768 $relationship->id = $id;
769 $relationship->selectAdd();
770 $relationship->selectAdd('contact_id_a, contact_id_b');
771 $relationship->find(TRUE);
772
773 return $relationship;
774 }
775
776 /**
777 * Check if the relationship type selected between two contacts is correct.
778 *
779 * @param int $contact_a
780 * 1st contact id.
781 * @param int $contact_b
782 * 2nd contact id.
783 * @param int $relationshipTypeId
784 * Relationship type id.
785 *
786 * @return bool
787 * true if it is valid relationship else false
788 */
789 public static function checkRelationshipType($contact_a, $contact_b, $relationshipTypeId) {
790 $relationshipType = new CRM_Contact_DAO_RelationshipType();
791 $relationshipType->id = $relationshipTypeId;
792 $relationshipType->selectAdd();
793 $relationshipType->selectAdd('contact_type_a, contact_type_b, contact_sub_type_a, contact_sub_type_b');
794 if ($relationshipType->find(TRUE)) {
795 $contact_type_a = CRM_Contact_BAO_Contact::getContactType($contact_a);
796 $contact_type_b = CRM_Contact_BAO_Contact::getContactType($contact_b);
797
798 $contact_sub_type_a = CRM_Contact_BAO_Contact::getContactSubType($contact_a);
799 $contact_sub_type_b = CRM_Contact_BAO_Contact::getContactSubType($contact_b);
800
801 if (((!$relationshipType->contact_type_a) || ($relationshipType->contact_type_a == $contact_type_a)) &&
802 ((!$relationshipType->contact_type_b) || ($relationshipType->contact_type_b == $contact_type_b)) &&
803 ((!$relationshipType->contact_sub_type_a) || (in_array($relationshipType->contact_sub_type_a,
804 $contact_sub_type_a
805 ))) &&
806 ((!$relationshipType->contact_sub_type_b) || (in_array($relationshipType->contact_sub_type_b,
807 $contact_sub_type_b
808 )))
809 ) {
810 return TRUE;
811 }
812 else {
813 return FALSE;
814 }
815 }
816 return FALSE;
817 }
818
819 /**
820 * This function does the validtion for valid relationship.
821 *
822 * @param array $params
823 * This array contains the values there are subitted by the form.
824 * @param array $ids
825 * The array that holds all the db ids.
826 * @param int $contactId
827 * This is contact id for adding relationship.
828 *
829 * @return string
830 */
831 public static function checkValidRelationship($params, $ids, $contactId) {
832 $errors = '';
833 // function to check if the relationship selected is correct
834 // i.e. employer relationship can exit between Individual and Organization (not between Individual and Individual)
835 if (!CRM_Contact_BAO_Relationship::checkRelationshipType($params['contact_id_a'], $params['contact_id_b'],
836 $params['relationship_type_id'])) {
837 $errors = 'Please select valid relationship between these two contacts.';
838 }
839 return $errors;
840 }
841
842 /**
843 * This function checks for duplicate relationship.
844 *
845 * @param array $params
846 * (reference ) an assoc array of name/value pairs.
847 * @param int $id
848 * This the id of the contact whom we are adding relationship.
849 * @param int $contactId
850 * This is contact id for adding relationship.
851 * @param int $relationshipId
852 * This is relationship id for the contact.
853 *
854 * @return bool
855 * true if record exists else false
856 */
857 public static function checkDuplicateRelationship(&$params, $id, $contactId = 0, $relationshipId = 0) {
858 $relationshipTypeId = CRM_Utils_Array::value('relationship_type_id', $params);
859 list($type) = explode('_', $relationshipTypeId);
860
861 $queryString = "
862 SELECT id
863 FROM civicrm_relationship
864 WHERE relationship_type_id = " . CRM_Utils_Type::escape($type, 'Integer');
865
866 /*
867 * CRM-11792 - date fields from API are in ISO format, but this function
868 * supports date arrays BAO has increasingly standardised to ISO format
869 * so I believe this function should support ISO rather than make API
870 * format it - however, need to support array format for now to avoid breakage
871 * @ time of writing this function is called from Relationship::legacyCreateMultiple (twice)
872 * CRM_BAO_Contact_Utils::clearCurrentEmployer (seemingly without dates)
873 * CRM_Contact_Form_Task_AddToOrganization::postProcess &
874 * CRM_Contact_Form_Task_AddToHousehold::postProcess
875 * (I don't think the last 2 support dates but not sure
876 */
877
878 $dateFields = array('end_date', 'start_date');
879 foreach ($dateFields as $dateField) {
880 if (array_key_exists($dateField, $params)) {
881 if (empty($params[$dateField]) || $params[$dateField] == 'null') {
882 //this is most likely coming from an api call & probably loaded
883 // from the DB to deal with some of the
884 // other myriad of excessive checks still in place both in
885 // the api & the create functions
886 $queryString .= " AND $dateField IS NULL";
887 continue;
888 }
889 elseif (is_array($params[$dateField])) {
890 $queryString .= " AND $dateField = " .
891 CRM_Utils_Type::escape(CRM_Utils_Date::format($params[$dateField]), 'Date');
892 }
893 else {
894 $queryString .= " AND $dateField = " .
895 CRM_Utils_Type::escape($params[$dateField], 'Date');
896 }
897 }
898 }
899
900 $queryString .=
901 " AND ( ( contact_id_a = " . CRM_Utils_Type::escape($id, 'Integer') .
902 " AND contact_id_b = " . CRM_Utils_Type::escape($contactId, 'Integer') .
903 " ) OR ( contact_id_a = " . CRM_Utils_Type::escape($contactId, 'Integer') .
904 " AND contact_id_b = " . CRM_Utils_Type::escape($id, 'Integer') . " ) ) ";
905
906 //if caseId is provided, include it duplicate checking.
907 if ($caseId = CRM_Utils_Array::value('case_id', $params)) {
908 $queryString .= " AND case_id = " . CRM_Utils_Type::escape($caseId, 'Integer');
909 }
910
911 if ($relationshipId) {
912 $queryString .= " AND id !=" . CRM_Utils_Type::escape($relationshipId, 'Integer');
913 }
914
915 $relationship = new CRM_Contact_BAO_Relationship();
916 $relationship->query($queryString);
917 $relationship->fetch();
918 $relationship->free();
919 return ($relationship->id) ? TRUE : FALSE;
920 }
921
922 /**
923 * Update the is_active flag in the db.
924 *
925 * @param int $id
926 * Id of the database record.
927 * @param bool $is_active
928 * Value we want to set the is_active field.
929 *
930 * @throws CiviCRM_API3_Exception
931 * @return Object
932 * DAO object on success, null otherwise
933 */
934 public static function setIsActive($id, $is_active) {
935 // as both the create & add functions have a bunch of logic in them that
936 // doesn't seem to cope with a normal update we will call the api which
937 // has tested handling for this
938 // however, a longer term solution would be to simplify the add, create & api functions
939 // to be more standard. It is debatable @ that point whether it's better to call the BAO
940 // direct as the api is more tested.
941 $result = civicrm_api('relationship', 'create', array(
942 'id' => $id,
943 'is_active' => $is_active,
944 'version' => 3,
945 ));
946
947 if (is_array($result) && !empty($result['is_error']) && $result['error_message'] != 'Relationship already exists') {
948 throw new CiviCRM_API3_Exception($result['error_message'], CRM_Utils_Array::value('error_code', $result, 'undefined'), $result);
949 }
950
951 return TRUE;
952 }
953
954 /**
955 * Fetch a relationship object and store the values in the values array.
956 *
957 * @param array $params
958 * Input parameters to find object.
959 * @param array $values
960 * Output values of the object.
961 *
962 * @return array
963 * (reference) the values that could be potentially assigned to smarty
964 */
965 public static function &getValues(&$params, &$values) {
966 if (empty($params)) {
967 return NULL;
968 }
969 $v = array();
970
971 // get the specific number of relationship or all relationships.
972 if (!empty($params['numRelationship'])) {
973 $v['data'] = &CRM_Contact_BAO_Relationship::getRelationship($params['contact_id'], NULL, $params['numRelationship']);
974 }
975 else {
976 $v['data'] = CRM_Contact_BAO_Relationship::getRelationship($params['contact_id']);
977 }
978
979 // get the total count of relationships
980 $v['totalCount'] = count($v['data']);
981
982 $values['relationship']['data'] = &$v['data'];
983 $values['relationship']['totalCount'] = &$v['totalCount'];
984
985 return $v;
986 }
987
988 /**
989 * Helper function to form the sql for relationship retrieval.
990 *
991 * @param int $contactId
992 * Contact id.
993 * @param int $status
994 * (check const at top of file).
995 * @param int $numRelationship
996 * No of relationships to display (limit).
997 * @param int $count
998 * Get the no of relationships.
999 * $param int $relationshipId relationship id
1000 * @param int $relationshipId
1001 * @param string $direction
1002 * The direction we are interested in a_b or b_a.
1003 * @param array $params
1004 * Array of extra values including relationship_type_id per api spec.
1005 *
1006 * @return array
1007 * [select, from, where]
1008 */
1009 public static function makeURLClause($contactId, $status, $numRelationship, $count, $relationshipId, $direction, $params = array()) {
1010 $select = $from = $where = '';
1011
1012 $select = '( ';
1013 if ($count) {
1014 if ($direction == 'a_b') {
1015 $select .= ' SELECT count(DISTINCT civicrm_relationship.id) as cnt1, 0 as cnt2 ';
1016 }
1017 else {
1018 $select .= ' SELECT 0 as cnt1, count(DISTINCT civicrm_relationship.id) as cnt2 ';
1019 }
1020 }
1021 else {
1022 $select .= ' SELECT civicrm_relationship.id as civicrm_relationship_id,
1023 civicrm_contact.sort_name as sort_name,
1024 civicrm_contact.display_name as display_name,
1025 civicrm_contact.job_title as job_title,
1026 civicrm_contact.employer_id as employer_id,
1027 civicrm_contact.organization_name as organization_name,
1028 civicrm_address.street_address as street_address,
1029 civicrm_address.city as city,
1030 civicrm_address.postal_code as postal_code,
1031 civicrm_state_province.abbreviation as state,
1032 civicrm_country.name as country,
1033 civicrm_email.email as email,
1034 civicrm_contact.contact_type as contact_type,
1035 civicrm_phone.phone as phone,
1036 civicrm_contact.id as civicrm_contact_id,
1037 civicrm_relationship.contact_id_b as contact_id_b,
1038 civicrm_relationship.contact_id_a as contact_id_a,
1039 civicrm_relationship_type.id as civicrm_relationship_type_id,
1040 civicrm_relationship.start_date as start_date,
1041 civicrm_relationship.end_date as end_date,
1042 civicrm_relationship.description as description,
1043 civicrm_relationship.is_active as is_active,
1044 civicrm_relationship.is_permission_a_b as is_permission_a_b,
1045 civicrm_relationship.is_permission_b_a as is_permission_b_a,
1046 civicrm_relationship.case_id as case_id';
1047
1048 if ($direction == 'a_b') {
1049 $select .= ', civicrm_relationship_type.label_a_b as label_a_b,
1050 civicrm_relationship_type.label_b_a as relation ';
1051 }
1052 else {
1053 $select .= ', civicrm_relationship_type.label_a_b as label_a_b,
1054 civicrm_relationship_type.label_a_b as relation ';
1055 }
1056 }
1057
1058 $from = "
1059 FROM civicrm_relationship
1060 INNER JOIN civicrm_relationship_type ON ( civicrm_relationship.relationship_type_id = civicrm_relationship_type.id )
1061 INNER JOIN civicrm_contact ";
1062 if ($direction == 'a_b') {
1063 $from .= 'ON ( civicrm_contact.id = civicrm_relationship.contact_id_a ) ';
1064 }
1065 else {
1066 $from .= 'ON ( civicrm_contact.id = civicrm_relationship.contact_id_b ) ';
1067 }
1068 $from .= "
1069 LEFT JOIN civicrm_address ON (civicrm_address.contact_id = civicrm_contact.id AND civicrm_address.is_primary = 1)
1070 LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = civicrm_contact.id AND civicrm_phone.is_primary = 1)
1071 LEFT JOIN civicrm_email ON (civicrm_email.contact_id = civicrm_contact.id AND civicrm_email.is_primary = 1)
1072 LEFT JOIN civicrm_state_province ON (civicrm_address.state_province_id = civicrm_state_province.id)
1073 LEFT JOIN civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
1074 ";
1075 $where = 'WHERE ( 1 )';
1076 if ($contactId) {
1077 if ($direction == 'a_b') {
1078 $where .= ' AND civicrm_relationship.contact_id_b = ' . CRM_Utils_Type::escape($contactId, 'Positive');
1079 }
1080 else {
1081 $where .= ' AND civicrm_relationship.contact_id_a = ' . CRM_Utils_Type::escape($contactId, 'Positive') . '
1082 AND civicrm_relationship.contact_id_a != civicrm_relationship.contact_id_b ';
1083 }
1084 }
1085 if ($relationshipId) {
1086 $where .= ' AND civicrm_relationship.id = ' . CRM_Utils_Type::escape($relationshipId, 'Positive');
1087 }
1088
1089 $date = date('Y-m-d');
1090 if ($status == self::PAST) {
1091 //this case for showing past relationship
1092 $where .= ' AND civicrm_relationship.is_active = 1 ';
1093 $where .= " AND civicrm_relationship.end_date < '" . $date . "'";
1094 }
1095 elseif ($status == self::DISABLED) {
1096 // this case for showing disabled relationship
1097 $where .= ' AND civicrm_relationship.is_active = 0 ';
1098 }
1099 elseif ($status == self::CURRENT) {
1100 //this case for showing current relationship
1101 $where .= ' AND civicrm_relationship.is_active = 1 ';
1102 $where .= " AND (civicrm_relationship.end_date >= '" . $date . "' OR civicrm_relationship.end_date IS NULL) ";
1103 }
1104 elseif ($status == self::INACTIVE) {
1105 //this case for showing inactive relationships
1106 $where .= " AND (civicrm_relationship.end_date < '" . $date . "'";
1107 $where .= ' OR civicrm_relationship.is_active = 0 )';
1108 }
1109
1110 // CRM-6181
1111 $where .= ' AND civicrm_contact.is_deleted = 0';
1112 if (!empty($params['membership_type_id']) && empty($params['relationship_type_id'])) {
1113 $where .= self::membershipTypeToRelationshipTypes($params, $direction);
1114 }
1115 if (!empty($params['relationship_type_id'])) {
1116 if (is_array($params['relationship_type_id'])) {
1117 $where .= " AND " . CRM_Core_DAO::createSQLFilter('relationship_type_id', $params['relationship_type_id'], 'Integer');
1118 }
1119 else {
1120 $where .= ' AND relationship_type_id = ' . CRM_Utils_Type::escape($params['relationship_type_id'], 'Positive');
1121 }
1122 }
1123 if ($direction == 'a_b') {
1124 $where .= ' ) UNION ';
1125 }
1126 else {
1127 $where .= ' ) ';
1128 }
1129
1130 return array($select, $from, $where);
1131 }
1132
1133 /**
1134 * Get a list of relationships.
1135 *
1136 * @param int $contactId
1137 * Contact id.
1138 * @param int $status
1139 * 1: Past 2: Disabled 3: Current.
1140 * @param int $numRelationship
1141 * No of relationships to display (limit).
1142 * @param int $count
1143 * Get the no of relationships.
1144 * @param int $relationshipId
1145 * @param array $links
1146 * the list of links to display
1147 * @param int $permissionMask
1148 * the permission mask to be applied for the actions
1149 * @param bool $permissionedContact
1150 * to return only permissioned Contact
1151 * @param array $params
1152 *
1153 * @return array|int
1154 * relationship records
1155 */
1156 public static function getRelationship(
1157 $contactId = NULL,
1158 $status = 0, $numRelationship = 0,
1159 $count = 0, $relationshipId = 0,
1160 $links = NULL, $permissionMask = NULL,
1161 $permissionedContact = FALSE,
1162 $params = array()
1163 ) {
1164 $values = array();
1165 if (!$contactId && !$relationshipId) {
1166 return $values;
1167 }
1168
1169 list($select1, $from1, $where1) = self::makeURLClause($contactId, $status, $numRelationship,
1170 $count, $relationshipId, 'a_b', $params
1171 );
1172 list($select2, $from2, $where2) = self::makeURLClause($contactId, $status, $numRelationship,
1173 $count, $relationshipId, 'b_a', $params
1174 );
1175
1176 $order = $limit = '';
1177 if (!$count) {
1178 if (empty($params['sort'])) {
1179 $order = ' ORDER BY civicrm_relationship_type_id, sort_name ';
1180 }
1181 else {
1182 $order = " ORDER BY {$params['sort']} ";
1183 }
1184
1185 $offset = 0;
1186 if (!empty($params['offset']) && $params['offset'] > 0) {
1187 $offset = $params['offset'];
1188 }
1189
1190 if ($numRelationship) {
1191 $limit = " LIMIT {$offset}, $numRelationship";
1192 }
1193 }
1194
1195 // building the query string
1196 $queryString = $select1 . $from1 . $where1 . $select2 . $from2 . $where2 . $order . $limit;
1197
1198 $relationship = new CRM_Contact_DAO_Relationship();
1199
1200 $relationship->query($queryString);
1201 $row = array();
1202 if ($count) {
1203 $relationshipCount = 0;
1204 while ($relationship->fetch()) {
1205 $relationshipCount += $relationship->cnt1 + $relationship->cnt2;
1206 }
1207 return $relationshipCount;
1208 }
1209 else {
1210
1211 $mask = NULL;
1212 if ($status != self::INACTIVE) {
1213 if ($links) {
1214 $mask = array_sum(array_keys($links));
1215 if ($mask & CRM_Core_Action::DISABLE) {
1216 $mask -= CRM_Core_Action::DISABLE;
1217 }
1218 if ($mask & CRM_Core_Action::ENABLE) {
1219 $mask -= CRM_Core_Action::ENABLE;
1220 }
1221
1222 if ($status == self::CURRENT) {
1223 $mask |= CRM_Core_Action::DISABLE;
1224 }
1225 elseif ($status == self::DISABLED) {
1226 $mask |= CRM_Core_Action::ENABLE;
1227 }
1228 $mask = $mask & $permissionMask;
1229 }
1230 }
1231
1232 while ($relationship->fetch()) {
1233 $rid = $relationship->civicrm_relationship_id;
1234 $cid = $relationship->civicrm_contact_id;
1235 if (($permissionedContact &&
1236 (!CRM_Contact_BAO_Contact_Permission::relationship($cid, $contactId))
1237 ) ||
1238 (!CRM_Contact_BAO_Contact_Permission::allow($cid))
1239 ) {
1240 continue;
1241 }
1242 $values[$rid]['id'] = $rid;
1243 $values[$rid]['cid'] = $cid;
1244 $values[$rid]['contact_id_a'] = $relationship->contact_id_a;
1245 $values[$rid]['contact_id_b'] = $relationship->contact_id_b;
1246 $values[$rid]['contact_type'] = $relationship->contact_type;
1247 $values[$rid]['relationship_type_id'] = $relationship->civicrm_relationship_type_id;
1248 $values[$rid]['relation'] = $relationship->relation;
1249 $values[$rid]['name'] = $relationship->sort_name;
1250 $values[$rid]['display_name'] = $relationship->display_name;
1251 $values[$rid]['job_title'] = $relationship->job_title;
1252 $values[$rid]['email'] = $relationship->email;
1253 $values[$rid]['phone'] = $relationship->phone;
1254 $values[$rid]['employer_id'] = $relationship->employer_id;
1255 $values[$rid]['organization_name'] = $relationship->organization_name;
1256 $values[$rid]['country'] = $relationship->country;
1257 $values[$rid]['city'] = $relationship->city;
1258 $values[$rid]['state'] = $relationship->state;
1259 $values[$rid]['start_date'] = $relationship->start_date;
1260 $values[$rid]['end_date'] = $relationship->end_date;
1261 $values[$rid]['description'] = $relationship->description;
1262 $values[$rid]['is_active'] = $relationship->is_active;
1263 $values[$rid]['is_permission_a_b'] = $relationship->is_permission_a_b;
1264 $values[$rid]['is_permission_b_a'] = $relationship->is_permission_b_a;
1265 $values[$rid]['case_id'] = $relationship->case_id;
1266
1267 if ($status) {
1268 $values[$rid]['status'] = $status;
1269 }
1270
1271 $values[$rid]['civicrm_relationship_type_id'] = $relationship->civicrm_relationship_type_id;
1272
1273 if ($relationship->contact_id_a == $contactId) {
1274 $values[$rid]['rtype'] = 'a_b';
1275 }
1276 else {
1277 $values[$rid]['rtype'] = 'b_a';
1278 }
1279
1280 if ($links) {
1281 $replace = array(
1282 'id' => $rid,
1283 'rtype' => $values[$rid]['rtype'],
1284 'cid' => $contactId,
1285 'cbid' => $values[$rid]['cid'],
1286 'caseid' => $values[$rid]['case_id'],
1287 'clientid' => $contactId,
1288 );
1289
1290 if ($status == self::INACTIVE) {
1291 // setting links for inactive relationships
1292 $mask = array_sum(array_keys($links));
1293 if (!$values[$rid]['is_active']) {
1294 $mask -= CRM_Core_Action::DISABLE;
1295 }
1296 else {
1297 $mask -= CRM_Core_Action::ENABLE;
1298 $mask -= CRM_Core_Action::DISABLE;
1299 }
1300 }
1301
1302 // Give access to manage case link by copying to MAX_ACTION index temporarily, depending on case permission of user.
1303 if ($values[$rid]['case_id']) {
1304 // Borrowed logic from CRM_Case_Page_Tab
1305 $hasCaseAccess = FALSE;
1306 if (CRM_Core_Permission::check('access all cases and activities')) {
1307 $hasCaseAccess = TRUE;
1308 }
1309 else {
1310 $userCases = CRM_Case_BAO_Case::getCases(FALSE);
1311 if (array_key_exists($values[$rid]['case_id'], $userCases)) {
1312 $hasCaseAccess = TRUE;
1313 }
1314 }
1315
1316 if ($hasCaseAccess) {
1317 // give access by copying to MAX_ACTION temporarily, otherwise leave at NONE which won't display
1318 $links[CRM_Core_Action::MAX_ACTION] = $links[CRM_Core_Action::NONE];
1319 $links[CRM_Core_Action::MAX_ACTION]['name'] = ts('Manage Case #%1', array(1 => $values[$rid]['case_id']));
1320 $links[CRM_Core_Action::MAX_ACTION]['class'] = 'no-popup';
1321
1322 // Also make sure we have the right client cid since can get here from multiple relationship tabs.
1323 if ($values[$rid]['rtype'] == 'b_a') {
1324 $replace['clientid'] = $values[$rid]['cid'];
1325 }
1326 }
1327 }
1328
1329 $values[$rid]['action'] = CRM_Core_Action::formLink(
1330 $links,
1331 $mask,
1332 $replace,
1333 ts('more'),
1334 FALSE,
1335 'relationship.selector.row',
1336 'Relationship',
1337 $rid);
1338 unset($links[CRM_Core_Action::MAX_ACTION]);
1339 }
1340 }
1341
1342 $relationship->free();
1343 return $values;
1344 }
1345 }
1346
1347 /**
1348 * Get get list of relationship type based on the target contact type.
1349 *
1350 * @param string $targetContactType
1351 * It's valid contact tpye(may be Individual , Organization , Household).
1352 *
1353 * @return array
1354 * array reference of all relationship types with context to current contact type .
1355 */
1356 static public function getRelationType($targetContactType) {
1357 $relationshipType = array();
1358 $allRelationshipType = CRM_Core_PseudoConstant::relationshipType();
1359
1360 foreach ($allRelationshipType as $key => $type) {
1361 if ($type['contact_type_b'] == $targetContactType) {
1362 $relationshipType[$key . '_a_b'] = $type['label_a_b'];
1363 }
1364 }
1365
1366 return $relationshipType;
1367 }
1368
1369 /**
1370 * Create / update / delete membership for related contacts.
1371 *
1372 * This function will create/update/delete membership for related
1373 * contact based on 1) contact have active membership 2) that
1374 * membership is is extedned by the same relationship type to that
1375 * of the existing relationship.
1376 *
1377 * @param int $contactId
1378 * contact id.
1379 * @param array $params
1380 * array of values submitted by POST.
1381 * @param array $ids
1382 * array of ids.
1383 * @param \const|int $action which action called this function
1384 *
1385 * @param bool $active
1386 *
1387 * @throws \CRM_Core_Exception
1388 */
1389 public static function relatedMemberships($contactId, &$params, $ids, $action = CRM_Core_Action::ADD, $active = TRUE) {
1390 // Check the end date and set the status of the relationship
1391 // accordingly.
1392 $status = self::CURRENT;
1393 $targetContact = $targetContact = CRM_Utils_Array::value('contact_check', $params, array());
1394
1395 if (!empty($params['end_date'])) {
1396 $endDate = CRM_Utils_Date::setDateDefaults(CRM_Utils_Date::format($params['end_date']), NULL, 'Ymd');
1397 $today = date('Ymd');
1398
1399 if ($today > $endDate) {
1400 $status = self::PAST;
1401 }
1402 }
1403
1404 if (($action & CRM_Core_Action::ADD) &&
1405 ($status & self::PAST)
1406 ) {
1407 // if relationship is PAST and action is ADD, no qustion
1408 // of creating RELATED membership and return back to
1409 // calling method
1410 return;
1411 }
1412
1413 $rel = explode('_', $params['relationship_type_id']);
1414
1415 $relTypeId = $rel[0];
1416 if (!empty($rel[1])) {
1417 $relDirection = "_{$rel[1]}_{$rel[2]}";
1418 }
1419 else {
1420 // this call is coming from somewhere where the direction was resolved early on (e.g an api call)
1421 // so we can assume _a_b
1422 $relDirection = "_a_b";
1423 $targetContact = array($params['contact_id_b'] => 1);
1424 }
1425
1426 if (($action & CRM_Core_Action::ADD) ||
1427 ($action & CRM_Core_Action::DELETE)
1428 ) {
1429 $contact = $contactId;
1430 }
1431 elseif ($action & CRM_Core_Action::UPDATE) {
1432 $contact = $ids['contact'];
1433 $targetContact = array($ids['contactTarget'] => 1);
1434 }
1435
1436 // Build the 'values' array for
1437 // 1. ContactA
1438 // 2. ContactB
1439 // This will allow us to check if either of the contacts in
1440 // relationship have active memberships.
1441
1442 $values = array();
1443
1444 // 1. ContactA
1445 $values[$contact] = array(
1446 'relatedContacts' => $targetContact,
1447 'relationshipTypeId' => $relTypeId,
1448 'relationshipTypeDirection' => $relDirection,
1449 );
1450 // 2. ContactB
1451 if (!empty($targetContact)) {
1452 foreach ($targetContact as $cid => $donCare) {
1453 $values[$cid] = array(
1454 'relatedContacts' => array($contact => 1),
1455 'relationshipTypeId' => $relTypeId,
1456 );
1457
1458 $relTypeParams = array('id' => $relTypeId);
1459 $relTypeValues = array();
1460 CRM_Contact_BAO_RelationshipType::retrieve($relTypeParams, $relTypeValues);
1461
1462 if (CRM_Utils_Array::value('name_a_b', $relTypeValues) == CRM_Utils_Array::value('name_b_a', $relTypeValues)) {
1463 $values[$cid]['relationshipTypeDirection'] = '_a_b';
1464 }
1465 else {
1466 $values[$cid]['relationshipTypeDirection'] = ($relDirection == '_a_b') ? '_b_a' : '_a_b';
1467 }
1468 }
1469 }
1470
1471 // CRM-15829 UPDATES
1472 // If we're looking for active memberships we must consider pending (id: 5) ones too.
1473 // Hence we can't just call CRM_Member_BAO_Membership::getValues below with the active flag, is it would completely miss pending relatioships.
1474 // As suggested by @davecivicrm, the pending status id is fetched using the CRM_Member_PseudoConstant::membershipStatus() class and method, since these ids differ from system to system.
1475 $pendingStatusId = array_search('Pending', CRM_Member_PseudoConstant::membershipStatus());
1476
1477 $query = 'SELECT * FROM `civicrm_membership_status`';
1478 if ($active) {
1479 $query .= 'WHERE `is_current_member` = 1 OR `id` = %1 ';
1480 }
1481
1482 $params[1] = array($pendingStatusId, 'String');
1483 $dao = CRM_Core_DAO::executeQuery($query, $params);
1484
1485 while ($dao->fetch()) {
1486 $membershipStatusRecordIds[$dao->id] = $dao->id;
1487 }
1488
1489 // Now get the active memberships for all the contacts.
1490 // If contact have any valid membership(s), then add it to
1491 // 'values' array.
1492 foreach ($values as $cid => $subValues) {
1493 $memParams = array('contact_id' => $cid);
1494 $memberships = array();
1495
1496 // CRM-15829 UPDATES
1497 // Since we want PENDING memberships as well, the $active flag needs to be set to false so that this will return all memberships and we can then filter the memberships based on the status IDs recieved above.
1498 CRM_Member_BAO_Membership::getValues($memParams, $memberships, FALSE, TRUE);
1499
1500 // CRM-15829 UPDATES
1501 // filter out the memberships returned by CRM_Member_BAO_Membership::getValues based on the status IDs fetched on line ~1462
1502 foreach ($memberships as $key => $membership) {
1503
1504 if (!isset($memberships[$key]['status_id'])) {
1505 continue;
1506 }
1507
1508 $membershipStatusId = $memberships[$key]['status_id'];
1509 if (!isset($membershipStatusRecordIds[$membershipStatusId])) {
1510 unset($memberships[$key]);
1511 }
1512 }
1513
1514 if (empty($memberships)) {
1515 continue;
1516 }
1517
1518 //get ownerMembershipIds for related Membership
1519 //this is to handle memberships being deleted and recreated
1520 if (!empty($memberships['owner_membership_ids'])) {
1521 $ownerMemIds[$cid] = $memberships['owner_membership_ids'];
1522 unset($memberships['owner_membership_ids']);
1523 }
1524
1525 $values[$cid]['memberships'] = $memberships;
1526 }
1527 $deceasedStatusId = array_search('Deceased', CRM_Member_PseudoConstant::membershipStatus());
1528
1529 // done with 'values' array.
1530 // Finally add / edit / delete memberships for the related contacts
1531
1532 foreach ($values as $cid => $details) {
1533 if (!array_key_exists('memberships', $details)) {
1534 continue;
1535 }
1536
1537 $relatedContacts = array_keys(CRM_Utils_Array::value('relatedContacts', $details, array()));
1538 $mainRelatedContactId = reset($relatedContacts);
1539
1540 foreach ($details['memberships'] as $membershipId => $membershipValues) {
1541 $relTypeIds = array();
1542 if ($action & CRM_Core_Action::DELETE) {
1543 // Delete memberships of the related contacts only if relationship type exists for membership type
1544 $query = "
1545 SELECT relationship_type_id, relationship_direction
1546 FROM civicrm_membership_type
1547 WHERE id = {$membershipValues['membership_type_id']}";
1548 $dao = CRM_Core_DAO::executeQuery($query);
1549 $relTypeDirs = array();
1550 while ($dao->fetch()) {
1551 $relTypeId = $dao->relationship_type_id;
1552 $relDirection = $dao->relationship_direction;
1553 }
1554 $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $relTypeId);
1555 if (in_array($values[$cid]['relationshipTypeId'], $relTypeIds
1556 //CRM-16300 check if owner membership exist for related membership
1557 ) && !empty($membershipValues['owner_membership_id']) && !empty($values[$mainRelatedContactId]['memberships'][$membershipValues['owner_membership_id']])) {
1558 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], $membershipValues['membership_contact_id']);
1559 }
1560 continue;
1561 }
1562 if (($action & CRM_Core_Action::UPDATE) &&
1563 ($status & self::PAST) &&
1564 ($membershipValues['owner_membership_id'])
1565 ) {
1566 // If relationship is PAST and action is UPDATE
1567 // then delete the RELATED membership
1568 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'],
1569 $membershipValues['membership_contact_id']
1570 );
1571 continue;
1572 }
1573
1574 // add / edit the memberships for related
1575 // contacts.
1576
1577 // Get the Membership Type Details.
1578 $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipValues['membership_type_id']);
1579 // Check if contact's relationship type exists in membership type
1580 $relTypeDirs = array();
1581 if (!empty($membershipType['relationship_type_id'])) {
1582 $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_type_id']);
1583 }
1584 if (!empty($membershipType['relationship_direction'])) {
1585 $relDirections = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_direction']);
1586 }
1587 foreach ($relTypeIds as $key => $value) {
1588 $relTypeDirs[] = $value . '_' . $relDirections[$key];
1589 }
1590 $relTypeDir = $details['relationshipTypeId'] . $details['relationshipTypeDirection'];
1591 if (in_array($relTypeDir, $relTypeDirs)) {
1592 // Check if relationship being created/updated is
1593 // similar to that of membership type's
1594 // relationship.
1595
1596 $membershipValues['owner_membership_id'] = $membershipId;
1597 unset($membershipValues['id']);
1598 unset($membershipValues['membership_contact_id']);
1599 unset($membershipValues['contact_id']);
1600 unset($membershipValues['membership_id']);
1601 foreach ($details['relatedContacts'] as $relatedContactId => $donCare) {
1602 $membershipValues['contact_id'] = $relatedContactId;
1603 if ($deceasedStatusId &&
1604 CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $relatedContactId, 'is_deceased')
1605 ) {
1606 $membershipValues['status_id'] = $deceasedStatusId;
1607 $membershipValues['skipStatusCal'] = TRUE;
1608 }
1609 foreach (array(
1610 'join_date',
1611 'start_date',
1612 'end_date',
1613 ) as $dateField) {
1614 if (!empty($membershipValues[$dateField])) {
1615 $membershipValues[$dateField] = CRM_Utils_Date::processDate($membershipValues[$dateField]);
1616 }
1617 }
1618
1619 if ($action & CRM_Core_Action::UPDATE) {
1620 //if updated relationship is already related to contact don't delete existing inherited membership
1621 if (in_array($relTypeId, $relTypeIds
1622 ) && !empty($values[$relatedContactId]['memberships']) && !empty($ownerMemIds
1623 ) && in_array($membershipValues['owner_membership_id'], $ownerMemIds[$relatedContactId])) {
1624 continue;
1625 }
1626
1627 //delete the membership record for related
1628 //contact before creating new membership record.
1629 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $relatedContactId);
1630 }
1631
1632 // check whether we have some related memberships still available
1633 $query = "
1634 SELECT count(*)
1635 FROM civicrm_membership
1636 LEFT JOIN civicrm_membership_status ON (civicrm_membership_status.id = civicrm_membership.status_id)
1637 WHERE membership_type_id = {$membershipValues['membership_type_id']} AND owner_membership_id = {$membershipValues['owner_membership_id']}
1638 AND is_current_member = 1";
1639 $result = CRM_Core_DAO::singleValueQuery($query);
1640 if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) {
1641 CRM_Member_BAO_Membership::create($membershipValues, CRM_Core_DAO::$_nullArray);
1642 }
1643 }
1644 }
1645 elseif ($action & CRM_Core_Action::UPDATE) {
1646 // if action is update and updated relationship do
1647 // not match with the existing
1648 // membership=>relationship then we need to
1649 // delete the membership record created for
1650 // previous relationship.
1651 // CRM-16087 we need to pass ownerMembershipId to deleteRelatedMemberships function
1652 if (empty($params['relationship_ids']) && !empty($params['id'])) {
1653 $relIds = array($params['id']);
1654 }
1655 else {
1656 $relIds = CRM_Utils_Array::value('relationship_ids', $params);
1657 }
1658 if (self::isDeleteRelatedMembership($relTypeIds, $contactId, $mainRelatedContactId, $relTypeId,
1659 $relIds) && !empty($membershipValues['owner_membership_id']
1660 ) && !empty($values[$mainRelatedContactId]['memberships'][$membershipValues['owner_membership_id']])) {
1661 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], $membershipValues['membership_contact_id']);
1662 }
1663 }
1664 }
1665 }
1666 }
1667
1668 /**
1669 * Helper function to check whether to delete the membership or not.
1670 *
1671 * Function takes a list of related membership types and if it is not also passed a
1672 * relationship ID of that types evaluates whether the membership should be deleted.
1673 *
1674 * @param array $membershipTypeRelationshipTypeIDs
1675 * Relation type IDs related to the given membership type.
1676 * @param int $contactId
1677 * @param int $mainRelatedContactId
1678 * @param int $relTypeId
1679 * @param array $relIds
1680 *
1681 * @return bool
1682 */
1683 public static function isDeleteRelatedMembership($membershipTypeRelationshipTypeIDs, $contactId, $mainRelatedContactId, $relTypeId, $relIds) {
1684 if (empty($membershipTypeRelationshipTypeIDs) || in_array($relTypeId, $membershipTypeRelationshipTypeIDs)) {
1685 return FALSE;
1686 }
1687
1688 if (empty($relIds)) {
1689 return FALSE;
1690 }
1691
1692 $relParamas = array(
1693 1 => array($contactId, 'Integer'),
1694 2 => array($mainRelatedContactId, 'Integer'),
1695 );
1696
1697 if ($contactId == $mainRelatedContactId) {
1698 $recordsFound = (int) CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM civicrm_relationship WHERE relationship_type_id IN ( " . implode(',', $membershipTypeRelationshipTypeIDs) . " ) AND
1699 contact_id_a IN ( %1 ) OR contact_id_b IN ( %1 ) AND id IN (" . implode(',', $relIds) . ")", $relParamas);
1700 if ($recordsFound) {
1701 return FALSE;
1702 }
1703 return TRUE;
1704 }
1705
1706 $recordsFound = (int) CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM civicrm_relationship WHERE relationship_type_id IN ( " . implode(',', $membershipTypeRelationshipTypeIDs) . " ) AND contact_id_a IN ( %1, %2 ) AND contact_id_b IN ( %1, %2 ) AND id NOT IN (" . implode(',', $relIds) . ")", $relParamas);
1707
1708 if ($recordsFound) {
1709 return FALSE;
1710 }
1711
1712 return TRUE;
1713 }
1714
1715 /**
1716 * Get Current Employer for Contact.
1717 *
1718 * @param $contactIds
1719 * Contact Ids.
1720 *
1721 * @return array
1722 * array of the current employer
1723 */
1724 public static function getCurrentEmployer($contactIds) {
1725 $contacts = implode(',', $contactIds);
1726
1727 $query = "
1728 SELECT organization_name, id, employer_id
1729 FROM civicrm_contact
1730 WHERE id IN ( {$contacts} )
1731 ";
1732
1733 $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray);
1734 $currentEmployer = array();
1735 while ($dao->fetch()) {
1736 $currentEmployer[$dao->id]['org_id'] = $dao->employer_id;
1737 $currentEmployer[$dao->id]['org_name'] = $dao->organization_name;
1738 }
1739
1740 return $currentEmployer;
1741 }
1742
1743 /**
1744 * Return list of permissioned employer for a given contact.
1745 *
1746 * @param int $contactID
1747 * contact id whose employers.
1748 * are to be found.
1749 * @param string $name
1750 * employers sort name.
1751 *
1752 * @return array
1753 * array of employers.
1754 */
1755 public static function getPermissionedEmployer($contactID, $name = NULL) {
1756 //get the relationship id
1757 $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType',
1758 'Employee of', 'id', 'name_a_b'
1759 );
1760
1761 return self::getPermissionedContacts($contactID, $relTypeId, $name);
1762 }
1763
1764
1765 /**
1766 * Function to return list of permissioned contacts for a given contact and relationship type.
1767 *
1768 * @param int $contactID
1769 * contact id whose permissioned contacts are to be found.
1770 * @param string $relTypeId
1771 * one or more relationship type id's.
1772 * @param string $name
1773 *
1774 * @return array
1775 * Array of contacts
1776 */
1777 public static function getPermissionedContacts($contactID, $relTypeId, $name = NULL) {
1778 $contacts = array();
1779
1780 if ($relTypeId) {
1781 $query = "
1782 SELECT cc.id as id, cc.sort_name as name
1783 FROM civicrm_relationship cr, civicrm_contact cc
1784 WHERE
1785 cr.contact_id_a = %1 AND
1786 cr.relationship_type_id IN (%2) AND
1787 cr.is_permission_a_b = 1 AND
1788 IF(cr.end_date IS NULL, 1, (DATEDIFF( CURDATE( ), cr.end_date ) <= 0)) AND
1789 cr.is_active = 1 AND
1790 cc.id = cr.contact_id_b AND
1791 cc.is_deleted = 0";
1792
1793 if (!empty($name)) {
1794 $name = CRM_Utils_Type::escape($name, 'String');
1795 $query .= "
1796 AND cc.sort_name LIKE '%$name%'";
1797 }
1798
1799 $args = array(1 => array($contactID, 'Integer'), 2 => array($relTypeId, 'String'));
1800 $dao = CRM_Core_DAO::executeQuery($query, $args);
1801
1802 while ($dao->fetch()) {
1803 $contacts[$dao->id] = array(
1804 'name' => $dao->name,
1805 'value' => $dao->id,
1806 );
1807 }
1808 }
1809 return $contacts;
1810 }
1811
1812 /**
1813 * Merge relationships from otherContact to mainContact.
1814 *
1815 * Called during contact merge operation
1816 *
1817 * @param int $mainId
1818 * Contact id of main contact record.
1819 * @param int $otherId
1820 * Contact id of record which is going to merge.
1821 * @param array $sqls
1822 * (reference) array of sql statements to append to.
1823 *
1824 * @see CRM_Dedupe_Merger::cpTables()
1825 */
1826 public static function mergeRelationships($mainId, $otherId, &$sqls) {
1827 // Delete circular relationships
1828 $sqls[] = "DELETE FROM civicrm_relationship
1829 WHERE (contact_id_a = $mainId AND contact_id_b = $otherId)
1830 OR (contact_id_b = $mainId AND contact_id_a = $otherId)";
1831
1832 // Delete relationship from other contact if main contact already has that relationship
1833 $sqls[] = "DELETE r2
1834 FROM civicrm_relationship r1, civicrm_relationship r2
1835 WHERE r1.relationship_type_id = r2.relationship_type_id
1836 AND r1.id <> r2.id
1837 AND (
1838 r1.contact_id_a = $mainId AND r2.contact_id_a = $otherId AND r1.contact_id_b = r2.contact_id_b
1839 OR r1.contact_id_b = $mainId AND r2.contact_id_b = $otherId AND r1.contact_id_a = r2.contact_id_a
1840 OR (
1841 (r1.contact_id_a = $mainId AND r2.contact_id_b = $otherId AND r1.contact_id_b = r2.contact_id_a
1842 OR r1.contact_id_b = $mainId AND r2.contact_id_a = $otherId AND r1.contact_id_a = r2.contact_id_b)
1843 AND r1.relationship_type_id IN (SELECT id FROM civicrm_relationship_type WHERE name_b_a = name_a_b)
1844 )
1845 )";
1846
1847 // Move relationships
1848 $sqls[] = "UPDATE IGNORE civicrm_relationship SET contact_id_a = $mainId WHERE contact_id_a = $otherId";
1849 $sqls[] = "UPDATE IGNORE civicrm_relationship SET contact_id_b = $mainId WHERE contact_id_b = $otherId";
1850
1851 // Move current employer id (name will get updated later)
1852 $sqls[] = "UPDATE civicrm_contact SET employer_id = $mainId WHERE employer_id = $otherId";
1853 }
1854
1855 /**
1856 * Set 'is_valid' field to false for all relationships whose end date is in the past, ie. are expired.
1857 *
1858 * @return bool
1859 * True on success, false if error is encountered.
1860 */
1861 public static function disableExpiredRelationships() {
1862 $query = "SELECT id FROM civicrm_relationship WHERE is_active = 1 AND end_date < CURDATE()";
1863
1864 $dao = CRM_Core_DAO::executeQuery($query);
1865 while ($dao->fetch()) {
1866 $result = CRM_Contact_BAO_Relationship::setIsActive($dao->id, FALSE);
1867 // Result will be NULL if error occurred. We abort early if error detected.
1868 if ($result == NULL) {
1869 return FALSE;
1870 }
1871 }
1872 return TRUE;
1873 }
1874
1875 /**
1876 * Function filters the query by possible relationships for the membership type.
1877 *
1878 * It is intended to be called when constructing queries for the api (reciprocal & non-reciprocal)
1879 * and to add clauses to limit the return to those relationships which COULD inherit a membership type
1880 * (as opposed to those who inherit a particular membership
1881 *
1882 * @param array $params
1883 * Api input array.
1884 * @param null $direction
1885 *
1886 * @return array|void
1887 */
1888 public static function membershipTypeToRelationshipTypes(&$params, $direction = NULL) {
1889 $membershipType = civicrm_api3('membership_type', 'getsingle', array(
1890 'id' => $params['membership_type_id'],
1891 'return' => 'relationship_type_id, relationship_direction',
1892 ));
1893 $relationshipTypes = $membershipType['relationship_type_id'];
1894 if (empty($relationshipTypes)) {
1895 return NULL;
1896 }
1897 // if we don't have any contact data we can only filter on type
1898 if (empty($params['contact_id']) && empty($params['contact_id_a']) && empty($params['contact_id_a'])) {
1899 $params['relationship_type_id'] = array('IN' => $relationshipTypes);
1900 return NULL;
1901 }
1902 else {
1903 $relationshipDirections = (array) $membershipType['relationship_direction'];
1904 // if we have contact_id_a OR contact_id_b we can make a call here
1905 // if we have contact??
1906 foreach ($relationshipDirections as $index => $mtdirection) {
1907 if (isset($params['contact_id_a']) && $mtdirection == 'a_b' || $direction == 'a_b') {
1908 $types[] = $relationshipTypes[$index];
1909 }
1910 if (isset($params['contact_id_b']) && $mtdirection == 'b_a' || $direction == 'b_a') {
1911 $types[] = $relationshipTypes[$index];
1912 }
1913 }
1914 if (!empty($types)) {
1915 $params['relationship_type_id'] = array('IN' => $types);
1916 }
1917 elseif (!empty($clauses)) {
1918 return explode(' OR ', $clauses);
1919 }
1920 else {
1921 // effectively setting it to return no results
1922 $params['relationship_type_id'] = 0;
1923 }
1924 }
1925 }
1926
1927
1928 /**
1929 * Wrapper for contact relationship selector.
1930 *
1931 * @param array $params
1932 * Associated array for params record id.
1933 *
1934 * @return array
1935 * associated array of contact relationships
1936 */
1937 public static function getContactRelationshipSelector(&$params) {
1938 // format the params
1939 $params['offset'] = ($params['page'] - 1) * $params['rp'];
1940 $params['sort'] = CRM_Utils_Array::value('sortBy', $params);
1941
1942 if ($params['context'] == 'past') {
1943 $relationshipStatus = CRM_Contact_BAO_Relationship::INACTIVE;
1944 }
1945 elseif ($params['context'] == 'all') {
1946 $relationshipStatus = CRM_Contact_BAO_Relationship::ALL;
1947 }
1948 else {
1949 $relationshipStatus = CRM_Contact_BAO_Relationship::CURRENT;
1950 }
1951
1952 // check logged in user for permission
1953 $page = new CRM_Core_Page();
1954 CRM_Contact_Page_View::checkUserPermission($page, $params['contact_id']);
1955 $permissions = array($page->_permission);
1956 if ($page->_permission == CRM_Core_Permission::EDIT) {
1957 $permissions[] = CRM_Core_Permission::DELETE;
1958 }
1959 $mask = CRM_Core_Action::mask($permissions);
1960
1961 if ($params['context'] != 'user') {
1962 $links = CRM_Contact_Page_View_Relationship::links();
1963 $permissionedContacts = FALSE;
1964 }
1965 else {
1966 $links = CRM_Contact_Page_View_UserDashBoard::links();
1967 $permissionedContacts = TRUE;
1968 $mask = NULL;
1969 }
1970 // get contact relationships
1971 $relationships = CRM_Contact_BAO_Relationship::getRelationship($params['contact_id'],
1972 $relationshipStatus,
1973 $params['rp'], 0, 0,
1974 $links, $mask,
1975 $permissionedContacts,
1976 $params
1977 );
1978
1979 $contactRelationships = array();
1980 $params['total'] = 0;
1981 if (!empty($relationships)) {
1982 // get the total relationships
1983 if ($params['context'] != 'user') {
1984 $params['total'] = count($relationships);
1985 }
1986 else {
1987 // FIXME: we cannot directly determine total permissioned relationship, hence re-fire query
1988 $permissionedRelationships = CRM_Contact_BAO_Relationship::getRelationship($params['contact_id'],
1989 $relationshipStatus,
1990 0, 0, 0,
1991 NULL, NULL, TRUE
1992 );
1993 $params['total'] = count($permissionedRelationships);
1994 }
1995
1996 // format params
1997 foreach ($relationships as $relationshipId => $values) {
1998 $relationship = array();
1999
2000 $relationship['DT_RowClass'] = 'crm-entity';
2001 if ($values['is_active'] == 0) {
2002 $relationship['DT_RowClass'] .= ' disabled';
2003 }
2004
2005 $relationship['DT_RowData'] = array();
2006 $relationship['DT_RowData']['entity'] = 'relationship';
2007 $relationship['DT_RowData']['id'] = $values['id'];
2008
2009 //Add image icon for related contacts: CRM-14919
2010 $icon = CRM_Contact_BAO_Contact_Utils::getImage($values['contact_type'],
2011 FALSE,
2012 $values['cid']
2013 );
2014 $relationship['sort_name'] = $icon . ' ' . CRM_Utils_System::href(
2015 $values['name'],
2016 'civicrm/contact/view',
2017 "reset=1&cid={$values['cid']}");
2018
2019 $relationship['relation'] = CRM_Utils_System::href(
2020 $values['relation'],
2021 'civicrm/contact/view/rel',
2022 "action=view&reset=1&cid={$values['cid']}&id={$values['id']}&rtype={$values['rtype']}");
2023
2024 if ($params['context'] == 'current') {
2025 if (($params['contact_id'] == $values['contact_id_a'] AND $values['is_permission_a_b'] == 1) OR
2026 ($params['contact_id'] == $values['contact_id_b'] AND $values['is_permission_b_a'] == 1)
2027 ) {
2028 $relationship['sort_name'] .= '<span id="permission-a-b" class="crm-marker permission-relationship"> *</span>';
2029 }
2030
2031 if (($values['cid'] == $values['contact_id_a'] AND $values['is_permission_a_b'] == 1) OR
2032 ($values['cid'] == $values['contact_id_b'] AND $values['is_permission_b_a'] == 1)
2033 ) {
2034 $relationship['relation'] .= '<span id="permission-b-a" class="crm-marker permission-relationship"> *</span>';
2035 }
2036 }
2037
2038 if (!empty($values['description'])) {
2039 $relationship['relation'] .= "<p class='description'>{$values['description']}</p>";
2040 }
2041
2042 $relationship['start_date'] = CRM_Utils_Date::customFormat($values['start_date']);
2043 $relationship['end_date'] = CRM_Utils_Date::customFormat($values['end_date']);
2044 $relationship['city'] = $values['city'];
2045 $relationship['state'] = $values['state'];
2046 $relationship['email'] = $values['email'];
2047 $relationship['phone'] = $values['phone'];
2048 $relationship['links'] = $values['action'];
2049
2050 array_push($contactRelationships, $relationship);
2051 }
2052 }
2053
2054 $relationshipsDT = array();
2055 $relationshipsDT['data'] = $contactRelationships;
2056 $relationshipsDT['recordsTotal'] = $params['total'];
2057 $relationshipsDT['recordsFiltered'] = $params['total'];
2058
2059 return $relationshipsDT;
2060 }
2061
2062 }