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