CRM-11782 - Fix search by contact_type
authorColeman Watts <coleman@civicrm.org>
Sun, 11 Oct 2015 23:22:10 +0000 (19:22 -0400)
committerColeman Watts <coleman@civicrm.org>
Mon, 12 Oct 2015 18:14:46 +0000 (14:14 -0400)
CRM/Contact/BAO/Query.php
CRM/Contact/Form/Search/Basic.php
CRM/Contact/Form/Search/Criteria.php
CRM/Contact/Form/Search/Custom/Basic.php
CRM/Contact/Form/Search/Custom/MultipleValues.php
CRM/Core/Page/Basic.php
tests/phpunit/api/v3/ContactTest.php

index 04778d5076759b612a2bbc7e3b8393a8511732c2..8aef0736bac8d768d98605cad739e9110142c265 100644 (file)
@@ -1508,7 +1508,24 @@ class CRM_Contact_BAO_Query {
         $params[] = $values;
         continue;
       }
-      if ($id == 'privacy') {
+      // The form uses 1 field to represent two db fields
+      if ($id == 'contact_type' && $values && (!is_array($values) || !array_intersect(array_keys($values), CRM_Core_DAO::acceptedSQLOperators()))) {
+        $contactType = array();
+        $subType = array();
+        foreach ((array) $values as $key => $type) {
+          $types = explode('__', is_numeric($type) ? $key : $type);
+          $contactType[$types[0]] = $types[0];
+          // Add sub-type if specified
+          if (!empty($types[1])) {
+            $subType[$types[1]] = $types[1];
+          }
+        }
+        $params[] = array('contact_type', 'IN', $contactType, 0, 0);
+        if ($subType) {
+          $params[] = array('contact_sub_type', 'IN', $subType, 0, 0);
+        }
+      }
+      elseif ($id == 'privacy') {
         if (is_array($formValues['privacy'])) {
           $op = !empty($formValues['privacy']['do_not_toggle']) ? '=' : '!=';
           foreach ($formValues['privacy'] as $key => $value) {
@@ -1713,10 +1730,6 @@ class CRM_Contact_BAO_Query {
         $this->deletedContacts($values);
         return;
 
-      case 'contact_type':
-        $this->contactType($values);
-        return;
-
       case 'contact_sub_type':
         $this->contactSubType($values);
         return;
@@ -2794,7 +2807,7 @@ class CRM_Contact_BAO_Query {
 
     $clause = array();
     $alias = "contact_a.contact_sub_type";
-    $qillOperators = array('NOT LIKE' => ts('Not Like')) + CRM_Core_SelectValues::getSearchBuilderOperators();
+    $qillOperators = CRM_Core_SelectValues::getSearchBuilderOperators();
 
     $op = str_replace('IN', 'LIKE', $op);
     $op = str_replace('=', 'LIKE', $op);
@@ -5371,8 +5384,8 @@ SELECT COUNT( conts.total_amount ) as cancel_count,
       case 'IN':
       case 'NOT IN':
         // I feel like this would be escaped properly if passed through $queryString = CRM_Core_DAO::createSqlFilter.
-        if (!empty($value) && is_array($value) && !array_key_exists($op, $value)) {
-          $value = array($op => $value);
+        if (!empty($value) && (!is_array($value) || !array_key_exists($op, $value))) {
+          $value = array($op => (array) $value);
         }
 
       default:
index 6418ba7bee279486dea6bb3acdf71d2334ca9f7b..5dea92c50d94d290e022ac335090aaf335894f1b 100644 (file)
@@ -56,12 +56,8 @@ class CRM_Contact_Form_Search_Basic extends CRM_Contact_Form_Search {
       'advanced_search_options'
     );
 
-    $shortCuts = array();
-    //@todo FIXME - using the CRM_Core_DAO::VALUE_SEPARATOR creates invalid html - if you can find the form
-    // this is loaded onto then replace with something like '__' & test
-    $separator = CRM_Core_DAO::VALUE_SEPARATOR;
     if (!empty($searchOptions['contactType'])) {
-      $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements(FALSE, TRUE, $separator);
+      $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements();
       $this->add('select', 'contact_type',
         ts('is...'),
         $contactTypes,
@@ -161,7 +157,6 @@ class CRM_Contact_Form_Search_Basic extends CRM_Contact_Form_Search {
     // get it from controller only if form has been submitted, else preProcess has set this
     if (!empty($_POST)) {
       $this->_formValues = $this->controller->exportValues($this->_name);
-      $this->normalizeFormValues();
     }
 
     if (isset($this->_groupID) && empty($this->_formValues['group'])) {
@@ -198,22 +193,6 @@ class CRM_Contact_Form_Search_Basic extends CRM_Contact_Form_Search {
     parent::postProcess();
   }
 
-  /**
-   * Normalize the form values to make it look similar to the advanced form values.
-   *
-   * This prevents a ton of work downstream and allows us to use the same code for
-   * multiple purposes (queries, save/edit etc)
-   */
-  public function normalizeFormValues() {
-    $contactType = CRM_Utils_Array::value('contact_type', $this->_formValues);
-    if ($contactType && !is_array($contactType)) {
-      unset($this->_formValues['contact_type']);
-      $this->_formValues['contact_type'][$contactType] = 1;
-    }
-
-    return NULL;
-  }
-
   /**
    * Add a form rule for this form. If Go is pressed then we must select some checkboxes
    * and an action
index f34dcee02822037988cc4c1d7e2f89239fdd58df..15163ee9cca6d4cb233a465baae7a278a788a4e8 100644 (file)
@@ -38,11 +38,7 @@ class CRM_Contact_Form_Search_Criteria {
     $form->addElement('hidden', 'hidden_basic', 1);
 
     if ($form->_searchOptions['contactType']) {
-      // add checkboxes for contact type
-      //@todo FIXME - using the CRM_Core_DAO::VALUE_SEPARATOR creates invalid html - if you can find the form
-      // this is loaded onto then replace with something like '__' & test
-      $separator = CRM_Core_DAO::VALUE_SEPARATOR;
-      $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(FALSE, TRUE, $separator);
+      $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements();
 
       if ($contactTypes) {
         $form->add('select', 'contact_type', ts('Contact Type(s)'), $contactTypes, FALSE,
index f4fedf458f1f3746146f2a86dff40b5283b5145e..1f83727cb96273c9086290fae120f82441cf2c24 100644 (file)
@@ -85,42 +85,11 @@ class CRM_Contact_Form_Search_Custom_Basic extends CRM_Contact_Form_Search_Custo
     );
   }
 
-  /**
-   * Normalize the form values to make it look similar to the advanced form values.
-   *
-   * This prevents a ton of work downstream and allows us to use the same code for
-   * multiple purposes (queries, save/edit etc)
-   */
-  public function normalize() {
-    $contactType = CRM_Utils_Array::value('contact_type', $this->_formValues);
-    if ($contactType && !is_array($contactType)) {
-      unset($this->_formValues['contact_type']);
-      $this->_formValues['contact_type'][$contactType] = 1;
-    }
-
-    $group = CRM_Utils_Array::value('group', $this->_formValues);
-    if ($group && !is_array($group)) {
-      unset($this->_formValues['group']);
-      $this->_formValues['group'][$group] = 1;
-    }
-
-    $tag = CRM_Utils_Array::value('tag', $this->_formValues);
-    if ($tag && !is_array($tag)) {
-      unset($this->_formValues['tag']);
-      $this->_formValues['tag'][$tag] = 1;
-    }
-
-    return NULL;
-  }
-
   /**
    * @param CRM_Core_Form $form
    */
   public function buildForm(&$form) {
-    //@todo FIXME - using the CRM_Core_DAO::VALUE_SEPARATOR creates invalid html - if you can find the form
-    // this is loaded onto then replace with something like '__' & test
-    $separator = CRM_Core_DAO::VALUE_SEPARATOR;
-    $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements(FALSE, TRUE, $separator);
+    $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements();
     $form->add('select', 'contact_type', ts('Find...'), $contactTypes, FALSE, array('class' => 'crm-select2 huge'));
 
     // add select for groups
index e3ea1e1ae9c32c5f28bcadf65bc594d93662dcbc..829dd5f4766a3a3b10f7fba487fb239a923ce782 100644 (file)
@@ -105,11 +105,7 @@ class CRM_Contact_Form_Search_Custom_MultipleValues extends CRM_Contact_Form_Sea
 
     $form->add('text', 'sort_name', ts('Contact Name'), TRUE);
 
-    // add select for contact type
-    //@todo FIXME - using the CRM_Core_DAO::VALUE_SEPARATOR creates invalid html - if you can find the form
-    // this is loaded onto then replace with something like '__' & test
-    $separator = CRM_Core_DAO::VALUE_SEPARATOR;
-    $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements(FALSE, TRUE, $separator);
+    $contactTypes = array('' => ts('- any contact type -')) + CRM_Contact_BAO_ContactType::getSelectElements();
     $form->add('select', 'contact_type', ts('Find...'), $contactTypes, array('class' => 'crm-select2 huge'));
 
     // add select for groups
@@ -257,7 +253,7 @@ contact_a.sort_name    as sort_name,
       $this->_formValues
     );
     if ($contact_type != NULL) {
-      $contactType = explode(CRM_Core_DAO::VALUE_SEPARATOR, $contact_type);
+      $contactType = explode('__', $contact_type);
       if (count($contactType) > 1) {
         $clause[] = "contact_a.contact_type = '$contactType[0]' AND contact_a.contact_sub_type = '$contactType[1]'";
       }
index 2560d5fee5ca193b43c5949b706a4cd114b69fe6..ab495448de03f1efa2a4081f1ab60361ec38d121 100644 (file)
@@ -226,10 +226,7 @@ abstract class CRM_Core_Page_Basic extends CRM_Core_Page {
       $object->orderBy($key . ' asc');
     }
 
-    //@todo FIXME - using the CRM_Core_DAO::VALUE_SEPARATOR creates invalid html - if you can find the form
-    // this is loaded onto then replace with something like '__' & test
-    $separator = CRM_Core_DAO::VALUE_SEPARATOR;
-    $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(FALSE, TRUE, $separator);
+    $contactTypes = CRM_Contact_BAO_ContactType::getSelectElements(FALSE, FALSE);
     // find all objects
     $object->find();
     while ($object->fetch()) {
index c531525baf25295e94e53c0f07230ac5b2e9f409..86bf055ce77df7450eda9766610acc2e0b0dfa7c 100644 (file)
@@ -2739,4 +2739,51 @@ class api_v3_ContactTest extends CiviUnitTestCase {
     $this->assertEquals(0, $result['count']);
   }
 
+  public function testGetByContactType() {
+    $individual = $this->callAPISuccess('Contact', 'create', array(
+      'email' => 'individual@test.com',
+      'contact_type' => 'Individual',
+    ));
+    $household = $this->callAPISuccess('Contact', 'create', array(
+      'household_name' => 'household@test.com',
+      'contact_type' => 'Household',
+    ));
+    $organization = $this->callAPISuccess('Contact', 'create', array(
+      'organization_name' => 'organization@test.com',
+      'contact_type' => 'Organization',
+    ));
+    // Test with id - getsingle will throw an exception if not found
+    $this->callAPISuccess('Contact', 'getsingle', array(
+      'id' => $individual['id'],
+      'contact_type' => 'Individual',
+    ));
+    $this->callAPISuccess('Contact', 'getsingle', array(
+      'id' => $individual['id'],
+      'contact_type' => array('IN' => array('Individual')),
+      'return' => 'id',
+    ));
+    $this->callAPISuccess('Contact', 'getsingle', array(
+      'id' => $organization['id'],
+      'contact_type' => array('IN' => array('Individual', 'Organization')),
+    ));
+    // Test as array
+    $result = $this->callAPISuccess('Contact', 'get', array(
+      'contact_type' => array('IN' => array('Individual', 'Organization')),
+      'options' => array('limit' => 0),
+      'return' => 'id',
+    ));
+    $this->assertContains($organization['id'], array_keys($result['values']));
+    $this->assertContains($individual['id'], array_keys($result['values']));
+    $this->assertNotContains($household['id'], array_keys($result['values']));
+    // Test as string
+    $result = $this->callAPISuccess('Contact', 'get', array(
+      'contact_type' => 'Household',
+      'options' => array('limit' => 0),
+      'return' => 'id',
+    ));
+    $this->assertNotContains($organization['id'], array_keys($result['values']));
+    $this->assertNotContains($individual['id'], array_keys($result['values']));
+    $this->assertContains($household['id'], array_keys($result['values']));
+  }
+
 }