From 10befc1fbbdc6055426e90d38f02d9f35295def4 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Wed, 22 Mar 2017 19:24:16 -0400 Subject: [PATCH] CRM-20327 - API chaining - replace $value when using operators. --- CRM/Case/XMLProcessor/Process.php | 7 +--- api/api.php | 69 +++++++++++++++++++------------ api/v3/Case.php | 2 +- tests/phpunit/api/v3/CaseTest.php | 50 ++++++++++++++++++++++ 4 files changed, 94 insertions(+), 34 deletions(-) diff --git a/CRM/Case/XMLProcessor/Process.php b/CRM/Case/XMLProcessor/Process.php index aeb8572ea2..7222827578 100644 --- a/CRM/Case/XMLProcessor/Process.php +++ b/CRM/Case/XMLProcessor/Process.php @@ -437,12 +437,7 @@ AND a.is_deleted = 0 $statusName = 'Scheduled'; } - if ($this->_isMultiClient) { - $client = $params['clientID']; - } - else { - $client = array(1 => $params['clientID']); - } + $client = (array) $params['clientID']; //set order $orderVal = ''; diff --git a/api/api.php b/api/api.php index 80bfedd6d7..1675d9d1aa 100644 --- a/api/api.php +++ b/api/api.php @@ -128,42 +128,57 @@ function _civicrm_api_get_camel_name($entity) { * @param string $separator */ function _civicrm_api_replace_variables(&$params, &$parentResult, $separator = '.') { - - foreach ($params as $field => $value) { - + foreach ($params as $field => &$value) { if (is_string($value) && substr($value, 0, 6) == '$value') { - $valueSubstitute = substr($value, 7); + $value = _civicrm_api_replace_variable($value, $parentResult, $separator); + } + // Handle the operator syntax: array('OP' => $val) + elseif (is_array($value) && is_string(reset($value)) && substr(reset($value), 0, 6) == '$value') { + $key = key($value); + $value[$key] = _civicrm_api_replace_variable($value[$key], $parentResult, $separator); + } + } +} - if (!empty($parentResult[$valueSubstitute])) { - $params[$field] = $parentResult[$valueSubstitute]; - } - else { +/** + * Swap out a $value.foo variable with the value from parent api results. + * + * Called by _civicrm_api_replace_variables to do the substitution. + * + * @param string $value + * @param array $parentResult + * @param string $separator + * @return mixed|null + */ +function _civicrm_api_replace_variable($value, $parentResult, $separator) { + $valueSubstitute = substr($value, 7); - $stringParts = explode($separator, $value); - unset($stringParts[0]); + if (!empty($parentResult[$valueSubstitute])) { + return $parentResult[$valueSubstitute]; + } + else { + $stringParts = explode($separator, $value); + unset($stringParts[0]); + // CRM-16168 If we have failed to swap it out we should unset it rather than leave the placeholder. + $value = NULL; - $fieldname = array_shift($stringParts); + $fieldname = array_shift($stringParts); - //when our string is an array we will treat it as an array from that . onwards - $count = count($stringParts); - while ($count > 0) { - $fieldname .= "." . array_shift($stringParts); - if (array_key_exists($fieldname, $parentResult) && is_array($parentResult[$fieldname])) { - $arrayLocation = $parentResult[$fieldname]; - foreach ($stringParts as $key => $innerValue) { - $arrayLocation = CRM_Utils_Array::value($innerValue, $arrayLocation); - } - $params[$field] = $arrayLocation; - } - $count = count($stringParts); + //when our string is an array we will treat it as an array from that . onwards + $count = count($stringParts); + while ($count > 0) { + $fieldname .= "." . array_shift($stringParts); + if (array_key_exists($fieldname, $parentResult) && is_array($parentResult[$fieldname])) { + $arrayLocation = $parentResult[$fieldname]; + foreach ($stringParts as $key => $innerValue) { + $arrayLocation = CRM_Utils_Array::value($innerValue, $arrayLocation); } + $value = $arrayLocation; } - // CRM-16168 If we have failed to swap it out we should unset it rather than leave the placeholder. - if (substr($params[$field], 0, 6) == '$value') { - $params[$field] = NULL; - } + $count = count($stringParts); } } + return $value; } /** diff --git a/api/v3/Case.php b/api/v3/Case.php index 510b7d6750..0169c26ff8 100644 --- a/api/v3/Case.php +++ b/api/v3/Case.php @@ -272,7 +272,7 @@ function civicrm_api3_case_get($params) { if (empty($options['is_count']) && !empty($cases['values'])) { // For historic reasons we return these by default only when fetching a case by id - if (!empty($params['id']) && empty($options['return'])) { + if (!empty($params['id']) && is_numeric($params['id']) && empty($options['return'])) { $options['return'] = array( 'contacts' => 1, 'activities' => 1, diff --git a/tests/phpunit/api/v3/CaseTest.php b/tests/phpunit/api/v3/CaseTest.php index a9c874e9b7..cced2f112c 100644 --- a/tests/phpunit/api/v3/CaseTest.php +++ b/tests/phpunit/api/v3/CaseTest.php @@ -513,4 +513,54 @@ class api_v3_CaseTest extends CiviCaseTestCase { $this->assertEquals('CaseTag1', $result['tag_id'][$tag1['id']]['tag_id.name']); } + /** + * Test that a chained api call can use the operator syntax. + * + * E.g. array('IN' => $value.contact_id) + * + * @throws \Exception + */ + public function testCaseGetChainedOp() { + $contact1 = $this->individualCreate(array(), 1); + $contact2 = $this->individualCreate(array(), 2); + $case1 = $this->callAPISuccess('Case', 'create', array( + 'contact_id' => $contact1, + 'subject' => "Test case 1", + 'case_type_id' => $this->caseTypeId, + )); + $case2 = $this->callAPISuccess('Case', 'create', array( + 'contact_id' => $contact2, + 'subject' => "Test case 2", + 'case_type_id' => $this->caseTypeId, + )); + $case3 = $this->callAPISuccess('Case', 'create', array( + 'contact_id' => array($contact1, $contact2), + 'subject' => "Test case 3", + 'case_type_id' => $this->caseTypeId, + )); + + // Fetch case 1 and all cases with the same client. Chained get should return case 3. + $result = $this->callAPISuccessGetSingle('Case', array( + 'id' => $case1['id'], + 'return' => 'contact_id', + 'api.Case.get' => array( + 'contact_id' => array('IN' => "\$value.contact_id"), + 'id' => array('!=' => "\$value.id"), + ), + )); + $this->assertEquals($case3['id'], $result['api.Case.get']['id']); + + // Fetch case 3 and all cases with the same clients. Chained get should return case 1&2. + $result = $this->callAPISuccessGetSingle('Case', array( + 'id' => $case3['id'], + 'return' => array('contact_id'), + 'api.Case.get' => array( + 'return' => 'id', + 'contact_id' => array('IN' => "\$value.contact_id"), + 'id' => array('!=' => "\$value.id"), + ), + )); + $this->assertEquals(array($case1['id'], $case2['id']), array_keys(CRM_Utils_Array::rekey($result['api.Case.get']['values'], 'id'))); + } + } -- 2.25.1