CRM-16483 - Fix search builder groups operators
authorColeman Watts <coleman@civicrm.org>
Sun, 10 May 2015 01:35:58 +0000 (21:35 -0400)
committerColeman Watts <coleman@civicrm.org>
Sun, 10 May 2015 01:35:58 +0000 (21:35 -0400)
CRM/Contact/BAO/Query.php
CRM/Core/BAO/Mapping.php

index ef207bbb058a92f26d1c7542367592ea9ce4b5bd..a17756fa7759b50496250ded0ddc8d5a139e84a4 100644 (file)
@@ -2804,13 +2804,19 @@ class CRM_Contact_BAO_Query {
       $this->_useDistinct = TRUE;
     }
 
-    $groupNames = CRM_Core_PseudoConstant::group();
-    $groupIds = implode(',', array_keys($value));
+    // Replace pseudo operators from search builder
+    $op = str_replace('EMPTY', 'NULL', $op);
 
+    $groupNames = CRM_Core_PseudoConstant::group();
+    $groupIds = '';
     $names = array();
-    foreach ($value as $id => $dontCare) {
-      if (array_key_exists($id, $groupNames) && $dontCare) {
-        $names[] = $groupNames[$id];
+
+    if ($value) {
+      $groupIds = implode(',', array_keys($value));
+      foreach ($value as $id => $dontCare) {
+        if (array_key_exists($id, $groupNames) && $dontCare) {
+          $names[] = $groupNames[$id];
+        }
       }
     }
 
@@ -2855,19 +2861,36 @@ class CRM_Contact_BAO_Query {
 
     if (!$skipGroup) {
       $gcTable = "`civicrm_group_contact-{$groupIds}`";
-      $this->_tables[$gcTable] = $this->_whereTables[$gcTable] = " LEFT JOIN civicrm_group_contact {$gcTable} ON ( contact_a.id = {$gcTable}.contact_id AND {$gcTable}.group_id $op ( $groupIds ) )";
+      $joinClause = array("contact_a.id = {$gcTable}.contact_id");
+      if ($groupIds && ($op == 'IN' || $op == 'NOT IN')) {
+        $joinClause[] = "{$gcTable}.group_id IN ( $groupIds )";
+      }
+      // For NOT IN we join on groups the contact IS in, then exclude them in the where clause
+      if ($statii && $op == 'NOT IN') {
+        $joinClause[] = "{$gcTable}.status IN (" . implode(', ', $statii) . ")";
+      }
+      $this->_tables[$gcTable] = $this->_whereTables[$gcTable] = " LEFT JOIN civicrm_group_contact {$gcTable} ON (" . implode(' AND ', $joinClause) . ")";
     }
 
-    $qill = ts('Contacts %1', array(1 => $op));
+    if ($op == 'IN') {
+      $qill = ts('In group');
+    }
+    else {
+      $qill = ts('Groups %1', array(1 => $op));
+    }
     $qill .= ' ' . implode(' ' . ts('or') . ' ', $names);
 
     $groupClause = NULL;
 
     if (!$skipGroup) {
-      $groupClause = "{$gcTable}.group_id $op ( $groupIds )";
-      if (!empty($statii)) {
+      $groupClause = "{$gcTable}.group_id $op" . ($groupIds ? " ( $groupIds ) " : '');
+      if (!empty($statii) && $groupIds) {
         $groupClause .= " AND {$gcTable}.status IN (" . implode(', ', $statii) . ")";
-        $qill .= " " . ts('AND') . " " . ts('Group Status') . ' - ' . implode(' ' . ts('or') . ' ', $statii);
+        $qill .= " " . ($op == 'NOT IN' ? ts('WHERE') : ts('AND')) . " " . ts('Group Status') . ' - ' . implode(' ' . ts('or') . ' ', $statii);
+      }
+      // For NOT IN op, params were set in the join
+      if ($op == 'NOT IN') {
+        $groupClause = "{$gcTable}.group_id IS NULL";
       }
     }
 
@@ -2895,7 +2918,7 @@ class CRM_Contact_BAO_Query {
    */
   public function getGroupsFromTypeCriteria($value) {
     $groupIds = array();
-    foreach ($value as $groupTypeValue) {
+    foreach ((array) $value as $groupTypeValue) {
       $groupList = CRM_Core_PseudoConstant::group($groupTypeValue);
       $groupIds = ($groupIds + $groupList);
     }
@@ -2911,7 +2934,7 @@ class CRM_Contact_BAO_Query {
    */
   public function savedSearch(&$values) {
     list($name, $op, $value, $grouping, $wildcard) = $values;
-    return $this->addGroupContactCache(array_keys($value));
+    return $this->addGroupContactCache(array_keys((array) $value));
   }
 
   /**
index 0cb7fb353ad297ec53a983de4219c4ca5cf58db3..2ea67c4becb7237ff44a6f45721681bd6cd11d4e 100644 (file)
@@ -1038,7 +1038,7 @@ class CRM_Core_BAO_Mapping extends CRM_Core_DAO_Mapping {
 
           // CRM-14563: we store checkbox, multi-select and adv-multi select custom field using separator, hence it
           // needs special handling.
-          if ($cfID = CRM_Core_BAO_CustomField::getKeyID($v[1])) {
+          if ($cfID = CRM_Core_BAO_CustomField::getKeyID(CRM_Utils_Array::value(1, $v))) {
             $isCustomField = TRUE;
             $customFieldType = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', $cfID, 'html_type');
             $specialHTMLType = array(