From 78c0bfc0357f16082465f06467729ad96a4891dd Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 27 Aug 2013 14:19:29 +1200 Subject: [PATCH] CRM-13294 support for api style array of ids as a param for contact_get --- CRM/Contact/BAO/Query.php | 7 +++++++ CRM/Core/DAO.php | 25 ++++++++++++++++++++----- api/v3/utils.php | 13 +++++++++++++ tests/phpunit/api/v3/ContactTest.php | 15 +++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php index 303d130dc0..d4405f4bac 100644 --- a/CRM/Contact/BAO/Query.php +++ b/CRM/Contact/BAO/Query.php @@ -1758,6 +1758,13 @@ class CRM_Contact_BAO_Query { } elseif (is_array($this->_params[$id][2])) { $idList = implode("','", $this->_params[$id][2]); + //why on earth do they put ' in the middle & not on the outside? We have to assume it's + //to support 'something' so lets add them conditionally to support the api (which is a tested flow + // so if you are looking to alter this check api test results + if(strpos(trim($idList), "'") > 0) { + $idList = "'" . $idList . "'"; + } + $this->_where[0][] = "contact_a.id IN ({$idList})"; } else { diff --git a/CRM/Core/DAO.php b/CRM/Core/DAO.php index 977fc60a9f..1abc63a044 100644 --- a/CRM/Core/DAO.php +++ b/CRM/Core/DAO.php @@ -1822,8 +1822,14 @@ EOS; * @param $filter array filter to be applied indexed by operator * @param $type String type of field (not actually used - nor in api @todo ) * @param $alias String alternative field name ('as') @todo- not actually used + * @param bool $returnSanitisedArray return a sanitised array instead of a clause + * this is primarily so we can add filters @ the api level to the Query object based fields + * @todo a better solutution would be for the query object to apply these filters based on the + * api supported format (but we don't want to risk breakage in alpha stage & query class is scary + * @todo @time of writing only IN & NOT IN are supported for the array style syntax (as test is + * required to extend further & it may be the comments per above should be implemented */ - public function createSQLFilter($fieldName, $filter, $type, $alias = NULL) { + public function createSQLFilter($fieldName, $filter, $type, $alias = NULL, $returnSanitisedArray = FALSE) { // http://issues.civicrm.org/jira/browse/CRM-9150 - stick with 'simple' operators for now // support for other syntaxes is discussed in ticket but being put off for now $acceptedSQLOperators = array('=', '<=', '>=', '>', '<', 'LIKE', "<>", "!=", "NOT LIKE", 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'); @@ -1833,7 +1839,9 @@ EOS; // unary operators case 'IS NULL': case 'IS NOT NULL': - return (sprintf('%s %s', $fieldName, $operator)); + if(!$returnSanitisedArray) { + return (sprintf('%s %s', $fieldName, $operator)); + } break; // ternary operators @@ -1842,7 +1850,9 @@ EOS; if (empty($criteria[0]) || empty($criteria[1])) { throw new exception("invalid criteria for $operator"); } - return (sprintf('%s ' . $operator . ' "%s" AND "%s"', $fieldName, CRM_Core_DAO::escapeString($criteria[0]), CRM_Core_DAO::escapeString($criteria[1]))); + if(!$returnSanitisedArray) { + return (sprintf('%s ' . $operator . ' "%s" AND "%s"', $fieldName, CRM_Core_DAO::escapeString($criteria[0]), CRM_Core_DAO::escapeString($criteria[1]))); + } break; // n-ary operators @@ -1855,13 +1865,18 @@ EOS; 'CRM_Core_DAO', 'escapeString' ), $criteria); - return (sprintf('%s %s ("%s")', $fieldName, $operator, implode('", "', $escapedCriteria))); + if(!$returnSanitisedArray) { + return (sprintf('%s %s ("%s")', $fieldName, $operator, implode('", "', $escapedCriteria))); + } + return $escapedCriteria; break; // binary operators default: - return(sprintf('%s %s "%s"', $fieldName, $operator, CRM_Core_DAO::escapeString($criteria))); + if(!$returnSanitisedArray) { + return(sprintf('%s %s "%s"', $fieldName, $operator, CRM_Core_DAO::escapeString($criteria))); + } } } } diff --git a/api/v3/utils.php b/api/v3/utils.php index 14f6daa352..149a7fb34b 100644 --- a/api/v3/utils.php +++ b/api/v3/utils.php @@ -425,7 +425,20 @@ function _civicrm_api3_get_using_query_object($entity, $params, $additional_opti } $newParams = CRM_Contact_BAO_Query::convertFormValues($inputParams); + foreach ($newParams as &$newParam) { + if($newParam[1] == '=' && is_array($newParam[2])) { + // we may be looking at an attempt to use the 'IN' style syntax + // @todo at time of writing only 'IN' & 'NOT IN' are supported for the array style syntax + $sqlFilter = CRM_Core_DAO::createSqlFilter($newParam[0], $params[$newParam[0]], 'String', NULL, TRUE); + if($sqlFilter) { + $newParam[1] = key($newParam[2]); + $newParam[2] = $sqlFilter; + } + } + + } $skipPermissions = CRM_Utils_Array::value('check_permissions', $params)? 0 :1; + list($entities, $options) = CRM_Contact_BAO_Query::apiQuery( $newParams, $returnProperties, diff --git a/tests/phpunit/api/v3/ContactTest.php b/tests/phpunit/api/v3/ContactTest.php index f32706f41d..b292b054fb 100644 --- a/tests/phpunit/api/v3/ContactTest.php +++ b/tests/phpunit/api/v3/ContactTest.php @@ -409,6 +409,21 @@ class api_v3_ContactTest extends CiviUnitTestCase { $this->callAPISuccess($this->_entity, 'delete', array('id' => $c1['id'])); $this->callAPISuccess($this->_entity, 'delete', array('id' => $c2['id'])); } + /* + * Test that we can retrieve contacts using + * 'id' => array('IN' => array('3,4')) syntax + */ + function testGetINIDArray() { + $c1 = $this->callAPISuccess($this->_entity, 'create', $this->_params); + $c2 = $this->callAPISuccess($this->_entity, 'create', array('first_name' => 'bb', 'last_name' => 'ccc', 'contact_type' => 'Individual')); + $c3 = $this->callAPISuccess($this->_entity, 'create', array('first_name' => 'hh', 'last_name' => 'll', 'contact_type' => 'Individual')); + $result = $this->callAPISuccess($this->_entity, 'get', array('id' => array('IN' => array($c1['id'], $c3['id'])))); + $this->assertEquals(2, $result['count']); + $this->assertEquals(array($c1['id'], $c3['id']), array_keys($result['values'])); + $this->callAPISuccess($this->_entity, 'delete', array('id' => $c1['id'])); + $this->callAPISuccess($this->_entity, 'delete', array('id' => $c2['id'])); + $this->callAPISuccess($this->_entity, 'delete', array('id' => $c3['id'])); + } /* * Test variants on deleted behaviour */ -- 2.25.1