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