From 84b531d86bfd6fda0fecb74a21b2b7a56bd5ed67 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Sat, 3 Jul 2021 18:07:31 -0400 Subject: [PATCH] SearchKit - Fix array filters with serialized fields --- .../Civi/Api4/Action/SearchDisplay/Run.php | 16 ++++++++-- .../api/v4/SearchDisplay/SearchRunTest.php | 31 ++++++++++++++++--- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php b/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php index ea0f915603..9cb82985b1 100644 --- a/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php +++ b/ext/search_kit/Civi/Api4/Action/SearchDisplay/Run.php @@ -213,10 +213,22 @@ class Run extends \Civi\Api4\Generic\AbstractAction { // Array is either associative `OP => VAL` or sequential `IN (...)` if (is_array($value)) { $value = array_filter($value, [$this, 'hasValue']); - // Use IN if array does not contain operators as keys + // If array does not contain operators as keys, assume array of values if (array_diff_key($value, array_flip(CoreUtil::getOperators()))) { - $clause[] = [$fieldName, 'IN', $value]; + // Use IN for regular fields + if (empty($field['serialize'])) { + $clause[] = [$fieldName, 'IN', $value]; + } + // Use an OR group of CONTAINS for array fields + else { + $orGroup = []; + foreach ($value as $val) { + $orGroup[] = [$fieldName, 'CONTAINS', $val]; + } + $clause[] = ['OR', $orGroup]; + } } + // Operator => Value array else { foreach ($value as $operator => $val) { $clause[] = [$fieldName, $operator, $val]; diff --git a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php index 41a4f3c8b4..be4585365d 100644 --- a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php +++ b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php @@ -3,6 +3,7 @@ namespace api\v4\SearchDisplay; use Civi\API\Exception\UnauthorizedException; use Civi\Api4\Contact; +use Civi\Api4\ContactType; use Civi\Api4\SavedSearch; use Civi\Api4\SearchDisplay; use Civi\Api4\UFMatch; @@ -27,11 +28,19 @@ class SearchRunTest extends \PHPUnit\Framework\TestCase implements HeadlessInter * Test running a searchDisplay with various filters. */ public function testRunDisplay() { + foreach (['Tester', 'Bot'] as $type) { + ContactType::create(FALSE) + ->addValue('parent_id.name', 'Individual') + ->addValue('label', $type) + ->addValue('name', $type) + ->execute(); + } + $lastName = uniqid(__FUNCTION__); $sampleData = [ - ['first_name' => 'One', 'last_name' => $lastName], - ['first_name' => 'Two', 'last_name' => $lastName], - ['first_name' => 'Three', 'last_name' => $lastName], + ['first_name' => 'One', 'last_name' => $lastName, 'contact_sub_type' => ['Tester', 'Bot']], + ['first_name' => 'Two', 'last_name' => $lastName, 'contact_sub_type' => ['Tester']], + ['first_name' => 'Three', 'last_name' => $lastName, 'contact_sub_type' => ['Bot']], ['first_name' => 'Four', 'last_name' => $lastName], ]; Contact::save(FALSE)->setRecords($sampleData)->execute(); @@ -43,7 +52,7 @@ class SearchRunTest extends \PHPUnit\Framework\TestCase implements HeadlessInter 'api_entity' => 'Contact', 'api_params' => [ 'version' => 4, - 'select' => ['id', 'first_name', 'last_name'], + 'select' => ['id', 'first_name', 'last_name', 'contact_sub_type:label'], 'where' => [], ], ], @@ -72,6 +81,12 @@ class SearchRunTest extends \PHPUnit\Framework\TestCase implements HeadlessInter 'dataType' => 'String', 'type' => 'field', ], + [ + 'key' => 'contact_sub_type:label', + 'label' => 'Type', + 'dataType' => 'String', + 'type' => 'field', + ], ], 'sort' => [ ['id', 'ASC'], @@ -97,6 +112,14 @@ class SearchRunTest extends \PHPUnit\Framework\TestCase implements HeadlessInter $this->assertCount(2, $result); $this->assertEquals('Three', $result[0]['first_name']); $this->assertEquals('Two', $result[1]['first_name']); + + $params['filters'] = ['contact_sub_type:label' => ['Tester', 'Bot']]; + $result = civicrm_api4('SearchDisplay', 'run', $params); + $this->assertCount(3, $result); + + $params['filters'] = ['contact_sub_type' => ['Tester']]; + $result = civicrm_api4('SearchDisplay', 'run', $params); + $this->assertCount(2, $result); } /** -- 2.25.1