Merge pull request #6963 from agileware/4.6-CRM-17402
[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 $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 //CRM-16978:check duplicate relationship as per case id.
193 if ($caseId = CRM_Utils_Array::value('case_id', $params)) {
194 $contactFields['case_id'] = $caseId;
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 in_array($value['contact_sub_type_b'], $contactSubType) ||
565 (!$value['contact_sub_type_a'] && !$onlySubTypeRelationTypes)
566 )
567 ) {
568 $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"];
569 }
570
571 if (((!$value['contact_type_b']) ||
572 $value['contact_type_b'] == $contactType
573 ) &&
574 ((!$value['contact_type_a']) ||
575 (!$otherContactType) ||
576 $value['contact_type_a'] == $otherContactType
577 ) &&
578 (in_array($value['contact_sub_type_b'], $contactSubType) ||
579 in_array($value['contact_sub_type_a'], $contactSubType) ||
580 (!$value['contact_sub_type_b'] && !$onlySubTypeRelationTypes)
581 )
582 ) {
583 $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"];
584 }
585
586 if ($all) {
587 $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"];
588 $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"];
589 }
590 }
591
592 if ($biDirectional) {
593 // lets clean up the data and eliminate all duplicate values
594 // (i.e. the relationship is bi-directional)
595 $relationshipType = array_unique($relationshipType);
596 }
597
598 // sort the relationshipType in ascending order CRM-7736
599 asort($relationshipType);
600 return $relationshipType;
601 }
602
603 /**
604 * Delete current employer relationship.
605 *
606 * @param int $id
607 * @param int $action
608 *
609 * @return CRM_Contact_DAO_Relationship
610 */
611 public static function clearCurrentEmployer($id, $action) {
612 $relationship = new CRM_Contact_DAO_Relationship();
613 $relationship->id = $id;
614 $relationship->find(TRUE);
615
616 //to delete relationship between household and individual \
617 //or between individual and organization
618 if (($action & CRM_Core_Action::DISABLE) || ($action & CRM_Core_Action::DELETE)) {
619 $relTypes = CRM_Utils_Array::index(array('name_a_b'), CRM_Core_PseudoConstant::relationshipType('name'));
620 if ($relationship->relationship_type_id == $relTypes['Employee of']['id'] ||
621 $relationship->relationship_type_id == $relTypes['Household Member of']['id']
622 ) {
623 $sharedContact = new CRM_Contact_DAO_Contact();
624 $sharedContact->id = $relationship->contact_id_a;
625 $sharedContact->find(TRUE);
626
627 // CRM-15881 UPDATES
628 // changed FROM "...relationship->relationship_type_id == 4..." TO "...relationship->relationship_type_id == 5..."
629 // As the system should be looking for type "employer of" (id 5) and not "sibling of" (id 4)
630 // 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.
631 $employerRelTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType', 'Employee of', 'id', 'name_a_b');
632
633 if ($relationship->relationship_type_id == $employerRelTypeId && $relationship->contact_id_b == $sharedContact->employer_id) {
634 CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($relationship->contact_id_a);
635 }
636
637 }
638 }
639 return $relationship;
640 }
641
642 /**
643 * Delete the relationship.
644 *
645 * @param int $id
646 * Relationship id.
647 *
648 * @return null
649 */
650 public static function del($id) {
651 // delete from relationship table
652 CRM_Utils_Hook::pre('delete', 'Relationship', $id, CRM_Core_DAO::$_nullArray);
653
654 $relationship = self::clearCurrentEmployer($id, CRM_Core_Action::DELETE);
655 if (CRM_Core_Permission::access('CiviMember')) {
656 // create $params array which isrequired to delete memberships
657 // of the related contacts.
658 $params = array(
659 'relationship_type_id' => "{$relationship->relationship_type_id}_a_b",
660 'contact_check' => array($relationship->contact_id_b => 1),
661 );
662
663 $ids = array();
664 // calling relatedMemberships to delete the memberships of
665 // related contacts.
666 self::relatedMemberships($relationship->contact_id_a,
667 $params,
668 $ids,
669 CRM_Core_Action::DELETE,
670 FALSE
671 );
672 }
673
674 $relationship->delete();
675 CRM_Core_Session::setStatus(ts('Selected relationship has been deleted successfully.'), ts('Record Deleted'), 'success');
676
677 CRM_Utils_Hook::post('delete', 'Relationship', $id, $relationship);
678
679 // delete the recently created Relationship
680 $relationshipRecent = array(
681 'id' => $id,
682 'type' => 'Relationship',
683 );
684 CRM_Utils_Recent::del($relationshipRecent);
685
686 return $relationship;
687 }
688
689 /**
690 * Disable/enable the relationship.
691 *
692 * @param int $id
693 * Relationship id.
694 *
695 * @param int $action
696 * @param array $params
697 * @param array $ids
698 * @param bool $active
699 */
700 public static function disableEnableRelationship($id, $action, $params = array(), $ids = array(), $active = FALSE) {
701 $relationship = self::clearCurrentEmployer($id, $action);
702
703 if ($id) {
704 // create $params array which is required to delete memberships
705 // of the related contacts.
706 if (empty($params)) {
707 $params = array(
708 'relationship_type_id' => "{$relationship->relationship_type_id}_a_b",
709 'contact_check' => array($relationship->contact_id_b => 1),
710 );
711 }
712 $contact_id_a = empty($params['contact_id_a']) ? $relationship->contact_id_a : $params['contact_id_a'];
713 // calling relatedMemberships to delete/add the memberships of
714 // related contacts.
715 if ($action & CRM_Core_Action::DISABLE) {
716 CRM_Contact_BAO_Relationship::relatedMemberships($contact_id_a,
717 $params,
718 $ids,
719 CRM_Core_Action::DELETE,
720 $active
721 );
722 }
723 elseif ($action & CRM_Core_Action::ENABLE) {
724 $ids['contact'] = empty($ids['contact']) ? $contact_id_a : $ids['contact'];
725 CRM_Contact_BAO_Relationship::relatedMemberships($contact_id_a,
726 $params,
727 $ids,
728 empty($params['id']) ? CRM_Core_Action::ADD : CRM_Core_Action::UPDATE,
729 $active
730 );
731 }
732 }
733 }
734
735 /**
736 * Delete the object records that are associated with this contact.
737 *
738 * @param int $contactId
739 * Id of the contact to delete.
740 */
741 public static function deleteContact($contactId) {
742 $relationship = new CRM_Contact_DAO_Relationship();
743 $relationship->contact_id_a = $contactId;
744 $relationship->delete();
745
746 $relationship = new CRM_Contact_DAO_Relationship();
747 $relationship->contact_id_b = $contactId;
748 $relationship->delete();
749
750 CRM_Contact_BAO_Household::updatePrimaryContact(NULL, $contactId);
751 }
752
753 /**
754 * Get the other contact in a relationship.
755 *
756 * @param int $id
757 * Relationship id.
758 *
759 * $returns returns the contact ids in the realtionship
760 *
761 * @return \CRM_Contact_DAO_Relationship
762 */
763 public static function getRelationshipByID($id) {
764 $relationship = new CRM_Contact_DAO_Relationship();
765
766 $relationship->id = $id;
767 $relationship->selectAdd();
768 $relationship->selectAdd('contact_id_a, contact_id_b');
769 $relationship->find(TRUE);
770
771 return $relationship;
772 }
773
774 /**
775 * Check if the relationship type selected between two contacts is correct.
776 *
777 * @param int $contact_a
778 * 1st contact id.
779 * @param int $contact_b
780 * 2nd contact id.
781 * @param int $relationshipTypeId
782 * Relationship type id.
783 *
784 * @return bool
785 * true if it is valid relationship else false
786 */
787 public static function checkRelationshipType($contact_a, $contact_b, $relationshipTypeId) {
788 $relationshipType = new CRM_Contact_DAO_RelationshipType();
789 $relationshipType->id = $relationshipTypeId;
790 $relationshipType->selectAdd();
791 $relationshipType->selectAdd('contact_type_a, contact_type_b, contact_sub_type_a, contact_sub_type_b');
792 if ($relationshipType->find(TRUE)) {
793 $contact_type_a = CRM_Contact_BAO_Contact::getContactType($contact_a);
794 $contact_type_b = CRM_Contact_BAO_Contact::getContactType($contact_b);
795
796 $contact_sub_type_a = CRM_Contact_BAO_Contact::getContactSubType($contact_a);
797 $contact_sub_type_b = CRM_Contact_BAO_Contact::getContactSubType($contact_b);
798
799 if (((!$relationshipType->contact_type_a) || ($relationshipType->contact_type_a == $contact_type_a)) &&
800 ((!$relationshipType->contact_type_b) || ($relationshipType->contact_type_b == $contact_type_b)) &&
801 ((!$relationshipType->contact_sub_type_a) || (in_array($relationshipType->contact_sub_type_a,
802 $contact_sub_type_a
803 ))) &&
804 ((!$relationshipType->contact_sub_type_b) || (in_array($relationshipType->contact_sub_type_b,
805 $contact_sub_type_b
806 )))
807 ) {
808 return TRUE;
809 }
810 else {
811 return FALSE;
812 }
813 }
814 return FALSE;
815 }
816
817 /**
818 * This function does the validtion for valid relationship.
819 *
820 * @param array $params
821 * This array contains the values there are subitted by the form.
822 * @param array $ids
823 * The array that holds all the db ids.
824 * @param int $contactId
825 * This is contact id for adding relationship.
826 *
827 * @return string
828 */
829 public static function checkValidRelationship($params, $ids, $contactId) {
830 $errors = '';
831 // function to check if the relationship selected is correct
832 // i.e. employer relationship can exit between Individual and Organization (not between Individual and Individual)
833 if (!CRM_Contact_BAO_Relationship::checkRelationshipType($params['contact_id_a'], $params['contact_id_b'],
834 $params['relationship_type_id'])) {
835 $errors = 'Please select valid relationship between these two contacts.';
836 }
837 return $errors;
838 }
839
840 /**
841 * This function checks for duplicate relationship.
842 *
843 * @param array $params
844 * (reference ) an assoc array of name/value pairs.
845 * @param int $id
846 * This the id of the contact whom we are adding relationship.
847 * @param int $contactId
848 * This is contact id for adding relationship.
849 * @param int $relationshipId
850 * This is relationship id for the contact.
851 *
852 * @return bool
853 * true if record exists else false
854 */
855 public static function checkDuplicateRelationship(&$params, $id, $contactId = 0, $relationshipId = 0) {
856 $relationshipTypeId = CRM_Utils_Array::value('relationship_type_id', $params);
857 list($type) = explode('_', $relationshipTypeId);
858
859 $queryString = "
860 SELECT id
861 FROM civicrm_relationship
862 WHERE relationship_type_id = " . CRM_Utils_Type::escape($type, 'Integer');
863
864 /*
865 * CRM-11792 - date fields from API are in ISO format, but this function
866 * supports date arrays BAO has increasingly standardised to ISO format
867 * so I believe this function should support ISO rather than make API
868 * format it - however, need to support array format for now to avoid breakage
869 * @ time of writing this function is called from Relationship::legacyCreateMultiple (twice)
870 * CRM_BAO_Contact_Utils::clearCurrentEmployer (seemingly without dates)
871 * CRM_Contact_Form_Task_AddToOrganization::postProcess &
872 * CRM_Contact_Form_Task_AddToHousehold::postProcess
873 * (I don't think the last 2 support dates but not sure
874 */
875
876 $dateFields = array('end_date', 'start_date');
877 foreach ($dateFields as $dateField) {
878 if (array_key_exists($dateField, $params)) {
879 if (empty($params[$dateField]) || $params[$dateField] == 'null') {
880 //this is most likely coming from an api call & probably loaded
881 // from the DB to deal with some of the
882 // other myriad of excessive checks still in place both in
883 // the api & the create functions
884 $queryString .= " AND $dateField IS NULL";
885 continue;
886 }
887 elseif (is_array($params[$dateField])) {
888 $queryString .= " AND $dateField = " .
889 CRM_Utils_Type::escape(CRM_Utils_Date::format($params[$dateField]), 'Date');
890 }
891 else {
892 $queryString .= " AND $dateField = " .
893 CRM_Utils_Type::escape($params[$dateField], 'Date');
894 }
895 }
896 }
897
898 $queryString .=
899 " AND ( ( contact_id_a = " . CRM_Utils_Type::escape($id, 'Integer') .
900 " AND contact_id_b = " . CRM_Utils_Type::escape($contactId, 'Integer') .
901 " ) OR ( contact_id_a = " . CRM_Utils_Type::escape($contactId, 'Integer') .
902 " AND contact_id_b = " . CRM_Utils_Type::escape($id, 'Integer') . " ) ) ";
903
904 //if caseId is provided, include it duplicate checking.
905 if ($caseId = CRM_Utils_Array::value('case_id', $params)) {
906 $queryString .= " AND case_id = " . CRM_Utils_Type::escape($caseId, 'Integer');
907 }
908
909 if ($relationshipId) {
910 $queryString .= " AND id !=" . CRM_Utils_Type::escape($relationshipId, 'Integer');
911 }
912
913 $relationship = new CRM_Contact_BAO_Relationship();
914 $relationship->query($queryString);
915 $relationship->fetch();
916 $relationship->free();
917 return ($relationship->id) ? TRUE : FALSE;
918 }
919
920 /**
921 * Update the is_active flag in the db.
922 *
923 * @param int $id
924 * Id of the database record.
925 * @param bool $is_active
926 * Value we want to set the is_active field.
927 *
928 * @throws CiviCRM_API3_Exception
929 * @return Object
930 * DAO object on success, null otherwise
931 */
932 public static function setIsActive($id, $is_active) {
933 // as both the create & add functions have a bunch of logic in them that
934 // doesn't seem to cope with a normal update we will call the api which
935 // has tested handling for this
936 // however, a longer term solution would be to simplify the add, create & api functions
937 // to be more standard. It is debatable @ that point whether it's better to call the BAO
938 // direct as the api is more tested.
939 $result = civicrm_api('relationship', 'create', array(
940 'id' => $id,
941 'is_active' => $is_active,
942 'version' => 3,
943 ));
944
945 if (is_array($result) && !empty($result['is_error']) && $result['error_message'] != 'Duplicate Relationship') {
946 throw new CiviCRM_API3_Exception($result['error_message'], CRM_Utils_Array::value('error_code', $result, 'undefined'), $result);
947 }
948
949 return TRUE;
950 }
951
952 /**
953 * Fetch a relationship object and store the values in the values array.
954 *
955 * @param array $params
956 * Input parameters to find object.
957 * @param array $values
958 * Output values of the object.
959 *
960 * @return array
961 * (reference) the values that could be potentially assigned to smarty
962 */
963 public static function &getValues(&$params, &$values) {
964 if (empty($params)) {
965 return NULL;
966 }
967 $v = array();
968
969 // get the specific number of relationship or all relationships.
970 if (!empty($params['numRelationship'])) {
971 $v['data'] = &CRM_Contact_BAO_Relationship::getRelationship($params['contact_id'], NULL, $params['numRelationship']);
972 }
973 else {
974 $v['data'] = CRM_Contact_BAO_Relationship::getRelationship($params['contact_id']);
975 }
976
977 // get the total count of relationships
978 $v['totalCount'] = count($v['data']);
979
980 $values['relationship']['data'] = &$v['data'];
981 $values['relationship']['totalCount'] = &$v['totalCount'];
982
983 return $v;
984 }
985
986 /**
987 * Helper function to form the sql for relationship retrieval.
988 *
989 * @param int $contactId
990 * Contact id.
991 * @param int $status
992 * (check const at top of file).
993 * @param int $numRelationship
994 * No of relationships to display (limit).
995 * @param int $count
996 * Get the no of relationships.
997 * $param int $relationshipId relationship id
998 * @param int $relationshipId
999 * @param string $direction
1000 * The direction we are interested in a_b or b_a.
1001 * @param array $params
1002 * Array of extra values including relationship_type_id per api spec.
1003 *
1004 * @return array
1005 * [select, from, where]
1006 */
1007 public static function makeURLClause($contactId, $status, $numRelationship, $count, $relationshipId, $direction, $params = array()) {
1008 $select = $from = $where = '';
1009
1010 $select = '( ';
1011 if ($count) {
1012 if ($direction == 'a_b') {
1013 $select .= ' SELECT count(DISTINCT civicrm_relationship.id) as cnt1, 0 as cnt2 ';
1014 }
1015 else {
1016 $select .= ' SELECT 0 as cnt1, count(DISTINCT civicrm_relationship.id) as cnt2 ';
1017 }
1018 }
1019 else {
1020 $select .= ' SELECT civicrm_relationship.id as civicrm_relationship_id,
1021 civicrm_contact.sort_name as sort_name,
1022 civicrm_contact.display_name as display_name,
1023 civicrm_contact.job_title as job_title,
1024 civicrm_contact.employer_id as employer_id,
1025 civicrm_contact.organization_name as organization_name,
1026 civicrm_address.street_address as street_address,
1027 civicrm_address.city as city,
1028 civicrm_address.postal_code as postal_code,
1029 civicrm_state_province.abbreviation as state,
1030 civicrm_country.name as country,
1031 civicrm_email.email as email,
1032 civicrm_contact.contact_type as contact_type,
1033 civicrm_phone.phone as phone,
1034 civicrm_contact.id as civicrm_contact_id,
1035 civicrm_relationship.contact_id_b as contact_id_b,
1036 civicrm_relationship.contact_id_a as contact_id_a,
1037 civicrm_relationship_type.id as civicrm_relationship_type_id,
1038 civicrm_relationship.start_date as start_date,
1039 civicrm_relationship.end_date as end_date,
1040 civicrm_relationship.description as description,
1041 civicrm_relationship.is_active as is_active,
1042 civicrm_relationship.is_permission_a_b as is_permission_a_b,
1043 civicrm_relationship.is_permission_b_a as is_permission_b_a,
1044 civicrm_relationship.case_id as case_id';
1045
1046 if ($direction == 'a_b') {
1047 $select .= ', civicrm_relationship_type.label_a_b as label_a_b,
1048 civicrm_relationship_type.label_b_a as relation ';
1049 }
1050 else {
1051 $select .= ', civicrm_relationship_type.label_a_b as label_a_b,
1052 civicrm_relationship_type.label_a_b as relation ';
1053 }
1054 }
1055
1056 $from = "
1057 FROM civicrm_relationship
1058 INNER JOIN civicrm_relationship_type ON ( civicrm_relationship.relationship_type_id = civicrm_relationship_type.id )
1059 INNER JOIN civicrm_contact ";
1060 if ($direction == 'a_b') {
1061 $from .= 'ON ( civicrm_contact.id = civicrm_relationship.contact_id_a ) ';
1062 }
1063 else {
1064 $from .= 'ON ( civicrm_contact.id = civicrm_relationship.contact_id_b ) ';
1065 }
1066 $from .= "
1067 LEFT JOIN civicrm_address ON (civicrm_address.contact_id = civicrm_contact.id AND civicrm_address.is_primary = 1)
1068 LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = civicrm_contact.id AND civicrm_phone.is_primary = 1)
1069 LEFT JOIN civicrm_email ON (civicrm_email.contact_id = civicrm_contact.id AND civicrm_email.is_primary = 1)
1070 LEFT JOIN civicrm_state_province ON (civicrm_address.state_province_id = civicrm_state_province.id)
1071 LEFT JOIN civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
1072 ";
1073 $where = 'WHERE ( 1 )';
1074 if ($contactId) {
1075 if ($direction == 'a_b') {
1076 $where .= ' AND civicrm_relationship.contact_id_b = ' . CRM_Utils_Type::escape($contactId, 'Positive');
1077 }
1078 else {
1079 $where .= ' AND civicrm_relationship.contact_id_a = ' . CRM_Utils_Type::escape($contactId, 'Positive') . '
1080 AND civicrm_relationship.contact_id_a != civicrm_relationship.contact_id_b ';
1081 }
1082 }
1083 if ($relationshipId) {
1084 $where .= ' AND civicrm_relationship.id = ' . CRM_Utils_Type::escape($relationshipId, 'Positive');
1085 }
1086
1087 $date = date('Y-m-d');
1088 if ($status == self::PAST) {
1089 //this case for showing past relationship
1090 $where .= ' AND civicrm_relationship.is_active = 1 ';
1091 $where .= " AND civicrm_relationship.end_date < '" . $date . "'";
1092 }
1093 elseif ($status == self::DISABLED) {
1094 // this case for showing disabled relationship
1095 $where .= ' AND civicrm_relationship.is_active = 0 ';
1096 }
1097 elseif ($status == self::CURRENT) {
1098 //this case for showing current relationship
1099 $where .= ' AND civicrm_relationship.is_active = 1 ';
1100 $where .= " AND (civicrm_relationship.end_date >= '" . $date . "' OR civicrm_relationship.end_date IS NULL) ";
1101 }
1102 elseif ($status == self::INACTIVE) {
1103 //this case for showing inactive relationships
1104 $where .= " AND (civicrm_relationship.end_date < '" . $date . "'";
1105 $where .= ' OR civicrm_relationship.is_active = 0 )';
1106 }
1107
1108 // CRM-6181
1109 $where .= ' AND civicrm_contact.is_deleted = 0';
1110 if (!empty($params['membership_type_id']) && empty($params['relationship_type_id'])) {
1111 $where .= self::membershipTypeToRelationshipTypes($params, $direction);
1112 }
1113 if (!empty($params['relationship_type_id'])) {
1114 if (is_array($params['relationship_type_id'])) {
1115 $where .= " AND " . CRM_Core_DAO::createSQLFilter('relationship_type_id', $params['relationship_type_id'], 'Integer');
1116 }
1117 else {
1118 $where .= ' AND relationship_type_id = ' . CRM_Utils_Type::escape($params['relationship_type_id'], 'Positive');
1119 }
1120 }
1121 if ($direction == 'a_b') {
1122 $where .= ' ) UNION ';
1123 }
1124 else {
1125 $where .= ' ) ';
1126 }
1127
1128 return array($select, $from, $where);
1129 }
1130
1131 /**
1132 * Get a list of relationships.
1133 *
1134 * @param int $contactId
1135 * Contact id.
1136 * @param int $status
1137 * 1: Past 2: Disabled 3: Current.
1138 * @param int $numRelationship
1139 * No of relationships to display (limit).
1140 * @param int $count
1141 * Get the no of relationships.
1142 * @param int $relationshipId
1143 * @param array $links
1144 * the list of links to display
1145 * @param int $permissionMask
1146 * the permission mask to be applied for the actions
1147 * @param bool $permissionedContact
1148 * to return only permissioned Contact
1149 * @param array $params
1150 *
1151 * @return array|int
1152 * relationship records
1153 */
1154 public static function getRelationship(
1155 $contactId = NULL,
1156 $status = 0, $numRelationship = 0,
1157 $count = 0, $relationshipId = 0,
1158 $links = NULL, $permissionMask = NULL,
1159 $permissionedContact = FALSE,
1160 $params = array()
1161 ) {
1162 $values = array();
1163 if (!$contactId && !$relationshipId) {
1164 return $values;
1165 }
1166
1167 list($select1, $from1, $where1) = self::makeURLClause($contactId, $status, $numRelationship,
1168 $count, $relationshipId, 'a_b', $params
1169 );
1170 list($select2, $from2, $where2) = self::makeURLClause($contactId, $status, $numRelationship,
1171 $count, $relationshipId, 'b_a', $params
1172 );
1173
1174 $order = $limit = '';
1175 if (!$count) {
1176 if (empty($params['sort'])) {
1177 $order = ' ORDER BY civicrm_relationship_type_id, sort_name ';
1178 }
1179 else {
1180 $order = " ORDER BY {$params['sort']} ";
1181 }
1182
1183 $offset = 0;
1184 if (!empty($params['offset']) && $params['offset'] > 0) {
1185 $offset = $params['offset'];
1186 }
1187
1188 if ($numRelationship) {
1189 $limit = " LIMIT {$offset}, $numRelationship";
1190 }
1191 }
1192
1193 // building the query string
1194 $queryString = $select1 . $from1 . $where1 . $select2 . $from2 . $where2 . $order . $limit;
1195
1196 $relationship = new CRM_Contact_DAO_Relationship();
1197
1198 $relationship->query($queryString);
1199 $row = array();
1200 if ($count) {
1201 $relationshipCount = 0;
1202 while ($relationship->fetch()) {
1203 $relationshipCount += $relationship->cnt1 + $relationship->cnt2;
1204 }
1205 return $relationshipCount;
1206 }
1207 else {
1208
1209 $mask = NULL;
1210 if ($status != self::INACTIVE) {
1211 if ($links) {
1212 $mask = array_sum(array_keys($links));
1213 if ($mask & CRM_Core_Action::DISABLE) {
1214 $mask -= CRM_Core_Action::DISABLE;
1215 }
1216 if ($mask & CRM_Core_Action::ENABLE) {
1217 $mask -= CRM_Core_Action::ENABLE;
1218 }
1219
1220 if ($status == self::CURRENT) {
1221 $mask |= CRM_Core_Action::DISABLE;
1222 }
1223 elseif ($status == self::DISABLED) {
1224 $mask |= CRM_Core_Action::ENABLE;
1225 }
1226 $mask = $mask & $permissionMask;
1227 }
1228 }
1229
1230 while ($relationship->fetch()) {
1231 $rid = $relationship->civicrm_relationship_id;
1232 $cid = $relationship->civicrm_contact_id;
1233
1234 if ($permissionedContact &&
1235 (!CRM_Contact_BAO_Contact_Permission::allow($cid))
1236 ) {
1237 continue;
1238 }
1239 $values[$rid]['id'] = $rid;
1240 $values[$rid]['cid'] = $cid;
1241 $values[$rid]['contact_id_a'] = $relationship->contact_id_a;
1242 $values[$rid]['contact_id_b'] = $relationship->contact_id_b;
1243 $values[$rid]['contact_type'] = $relationship->contact_type;
1244 $values[$rid]['relationship_type_id'] = $relationship->civicrm_relationship_type_id;
1245 $values[$rid]['relation'] = $relationship->relation;
1246 $values[$rid]['name'] = $relationship->sort_name;
1247 $values[$rid]['display_name'] = $relationship->display_name;
1248 $values[$rid]['job_title'] = $relationship->job_title;
1249 $values[$rid]['email'] = $relationship->email;
1250 $values[$rid]['phone'] = $relationship->phone;
1251 $values[$rid]['employer_id'] = $relationship->employer_id;
1252 $values[$rid]['organization_name'] = $relationship->organization_name;
1253 $values[$rid]['country'] = $relationship->country;
1254 $values[$rid]['city'] = $relationship->city;
1255 $values[$rid]['state'] = $relationship->state;
1256 $values[$rid]['start_date'] = $relationship->start_date;
1257 $values[$rid]['end_date'] = $relationship->end_date;
1258 $values[$rid]['description'] = $relationship->description;
1259 $values[$rid]['is_active'] = $relationship->is_active;
1260 $values[$rid]['is_permission_a_b'] = $relationship->is_permission_a_b;
1261 $values[$rid]['is_permission_b_a'] = $relationship->is_permission_b_a;
1262 $values[$rid]['case_id'] = $relationship->case_id;
1263
1264 if ($status) {
1265 $values[$rid]['status'] = $status;
1266 }
1267
1268 $values[$rid]['civicrm_relationship_type_id'] = $relationship->civicrm_relationship_type_id;
1269
1270 if ($relationship->contact_id_a == $contactId) {
1271 $values[$rid]['rtype'] = 'a_b';
1272 }
1273 else {
1274 $values[$rid]['rtype'] = 'b_a';
1275 }
1276
1277 if ($links) {
1278 $replace = array(
1279 'id' => $rid,
1280 'rtype' => $values[$rid]['rtype'],
1281 'cid' => $contactId,
1282 'cbid' => $values[$rid]['cid'],
1283 'caseid' => $values[$rid]['case_id'],
1284 'clientid' => $contactId,
1285 );
1286
1287 if ($status == self::INACTIVE) {
1288 // setting links for inactive relationships
1289 $mask = array_sum(array_keys($links));
1290 if (!$values[$rid]['is_active']) {
1291 $mask -= CRM_Core_Action::DISABLE;
1292 }
1293 else {
1294 $mask -= CRM_Core_Action::ENABLE;
1295 $mask -= CRM_Core_Action::DISABLE;
1296 }
1297 $mask = $mask & $permissionMask;
1298 }
1299
1300 // Give access to manage case link by copying to MAX_ACTION index temporarily, depending on case permission of user.
1301 if ($values[$rid]['case_id']) {
1302 // Borrowed logic from CRM_Case_Page_Tab
1303 $hasCaseAccess = FALSE;
1304 if (CRM_Core_Permission::check('access all cases and activities')) {
1305 $hasCaseAccess = TRUE;
1306 }
1307 else {
1308 $userCases = CRM_Case_BAO_Case::getCases(FALSE);
1309 if (array_key_exists($values[$rid]['case_id'], $userCases)) {
1310 $hasCaseAccess = TRUE;
1311 }
1312 }
1313
1314 if ($hasCaseAccess) {
1315 // give access by copying to MAX_ACTION temporarily, otherwise leave at NONE which won't display
1316 $links[CRM_Core_Action::MAX_ACTION] = $links[CRM_Core_Action::NONE];
1317 $links[CRM_Core_Action::MAX_ACTION]['name'] = ts('Manage Case #%1', array(1 => $values[$rid]['case_id']));
1318 $links[CRM_Core_Action::MAX_ACTION]['class'] = 'no-popup';
1319
1320 // Also make sure we have the right client cid since can get here from multiple relationship tabs.
1321 if ($values[$rid]['rtype'] == 'b_a') {
1322 $replace['clientid'] = $values[$rid]['cid'];
1323 }
1324 }
1325 }
1326
1327 $values[$rid]['action'] = CRM_Core_Action::formLink(
1328 $links,
1329 $mask,
1330 $replace,
1331 ts('more'),
1332 FALSE,
1333 'relationship.selector.row',
1334 'Relationship',
1335 $rid);
1336 unset($links[CRM_Core_Action::MAX_ACTION]);
1337 }
1338 }
1339
1340 $relationship->free();
1341 return $values;
1342 }
1343 }
1344
1345 /**
1346 * Get get list of relationship type based on the target contact type.
1347 *
1348 * @param string $targetContactType
1349 * It's valid contact tpye(may be Individual , Organization , Household).
1350 *
1351 * @return array
1352 * array reference of all relationship types with context to current contact type .
1353 */
1354 static public function getRelationType($targetContactType) {
1355 $relationshipType = array();
1356 $allRelationshipType = CRM_Core_PseudoConstant::relationshipType();
1357
1358 foreach ($allRelationshipType as $key => $type) {
1359 if ($type['contact_type_b'] == $targetContactType) {
1360 $relationshipType[$key . '_a_b'] = $type['label_a_b'];
1361 }
1362 }
1363
1364 return $relationshipType;
1365 }
1366
1367 /**
1368 * Create / update / delete membership for related contacts.
1369 *
1370 * This function will create/update/delete membership for related
1371 * contact based on 1) contact have active membership 2) that
1372 * membership is is extedned by the same relationship type to that
1373 * of the existing relationship.
1374 *
1375 * @param int $contactId
1376 * contact id.
1377 * @param array $params
1378 * array of values submitted by POST.
1379 * @param array $ids
1380 * array of ids.
1381 * @param \const|int $action which action called this function
1382 *
1383 * @param bool $active
1384 *
1385 * @throws \CRM_Core_Exception
1386 */
1387 public static function relatedMemberships($contactId, &$params, $ids, $action = CRM_Core_Action::ADD, $active = TRUE) {
1388 // Check the end date and set the status of the relationship
1389 // accordingly.
1390 $status = self::CURRENT;
1391 $targetContact = $targetContact = CRM_Utils_Array::value('contact_check', $params, array());
1392
1393 if (!empty($params['end_date'])) {
1394 $endDate = CRM_Utils_Date::setDateDefaults(CRM_Utils_Date::format($params['end_date']), NULL, 'Ymd');
1395 $today = date('Ymd');
1396
1397 if ($today > $endDate) {
1398 $status = self::PAST;
1399 }
1400 }
1401
1402 if (($action & CRM_Core_Action::ADD) &&
1403 ($status & self::PAST)
1404 ) {
1405 // if relationship is PAST and action is ADD, no qustion
1406 // of creating RELATED membership and return back to
1407 // calling method
1408 return;
1409 }
1410
1411 $rel = explode('_', $params['relationship_type_id']);
1412
1413 $relTypeId = $rel[0];
1414 if (!empty($rel[1])) {
1415 $relDirection = "_{$rel[1]}_{$rel[2]}";
1416 }
1417 else {
1418 // this call is coming from somewhere where the direction was resolved early on (e.g an api call)
1419 // so we can assume _a_b
1420 $relDirection = "_a_b";
1421 $targetContact = array($params['contact_id_b'] => 1);
1422 }
1423
1424 if (($action & CRM_Core_Action::ADD) ||
1425 ($action & CRM_Core_Action::DELETE)
1426 ) {
1427 $contact = $contactId;
1428 }
1429 elseif ($action & CRM_Core_Action::UPDATE) {
1430 $contact = $ids['contact'];
1431 $targetContact = array($ids['contactTarget'] => 1);
1432 }
1433
1434 // Build the 'values' array for
1435 // 1. ContactA
1436 // 2. ContactB
1437 // This will allow us to check if either of the contacts in
1438 // relationship have active memberships.
1439
1440 $values = array();
1441
1442 // 1. ContactA
1443 $values[$contact] = array(
1444 'relatedContacts' => $targetContact,
1445 'relationshipTypeId' => $relTypeId,
1446 'relationshipTypeDirection' => $relDirection,
1447 );
1448 // 2. ContactB
1449 if (!empty($targetContact)) {
1450 foreach ($targetContact as $cid => $donCare) {
1451 $values[$cid] = array(
1452 'relatedContacts' => array($contact => 1),
1453 'relationshipTypeId' => $relTypeId,
1454 );
1455
1456 $relTypeParams = array('id' => $relTypeId);
1457 $relTypeValues = array();
1458 CRM_Contact_BAO_RelationshipType::retrieve($relTypeParams, $relTypeValues);
1459
1460 if (CRM_Utils_Array::value('name_a_b', $relTypeValues) == CRM_Utils_Array::value('name_b_a', $relTypeValues)) {
1461 $values[$cid]['relationshipTypeDirection'] = '_a_b';
1462 }
1463 else {
1464 $values[$cid]['relationshipTypeDirection'] = ($relDirection == '_a_b') ? '_b_a' : '_a_b';
1465 }
1466 }
1467 }
1468
1469 // CRM-15829 UPDATES
1470 // If we're looking for active memberships we must consider pending (id: 5) ones too.
1471 // Hence we can't just call CRM_Member_BAO_Membership::getValues below with the active flag, is it would completely miss pending relatioships.
1472 // 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.
1473 $pendingStatusId = array_search('Pending', CRM_Member_PseudoConstant::membershipStatus());
1474
1475 $query = 'SELECT * FROM `civicrm_membership_status`';
1476 if ($active) {
1477 $query .= 'WHERE `is_current_member` = 1 OR `id` = %1 ';
1478 }
1479
1480 $params[1] = array($pendingStatusId, 'String');
1481 $dao = CRM_Core_DAO::executeQuery($query, $params);
1482
1483 while ($dao->fetch()) {
1484 $membershipStatusRecordIds[$dao->id] = $dao->id;
1485 }
1486
1487 // Now get the active memberships for all the contacts.
1488 // If contact have any valid membership(s), then add it to
1489 // 'values' array.
1490 foreach ($values as $cid => $subValues) {
1491 $memParams = array('contact_id' => $cid);
1492 $memberships = array();
1493
1494 // CRM-15829 UPDATES
1495 // 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.
1496 CRM_Member_BAO_Membership::getValues($memParams, $memberships, FALSE, TRUE);
1497
1498 // CRM-15829 UPDATES
1499 // filter out the memberships returned by CRM_Member_BAO_Membership::getValues based on the status IDs fetched on line ~1462
1500 foreach ($memberships as $key => $membership) {
1501
1502 if (!isset($memberships[$key]['status_id'])) {
1503 continue;
1504 }
1505
1506 $membershipStatusId = $memberships[$key]['status_id'];
1507 if (!isset($membershipStatusRecordIds[$membershipStatusId])) {
1508 unset($memberships[$key]);
1509 }
1510 }
1511
1512 if (empty($memberships)) {
1513 continue;
1514 }
1515
1516 //get ownerMembershipIds for related Membership
1517 //this is to handle memberships being deleted and recreated
1518 if (!empty($memberships['owner_membership_ids'])) {
1519 $ownerMemIds[$cid] = $memberships['owner_membership_ids'];
1520 unset($memberships['owner_membership_ids']);
1521 }
1522
1523 $values[$cid]['memberships'] = $memberships;
1524 }
1525 $deceasedStatusId = array_search('Deceased', CRM_Member_PseudoConstant::membershipStatus());
1526
1527 // done with 'values' array.
1528 // Finally add / edit / delete memberships for the related contacts
1529
1530 foreach ($values as $cid => $details) {
1531 if (!array_key_exists('memberships', $details)) {
1532 continue;
1533 }
1534
1535 $relatedContacts = array_keys(CRM_Utils_Array::value('relatedContacts', $details, array()));
1536 $mainRelatedContactId = reset($relatedContacts);
1537
1538 foreach ($details['memberships'] as $membershipId => $membershipValues) {
1539 $relTypeIds = array();
1540 if ($action & CRM_Core_Action::DELETE) {
1541 // Delete memberships of the related contacts only if relationship type exists for membership type
1542 $query = "
1543 SELECT relationship_type_id, relationship_direction
1544 FROM civicrm_membership_type
1545 WHERE id = {$membershipValues['membership_type_id']}";
1546 $dao = CRM_Core_DAO::executeQuery($query);
1547 $relTypeDirs = array();
1548 while ($dao->fetch()) {
1549 $relTypeId = $dao->relationship_type_id;
1550 $relDirection = $dao->relationship_direction;
1551 }
1552 $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $relTypeId);
1553 if (in_array($values[$cid]['relationshipTypeId'], $relTypeIds
1554 //CRM-16300 check if owner membership exist for related membership
1555 ) && !empty($membershipValues['owner_membership_id']) && !empty($values[$mainRelatedContactId]['memberships'][$membershipValues['owner_membership_id']])) {
1556 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], $membershipValues['membership_contact_id']);
1557 }
1558 continue;
1559 }
1560 if (($action & CRM_Core_Action::UPDATE) &&
1561 ($status & self::PAST) &&
1562 ($membershipValues['owner_membership_id'])
1563 ) {
1564 // If relationship is PAST and action is UPDATE
1565 // then delete the RELATED membership
1566 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'],
1567 $membershipValues['membership_contact_id']
1568 );
1569 continue;
1570 }
1571
1572 // add / edit the memberships for related
1573 // contacts.
1574
1575 // Get the Membership Type Details.
1576 $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipValues['membership_type_id']);
1577 // Check if contact's relationship type exists in membership type
1578 $relTypeDirs = array();
1579 if (!empty($membershipType['relationship_type_id'])) {
1580 $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_type_id']);
1581 }
1582 if (!empty($membershipType['relationship_direction'])) {
1583 $relDirections = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_direction']);
1584 }
1585 foreach ($relTypeIds as $key => $value) {
1586 $relTypeDirs[] = $value . '_' . $relDirections[$key];
1587 }
1588 $relTypeDir = $details['relationshipTypeId'] . $details['relationshipTypeDirection'];
1589 if (in_array($relTypeDir, $relTypeDirs)) {
1590 // Check if relationship being created/updated is
1591 // similar to that of membership type's
1592 // relationship.
1593
1594 $membershipValues['owner_membership_id'] = $membershipId;
1595 unset($membershipValues['id']);
1596 unset($membershipValues['membership_contact_id']);
1597 unset($membershipValues['contact_id']);
1598 unset($membershipValues['membership_id']);
1599 foreach ($details['relatedContacts'] as $relatedContactId => $donCare) {
1600 $membershipValues['contact_id'] = $relatedContactId;
1601 if ($deceasedStatusId &&
1602 CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $relatedContactId, 'is_deceased')
1603 ) {
1604 $membershipValues['status_id'] = $deceasedStatusId;
1605 $membershipValues['skipStatusCal'] = TRUE;
1606 }
1607 foreach (array(
1608 'join_date',
1609 'start_date',
1610 'end_date',
1611 ) as $dateField) {
1612 if (!empty($membershipValues[$dateField])) {
1613 $membershipValues[$dateField] = CRM_Utils_Date::processDate($membershipValues[$dateField]);
1614 }
1615 }
1616
1617 if ($action & CRM_Core_Action::UPDATE) {
1618 //if updated relationship is already related to contact don't delete existing inherited membership
1619 if (in_array($relTypeId, $relTypeIds
1620 ) && !empty($values[$relatedContactId]['memberships']) && !empty($ownerMemIds
1621 ) && in_array($membershipValues['owner_membership_id'], $ownerMemIds[$relatedContactId])) {
1622 continue;
1623 }
1624
1625 //delete the membership record for related
1626 //contact before creating new membership record.
1627 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $relatedContactId);
1628 }
1629
1630 // check whether we have some related memberships still available
1631 $query = "
1632 SELECT count(*)
1633 FROM civicrm_membership
1634 LEFT JOIN civicrm_membership_status ON (civicrm_membership_status.id = civicrm_membership.status_id)
1635 WHERE membership_type_id = {$membershipValues['membership_type_id']} AND owner_membership_id = {$membershipValues['owner_membership_id']}
1636 AND is_current_member = 1";
1637 $result = CRM_Core_DAO::singleValueQuery($query);
1638 if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) {
1639 CRM_Member_BAO_Membership::create($membershipValues, CRM_Core_DAO::$_nullArray);
1640 }
1641 }
1642 }
1643 elseif ($action & CRM_Core_Action::UPDATE) {
1644 // if action is update and updated relationship do
1645 // not match with the existing
1646 // membership=>relationship then we need to
1647 // delete the membership record created for
1648 // previous relationship.
1649 // CRM-16087 we need to pass ownerMembershipId to deleteRelatedMemberships function
1650 if (empty($params['relationship_ids']) && !empty($params['id'])) {
1651 $relIds = array($params['id']);
1652 }
1653 else {
1654 $relIds = CRM_Utils_Array::value('relationship_ids', $params);
1655 }
1656 if (self::isDeleteRelatedMembership($relTypeIds, $contactId, $mainRelatedContactId, $relTypeId,
1657 $relIds) && !empty($membershipValues['owner_membership_id']
1658 ) && !empty($values[$mainRelatedContactId]['memberships'][$membershipValues['owner_membership_id']])) {
1659 CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], $membershipValues['membership_contact_id']);
1660 }
1661 }
1662 }
1663 }
1664 }
1665
1666 /**
1667 * Helper function to check whether to delete the membership or not.
1668 *
1669 * Function takes a list of related membership types and if it is not also passed a
1670 * relationship ID of that types evaluates whether the membership should be deleted.
1671 *
1672 * @param array $membershipTypeRelationshipTypeIDs
1673 * Relation type IDs related to the given membership type.
1674 * @param int $contactId
1675 * @param int $mainRelatedContactId
1676 * @param int $relTypeId
1677 * @param array $relIds
1678 *
1679 * @return bool
1680 */
1681 public static function isDeleteRelatedMembership($membershipTypeRelationshipTypeIDs, $contactId, $mainRelatedContactId, $relTypeId, $relIds) {
1682 if (empty($membershipTypeRelationshipTypeIDs) || in_array($relTypeId, $membershipTypeRelationshipTypeIDs)) {
1683 return FALSE;
1684 }
1685
1686 if (empty($relIds)) {
1687 return FALSE;
1688 }
1689
1690 $relParamas = array(
1691 1 => array($contactId, 'Integer'),
1692 2 => array($mainRelatedContactId, 'Integer'),
1693 );
1694
1695 if ($contactId == $mainRelatedContactId) {
1696 $recordsFound = (int) CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM civicrm_relationship WHERE relationship_type_id IN ( " . implode(',', $membershipTypeRelationshipTypeIDs) . " ) AND
1697 contact_id_a IN ( %1 ) OR contact_id_b IN ( %1 ) AND id IN (" . implode(',', $relIds) . ")", $relParamas);
1698 if ($recordsFound) {
1699 return FALSE;
1700 }
1701 return TRUE;
1702 }
1703
1704 $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);
1705
1706 if ($recordsFound) {
1707 return FALSE;
1708 }
1709
1710 return TRUE;
1711 }
1712
1713 /**
1714 * Get Current Employer for Contact.
1715 *
1716 * @param $contactIds
1717 * Contact Ids.
1718 *
1719 * @return array
1720 * array of the current employer
1721 */
1722 public static function getCurrentEmployer($contactIds) {
1723 $contacts = implode(',', $contactIds);
1724
1725 $query = "
1726 SELECT organization_name, id, employer_id
1727 FROM civicrm_contact
1728 WHERE id IN ( {$contacts} )
1729 ";
1730
1731 $dao = CRM_Core_DAO::executeQuery($query, CRM_Core_DAO::$_nullArray);
1732 $currentEmployer = array();
1733 while ($dao->fetch()) {
1734 $currentEmployer[$dao->id]['org_id'] = $dao->employer_id;
1735 $currentEmployer[$dao->id]['org_name'] = $dao->organization_name;
1736 }
1737
1738 return $currentEmployer;
1739 }
1740
1741 /**
1742 * Return list of permissioned employer for a given contact.
1743 *
1744 * @param int $contactID
1745 * contact id whose employers.
1746 * are to be found.
1747 * @param string $name
1748 * employers sort name.
1749 *
1750 * @return array
1751 * array of employers.
1752 */
1753 public static function getPermissionedEmployer($contactID, $name = NULL) {
1754 //get the relationship id
1755 $relTypeId = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType',
1756 'Employee of', 'id', 'name_a_b'
1757 );
1758
1759 return self::getPermissionedContacts($contactID, $relTypeId, $name);
1760 }
1761
1762
1763 /**
1764 * Function to return list of permissioned contacts for a given contact and relationship type.
1765 *
1766 * @param int $contactID
1767 * contact id whose permissioned contacts are to be found.
1768 * @param string $relTypeId
1769 * one or more relationship type id's.
1770 * @param string $name
1771 *
1772 * @return array
1773 * Array of contacts
1774 */
1775 public static function getPermissionedContacts($contactID, $relTypeId, $name = NULL) {
1776 $contacts = array();
1777
1778 if ($relTypeId) {
1779 $query = "
1780 SELECT cc.id as id, cc.sort_name as name
1781 FROM civicrm_relationship cr, civicrm_contact cc
1782 WHERE
1783 cr.contact_id_a = %1 AND
1784 cr.relationship_type_id IN (%2) AND
1785 cr.is_permission_a_b = 1 AND
1786 IF(cr.end_date IS NULL, 1, (DATEDIFF( CURDATE( ), cr.end_date ) <= 0)) AND
1787 cr.is_active = 1 AND
1788 cc.id = cr.contact_id_b AND
1789 cc.is_deleted = 0";
1790
1791 if (!empty($name)) {
1792 $name = CRM_Utils_Type::escape($name, 'String');
1793 $query .= "
1794 AND cc.sort_name LIKE '%$name%'";
1795 }
1796
1797 $args = array(1 => array($contactID, 'Integer'), 2 => array($relTypeId, 'String'));
1798 $dao = CRM_Core_DAO::executeQuery($query, $args);
1799
1800 while ($dao->fetch()) {
1801 $contacts[$dao->id] = array(
1802 'name' => $dao->name,
1803 'value' => $dao->id,
1804 );
1805 }
1806 }
1807 return $contacts;
1808 }
1809
1810 /**
1811 * Merge relationships from otherContact to mainContact.
1812 *
1813 * Called during contact merge operation
1814 *
1815 * @param int $mainId
1816 * Contact id of main contact record.
1817 * @param int $otherId
1818 * Contact id of record which is going to merge.
1819 * @param array $sqls
1820 * (reference) array of sql statements to append to.
1821 *
1822 * @see CRM_Dedupe_Merger::cpTables()
1823 */
1824 public static function mergeRelationships($mainId, $otherId, &$sqls) {
1825 // Delete circular relationships
1826 $sqls[] = "DELETE FROM civicrm_relationship
1827 WHERE (contact_id_a = $mainId AND contact_id_b = $otherId)
1828 OR (contact_id_b = $mainId AND contact_id_a = $otherId)";
1829
1830 // Delete relationship from other contact if main contact already has that relationship
1831 $sqls[] = "DELETE r2
1832 FROM civicrm_relationship r1, civicrm_relationship r2
1833 WHERE r1.relationship_type_id = r2.relationship_type_id
1834 AND r1.id <> r2.id
1835 AND (
1836 r1.contact_id_a = $mainId AND r2.contact_id_a = $otherId AND r1.contact_id_b = r2.contact_id_b
1837 OR r1.contact_id_b = $mainId AND r2.contact_id_b = $otherId AND r1.contact_id_a = r2.contact_id_a
1838 OR (
1839 (r1.contact_id_a = $mainId AND r2.contact_id_b = $otherId AND r1.contact_id_b = r2.contact_id_a
1840 OR r1.contact_id_b = $mainId AND r2.contact_id_a = $otherId AND r1.contact_id_a = r2.contact_id_b)
1841 AND r1.relationship_type_id IN (SELECT id FROM civicrm_relationship_type WHERE name_b_a = name_a_b)
1842 )
1843 )";
1844
1845 // Move relationships
1846 $sqls[] = "UPDATE IGNORE civicrm_relationship SET contact_id_a = $mainId WHERE contact_id_a = $otherId";
1847 $sqls[] = "UPDATE IGNORE civicrm_relationship SET contact_id_b = $mainId WHERE contact_id_b = $otherId";
1848
1849 // Move current employer id (name will get updated later)
1850 $sqls[] = "UPDATE civicrm_contact SET employer_id = $mainId WHERE employer_id = $otherId";
1851 }
1852
1853 /**
1854 * Set 'is_valid' field to false for all relationships whose end date is in the past, ie. are expired.
1855 *
1856 * @return bool
1857 * True on success, false if error is encountered.
1858 */
1859 public static function disableExpiredRelationships() {
1860 $query = "SELECT id FROM civicrm_relationship WHERE is_active = 1 AND end_date < CURDATE()";
1861
1862 $dao = CRM_Core_DAO::executeQuery($query);
1863 while ($dao->fetch()) {
1864 $result = CRM_Contact_BAO_Relationship::setIsActive($dao->id, FALSE);
1865 // Result will be NULL if error occurred. We abort early if error detected.
1866 if ($result == NULL) {
1867 return FALSE;
1868 }
1869 }
1870 return TRUE;
1871 }
1872
1873 /**
1874 * Function filters the query by possible relationships for the membership type.
1875 *
1876 * It is intended to be called when constructing queries for the api (reciprocal & non-reciprocal)
1877 * and to add clauses to limit the return to those relationships which COULD inherit a membership type
1878 * (as opposed to those who inherit a particular membership
1879 *
1880 * @param array $params
1881 * Api input array.
1882 * @param null $direction
1883 *
1884 * @return array|void
1885 */
1886 public static function membershipTypeToRelationshipTypes(&$params, $direction = NULL) {
1887 $membershipType = civicrm_api3('membership_type', 'getsingle', array(
1888 'id' => $params['membership_type_id'],
1889 'return' => 'relationship_type_id, relationship_direction',
1890 ));
1891 $relationshipTypes = $membershipType['relationship_type_id'];
1892 if (empty($relationshipTypes)) {
1893 return NULL;
1894 }
1895 // if we don't have any contact data we can only filter on type
1896 if (empty($params['contact_id']) && empty($params['contact_id_a']) && empty($params['contact_id_a'])) {
1897 $params['relationship_type_id'] = array('IN' => $relationshipTypes);
1898 return NULL;
1899 }
1900 else {
1901 $relationshipDirections = (array) $membershipType['relationship_direction'];
1902 // if we have contact_id_a OR contact_id_b we can make a call here
1903 // if we have contact??
1904 foreach ($relationshipDirections as $index => $mtdirection) {
1905 if (isset($params['contact_id_a']) && $mtdirection == 'a_b' || $direction == 'a_b') {
1906 $types[] = $relationshipTypes[$index];
1907 }
1908 if (isset($params['contact_id_b']) && $mtdirection == 'b_a' || $direction == 'b_a') {
1909 $types[] = $relationshipTypes[$index];
1910 }
1911 }
1912 if (!empty($types)) {
1913 $params['relationship_type_id'] = array('IN' => $types);
1914 }
1915 elseif (!empty($clauses)) {
1916 return explode(' OR ', $clauses);
1917 }
1918 else {
1919 // effectively setting it to return no results
1920 $params['relationship_type_id'] = 0;
1921 }
1922 }
1923 }
1924
1925
1926 /**
1927 * Wrapper for contact relationship selector.
1928 *
1929 * @param array $params
1930 * Associated array for params record id.
1931 *
1932 * @return array
1933 * associated array of contact relationships
1934 */
1935 public static function getContactRelationshipSelector(&$params) {
1936 // format the params
1937 $params['offset'] = ($params['page'] - 1) * $params['rp'];
1938 $params['sort'] = CRM_Utils_Array::value('sortBy', $params);
1939
1940 if ($params['context'] == 'past') {
1941 $relationshipStatus = CRM_Contact_BAO_Relationship::INACTIVE;
1942 }
1943 elseif ($params['context'] == 'all') {
1944 $relationshipStatus = CRM_Contact_BAO_Relationship::ALL;
1945 }
1946 else {
1947 $relationshipStatus = CRM_Contact_BAO_Relationship::CURRENT;
1948 }
1949
1950 // check logged in user for permission
1951 $page = new CRM_Core_Page();
1952 CRM_Contact_Page_View::checkUserPermission($page, $params['contact_id']);
1953 $permissions = array($page->_permission);
1954 if ($page->_permission == CRM_Core_Permission::EDIT) {
1955 $permissions[] = CRM_Core_Permission::DELETE;
1956 }
1957 $mask = CRM_Core_Action::mask($permissions);
1958
1959 $permissionedContacts = TRUE;
1960 if ($params['context'] != 'user') {
1961 $links = CRM_Contact_Page_View_Relationship::links();
1962 }
1963 else {
1964 $links = CRM_Contact_Page_View_UserDashBoard::links();
1965 $mask = NULL;
1966 }
1967 // get contact relationships
1968 $relationships = CRM_Contact_BAO_Relationship::getRelationship($params['contact_id'],
1969 $relationshipStatus,
1970 $params['rp'], 0, 0,
1971 $links, $mask,
1972 $permissionedContacts,
1973 $params
1974 );
1975
1976 $contactRelationships = array();
1977 $params['total'] = 0;
1978 if (!empty($relationships)) {
1979 // FIXME: 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,
1984 $permissionedContacts
1985 );
1986 $params['total'] = count($permissionedRelationships);
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 }