Fix for CRM-15750 advanced search using relationship and smart group produces backtrace
[civicrm-core.git] / CRM / Contact / BAO / Relationship.php
index ff62ead6704b27e62b08acea3d533385088fe76b..15c4dc0d4a02492ed63b1c4f829abee876b7cc22 100644 (file)
@@ -1,9 +1,9 @@
 <?php
 /*
  +--------------------------------------------------------------------+
- | CiviCRM version 4.4                                                |
+ | CiviCRM version 4.5                                                |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2013                                |
+ | Copyright CiviCRM LLC (c) 2004-2014                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
@@ -28,7 +28,7 @@
 /**
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2013
+ * @copyright CiviCRM LLC (c) 2004-2014
  * $Id$
  *
  */
@@ -56,7 +56,7 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
    */
   static function create(&$params, $ids = array()) {
     $valid = $invalid = $duplicate = $saved = 0;
-    $relationships = array();
+    $relationships = $relationshipIds = array();
     $relationshipId = CRM_Utils_Array::value('relationship', $ids, CRM_Utils_Array::value('id', $params));
     //CRM-9015 - the hooks are called here & in add (since add doesn't call create)
     // but in future should be tidied per ticket
@@ -261,7 +261,7 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
 
     $relationship->free();
 
-    CRM_Utils_Hook::post($hook, 'Relationship', $relationshipId, $relationship);
+    CRM_Utils_Hook::post($hook, 'Relationship', $relationship->id, $relationship);
 
     return $relationship;
   }
