CRM-20034 - Support OR grouping of api get params
authorColeman Watts <coleman@civicrm.org>
Thu, 16 Feb 2017 03:32:36 +0000 (22:32 -0500)
committerColeman Watts <coleman@civicrm.org>
Thu, 16 Feb 2017 03:32:36 +0000 (22:32 -0500)
Civi/API/Api3SelectQuery.php
tests/phpunit/api/v3/ActivityTest.php

index 984b1746688ee0436c100dd2aa5117afa55fe5b0..77bdd1b4b79c51732a395277d8258e74d4022963 100644 (file)
@@ -36,6 +36,7 @@ class Api3SelectQuery extends SelectQuery {
    * @inheritDoc
    */
   protected function buildWhereClause() {
+    $filters = array();
     foreach ($this->where as $key => $value) {
       $table_name = NULL;
       $column_name = NULL;
@@ -104,23 +105,37 @@ class Api3SelectQuery extends SelectQuery {
         // Just ignore this for the $where_clause.
         continue;
       }
-      if (!is_array($value)) {
-        $this->query->where(array("`$table_name`.`$column_name` = @value"), array(
-          "@value" => $value,
-        ));
+      $operator = is_array($value) ? \CRM_Utils_Array::first(array_keys($value)) : NULL;
+      if (!in_array($operator, \CRM_Core_DAO::acceptedSQLOperators())) {
+        $value = array('=' => $value);
       }
-      else {
-        // We expect only one element in the array, of the form
-        // "operator" => "rhs".
-        $operator = \CRM_Utils_Array::first(array_keys($value));
-        if (!in_array($operator, \CRM_Core_DAO::acceptedSQLOperators())) {
-          $this->query->where(array("{$table_name}.{$column_name} = @value"), array("@value" => $value));
-        }
-        else {
-          $this->query->where(\CRM_Core_DAO::createSQLFilter("{$table_name}.{$column_name}", $value));
+      $filters[$key] = \CRM_Core_DAO::createSQLFilter("{$table_name}.{$column_name}", $value);
+    }
+    // Support OR groups
+    if (!empty($this->where['options']['or'])) {
+      $orGroups = $this->where['options']['or'];
+      if (is_string($orGroups)) {
+        $orGroups = array_map('trim', explode(',', $orGroups));
+      }
+      if (!is_array(\CRM_Utils_Array::first($orGroups))) {
+        $orGroups = array($orGroups);
+      }
+      foreach ($orGroups as $orGroup) {
+        $orClause = array();
+        foreach ($orGroup as $key) {
+          if (!isset($filters[$key])) {
+            throw new \CiviCRM_API3_Exception("'$key' specified in OR group but not added to params");
+          }
+          $orClause[] = $filters[$key];
+          unset($filters[$key]);
         }
+        $this->query->where(implode(' OR ', $orClause));
       }
     }
+    // Add the remaining params using AND
+    foreach ($filters as $filter) {
+      $this->query->where($filter);
+    }
   }
 
   /**
index afe7e74b88f12a15a318d02177420db389b01f47..526e03dfd834546f7ee1a2dec07175835182f3e2 100644 (file)
@@ -1289,4 +1289,33 @@ class api_v3_ActivityTest extends CiviUnitTestCase {
     }
   }
 
+  public function testGetWithOr() {
+    $acts = array(
+      'test or 1' => 'orOperator',
+      'test or 2' => 'orOperator',
+      'test or 3' => 'nothing',
+    );
+    foreach ($acts as $subject => $details) {
+      $params = $this->_params;
+      $params['subject'] = $subject;
+      $params['details'] = $details;
+      $this->callAPISuccess('Activity', 'create', $params);
+    }
+    $result = $this->callAPISuccess('Activity', 'get', array(
+      'details' => 'orOperator',
+    ));
+    $this->assertEquals(2, $result['count']);
+    $result = $this->callAPISuccess('Activity', 'get', array(
+      'details' => 'orOperator',
+      'subject' => 'test or 3',
+    ));
+    $this->assertEquals(0, $result['count']);
+    $result = $this->callAPISuccess('Activity', 'get', array(
+      'details' => 'orOperator',
+      'subject' => 'test or 3',
+      'options' => array('or' => array(array('details', 'subject'))),
+    ));
+    $this->assertEquals(3, $result['count']);
+  }
+
 }