@@ -305,18 +305,21 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
   /**
    * Function to get get list of relationship type based on the contact type.
    *
-   * @param int     $contactId      this is the contact id of the current contact.
-   * @param string  $strContact     this value is currently ignored, keeping it there for legacy reasons
-   * @param string  $relationshipId the id of the existing relationship if any
-   * @param string  $contactType    contact type
-   * @param boolean $all            if true returns relationship types in both the direction
-   * @param string  $column         name/label that going to retrieve from db.
+   * @param int $contactId this is the contact id of the current contact.
+   * @param null $contactSuffix
+   * @param string $relationshipId the id of the existing relationship if any
+   * @param string $contactType contact type
+   * @param boolean $all if true returns relationship types in both the direction
+   * @param string $column name/label that going to retrieve from db.
    *
    *
-   * @param string  $contactSubType includes relationshiptypes between this subtype
+   * @param bool $biDirectional
+   * @param string $contactSubType includes relationshiptypes between this subtype
    *
    * @param boolean $onlySubTypeRelationTypes if set only subtype which is passed by $contactSubType
    *                                          related relationshiptypes get return
+   *
+   * @internal param string $strContact this value is currently ignored, keeping it there for legacy reasons
    * @access public
    * @static
    *
@@ -372,6 +375,7 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
         ) &&
         (!$contactSubType ||
           (in_array($value['contact_sub_type_a'], $contactSubType) ||
+            in_array($value['contact_sub_type_b'], $contactSubType) ||
             ((!$value['contact_sub_type_b'] &&
                 !$value['contact_sub_type_a']
               ) &&
@@ -382,10 +386,6 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
       ) {
         $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"];
       }
-      elseif (empty($value['contact_type_b'])) {
-        // case contact_type_b is "all contacts", CRM-9877
-        $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"];
-      }
 
       if (((!$value['contact_type_b']) ||
           $value['contact_type_b'] == $contactType
@@ -396,6 +396,7 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
         ) &&
         (!$contactSubType ||
           (in_array($value['contact_sub_type_b'], $contactSubType) ||
+            in_array($value['contact_sub_type_a'], $contactSubType) ||
             ((!$value['contact_sub_type_a'] &&
                 !$value['contact_sub_type_b']
               ) &&
@@ -406,10 +407,6 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
       ) {
         $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"];
       }
-      elseif (empty($value['contact_type_a'])) {
-        // case contact_type_a is "all contacts", CRM-9877
-        $relationshipType[$key . '_b_a'] = $value["{$column}_b_a"];
-      }
 
       if ($all) {
         $relationshipType[$key . '_a_b'] = $value["{$column}_a_b"];
@@ -428,6 +425,12 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
     return $relationshipType;
   }
 
+  /**
+   * @param $id
+   * @param $action
+   *
+   * @return CRM_Contact_DAO_Relationship
+   */
   static function clearCurrentEmployer($id, $action) {
     $relationship = new CRM_Contact_DAO_Relationship();
     $relationship->id = $id;
@@ -488,7 +491,7 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
     $relationship->delete();
     CRM_Core_Session::setStatus(ts('Selected relationship has been deleted successfully.'), ts('Record Deleted'), 'success');
 
-    CRM_Utils_Hook::post('delete', 'Relationship', $relationship->id, $relationship);
+    CRM_Utils_Hook::post('delete', 'Relationship', $id, $relationship);
 
     // delete the recently created Relationship
     $relationshipRecent = array(
@@ -505,9 +508,10 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
    *
    * @param int $id relationship id
    *
+   * @param $action
+   *
    * @return null
    * @access public
-
    * @static
    */
   static function disableEnableRelationship($id, $action) {
@@ -570,6 +574,8 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
    * @param int $id relationship id
    *
    * $returns  returns the contact ids in the realtionship
+   *
+   * @return \CRM_Contact_DAO_Relationship
    * @access public
    * @static
    */
@@ -628,12 +634,12 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
   /**
    * this function does the validtion for valid relationship
    *
-   * @param array   $params     this array contains the values there are subitted by the form
-   * @param array   $ids        the array that holds all the db ids
-   * @param integer $contactId  this is contact id for adding relationship
+   * @param array $params this array contains the values there are subitted by the form
+   * @param array $ids the array that holds all the db ids
+   * @param integer $contactId this is contact id for adding relationship
    *
-   * @return
-   * @access public
+   * @return string
+  @access public
    * @static
    */
   static function checkValidRelationship(&$params, &$ids, $contactId) {
@@ -732,9 +738,10 @@ WHERE  relationship_type_id = " . CRM_Utils_Type::escape($type, 'Integer');
   /**
    * update the is_active flag in the db
    *
-   * @param int      $id        id of the database record
-   * @param boolean  $is_active value we want to set the is_active field
+   * @param int $id id of the database record
+   * @param boolean $is_active value we want to set the is_active field
    *
+   * @throws CiviCRM_API3_Exception
    * @return Object             DAO object on success, null otherwise
    * @static
    */
@@ -745,7 +752,15 @@ WHERE  relationship_type_id = " . CRM_Utils_Type::escape($type, 'Integer');
     // however, a longer term solution would be to simplify the add, create & api functions
     // to be more standard. It is debatable @ that point whether it's better to call the BAO
     // direct as the api is more tested.
-    civicrm_api3('relationship', 'create', array('id' => $id, 'is_active' => $is_active));
+    $result = civicrm_api('relationship', 'create', array(
+      'id' => $id,
+      'is_active' => $is_active,
+      'version' => 3,
+    ));
+
+    if (is_array($result) && !empty($result['is_error']) && $result['error_message'] != 'Relationship already exists') {
+      throw new CiviCRM_API3_Exception($result['error_message'], CRM_Utils_Array::value('error_code', $result, 'undefined'), $result);
+    }
 
     // call (undocumented possibly deprecated) hook
     CRM_Utils_Hook::enableDisable('CRM_Contact_BAO_Relationship', $id, $is_active);
@@ -757,9 +772,9 @@ WHERE  relationship_type_id = " . CRM_Utils_Type::escape($type, 'Integer');
    * Given the list of params in the params array, fetch the object
    * and store the values in the values array
    *
-   * @param array $params        input parameters to find object
-   * @param array $values        output values of the object
-   * @param array $ids           the array that holds all the db ids
+   * @param array $params input parameters to find object
+   * @param array $values output values of the object
+   * @internal param array $ids the array that holds all the db ids
    *
    * @return array (reference)   the values that could be potentially assigned to smarty
    * @access public
@@ -796,10 +811,13 @@ WHERE  relationship_type_id = " . CRM_Utils_Type::escape($type, 'Integer');
    * @param int $numRelationship no of relationships to display (limit)
    * @param int $count get the no of relationships
    * $param int $relationshipId relationship id
-   * @param string $direction   the direction we are interested in a_b or b_a
+   * @param $relationshipId
+   * @param string $direction the direction we are interested in a_b or b_a
    * @param array $params array of extra values including relationship_type_id per api spec
    *
    * return string the query for this diretion
+   *
+   * @return array
    * @static
    * @access public
    */
@@ -828,9 +846,9 @@ WHERE  relationship_type_id = " . CRM_Utils_Type::escape($type, 'Integer');
                               civicrm_state_province.abbreviation as state,
                               civicrm_country.name as country,
                               civicrm_email.email as email,
+                              civicrm_contact.contact_type as contact_type,
                               civicrm_phone.phone as phone,
                               civicrm_contact.id as civicrm_contact_id,
-                              civicrm_contact.contact_type as contact_type,
                               civicrm_relationship.contact_id_b as contact_id_b,
                               civicrm_relationship.contact_id_a as contact_id_a,
                               civicrm_relationship_type.id as civicrm_relationship_type_id,
@@ -875,7 +893,8 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
         $where .= ' AND civicrm_relationship.contact_id_b = ' . CRM_Utils_Type::escape($contactId, 'Positive');
       }
       else {
-        $where .= ' AND civicrm_relationship.contact_id_a = ' . CRM_Utils_Type::escape($contactId, 'Positive');
+        $where .= ' AND civicrm_relationship.contact_id_a = ' . CRM_Utils_Type::escape($contactId, 'Positive') . '
+                    AND civicrm_relationship.contact_id_a != civicrm_relationship.contact_id_b ';
       }
     }
     if ($relationshipId) {
@@ -939,6 +958,13 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
    * $param boolean $permissionedContact to return only permissioned Contact
    * $param array $params array of variables consistent with filters supported by the api
    * return array $values relationship records
+   * @param int $relationshipId
+   * @param null $links
+   * @param null $permissionMask
+   * @param bool $permissionedContact
+   * @param array $params
+   *
+   * @return array|int
    * @static
    * @access public
    */
@@ -1028,6 +1054,7 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
         $values[$rid]['cid'] = $cid;
         $values[$rid]['contact_id_a'] = $relationship->contact_id_a;
         $values[$rid]['contact_id_b'] = $relationship->contact_id_b;
+        $values[$rid]['contact_type'] = $relationship->contact_type;
         $values[$rid]['relationship_type_id'] = $relationship->civicrm_relationship_type_id;
         $values[$rid]['relation'] = $relationship->relation;
         $values[$rid]['name'] = $relationship->sort_name;
@@ -1101,6 +1128,7 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
               // give access by copying to MAX_ACTION temporarily, otherwise leave at NONE which won't display
               $links[CRM_Core_Action::MAX_ACTION] = $links[CRM_Core_Action::NONE];
               $links[CRM_Core_Action::MAX_ACTION]['name'] = ts('Manage Case #%1', array(1 => $values[$rid]['case_id']));
+              $links[CRM_Core_Action::MAX_ACTION]['class'] = 'no-popup';
 
               // Also make sure we have the right client cid since can get here from multiple relationship tabs.
               if ($values[$rid]['rtype'] == 'b_a') {
@@ -1110,8 +1138,8 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
           }
 
           $values[$rid]['action'] = CRM_Core_Action::formLink(
-            $links, 
-            $mask, 
+            $links,
+            $mask,
             $replace,
             ts('more'),
             FALSE,
@@ -1159,10 +1187,11 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
    * @param $contactId  Int     contact id
    * @param $params     array   array of values submitted by POST
    * @param $ids        array   array of ids
-   * @param $action             which action called this function
+   * @param \const|\which $action which action called this function
    *
-   * @static
+   * @param bool $active
    *
+   * @static
    */
   static function relatedMemberships($contactId, &$params, $ids, $action = CRM_Core_Action::ADD, $active = TRUE) {
     // Check the end date and set the status of the relationship
@@ -1414,10 +1443,7 @@ SELECT count(*)
    *
    * @param $contactIds       Contact Ids
    *
-   * @return $currentEmployer array of the current employer
-   *
-   * @static
-   *
+   * @return array $currentEmployer array of the current employer@static
    */
   static function getCurrentEmployer($contactIds) {
     $contacts = implode(',', $contactIds);
@@ -1572,6 +1598,9 @@ AND cc.sort_name LIKE '%$name%'";
    * (as opposed to those who inherit a particular membership
    *
    * @param array $params api input array
+   * @param null $direction
+   *
+   * @return array
    */
   static function membershipTypeToRelationshipTypes(&$params, $direction = NULL) {
     $membershipType = civicrm_api3('membership_type', 'getsingle', array('id' => $params['membership_type_id'], 'return' => 'relationship_type_id, relationship_direction'));
@@ -1677,15 +1706,20 @@ AND cc.sort_name LIKE '%$name%'";
 
       // format params
       foreach ($relationships as $relationshipId => $values) {
-        $contactRelationships[$relationshipId]['name'] = CRM_Utils_System::href(
+        //Add image icon for related contacts: CRM-14919
+        $icon = CRM_Contact_BAO_Contact_Utils::getImage($values['contact_type'],
+          FALSE,
+          $values['cid']
+        );
+        $contactRelationships[$relationshipId]['name'] = $icon.' '.CRM_Utils_System::href(
           $values['name'],
           'civicrm/contact/view',
-          "reset=1&cid={$values['contact_id_b']}");
+          "reset=1&cid={$values['cid']}");
 
         $contactRelationships[$relationshipId]['relation'] = CRM_Utils_System::href(
           $values['relation'],
           'civicrm/contact/view/rel',
-          "action=view&reset=1&cid={$values['contact_id_a']}&id={$values['id']}&rtype={$values['rtype']}");
+          "action=view&reset=1&cid={$values['cid']}&id={$values['id']}&rtype={$values['rtype']}");
 
         if ($params['context'] == 'current') {
           if (($params['contact_id'] == $values['contact_id_a'] AND $values['is_permission_a_b'] == 1) OR