From ac84dadc2f5a4e4912d20def964b925dd2977a09 Mon Sep 17 00:00:00 2001 From: colemanw Date: Mon, 25 Sep 2023 13:19:00 -0400 Subject: [PATCH] SearchKit - Expose Address.proximity filter as Afform search filter --- .../Traits/SavedSearchInspectorTrait.php | 11 +++-- ext/afform/core/ang/af/fields/Location.html | 8 ++++ .../api/v4/SearchDisplay/SearchRunTest.php | 48 +++++++++++++++++++ .../CRM/Utils/Geocode/TestProvider.php | 7 ++- .../v4/Action/AddressGetCoordinatesTest.php | 6 +-- 5 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 ext/afform/core/ang/af/fields/Location.html diff --git a/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php b/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php index 337f3c052f..92487d91ba 100644 --- a/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php +++ b/Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php @@ -282,7 +282,7 @@ trait SavedSearchInspectorTrait { foreach ($fieldNames as $fieldName) { $field = $this->getField($fieldName); $dataType = $field['data_type'] ?? NULL; - $operators = ($field['operators'] ?? []) ?: CoreUtil::getOperators(); + $operators = array_values($field['operators'] ?? []) ?: CoreUtil::getOperators(); // Array is either associative `OP => VAL` or sequential `IN (...)` if (is_array($value)) { $value = array_filter($value, [$this, 'hasValue']); @@ -290,13 +290,15 @@ trait SavedSearchInspectorTrait { if (array_diff_key($value, array_flip(CoreUtil::getOperators()))) { // Use IN for regular fields if (empty($field['serialize'])) { - $filterClauses[] = [$fieldName, 'IN', $value]; + $op = in_array('IN', $operators, TRUE) ? 'IN' : $operators[0]; + $filterClauses[] = [$fieldName, $op, $value]; } // Use an OR group of CONTAINS for array fields else { + $op = in_array('CONTAINS', $operators, TRUE) ? 'CONTAINS' : $operators[0]; $orGroup = []; foreach ($value as $val) { - $orGroup[] = [$fieldName, 'CONTAINS', $val]; + $orGroup[] = [$fieldName, $op, $val]; } $filterClauses[] = ['OR', $orGroup]; } @@ -326,7 +328,8 @@ trait SavedSearchInspectorTrait { $filterClauses[] = [$fieldName, 'IN', (array) $value]; } else { - $filterClauses[] = [$fieldName, '=', $value]; + $op = in_array('=', $operators, TRUE) ? '=' : $operators[0]; + $filterClauses[] = [$fieldName, $op, $value]; } } // Single field diff --git a/ext/afform/core/ang/af/fields/Location.html b/ext/afform/core/ang/af/fields/Location.html new file mode 100644 index 0000000000..3075089e16 --- /dev/null +++ b/ext/afform/core/ang/af/fields/Location.html @@ -0,0 +1,8 @@ +
+ + + +
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 5251f16ac6..58d6300fb5 100644 --- a/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php +++ b/ext/search_kit/tests/phpunit/api/v4/SearchDisplay/SearchRunTest.php @@ -31,6 +31,16 @@ class SearchRunTest extends Api4TestBase implements TransactionalInterface { ->apply(); } + /** + * @inheritDoc + */ + public function tearDown(): void { + \Civi\Api4\Setting::revert(FALSE) + ->addSelect('geoProvider') + ->execute(); + parent::tearDown(); + } + /** * Test running a searchDisplay with various filters. */ @@ -2184,6 +2194,44 @@ class SearchRunTest extends Api4TestBase implements TransactionalInterface { $this->assertEquals(['test_file.txt', 'test_file.png', 'test_file_foo.unknown'], array_column($result[0]['columns'][1]['links'], 'text')); } + public function testRunWithAddressProximity(): void { + require_once __DIR__ . '/../../../../../../../tests/phpunit/CRM/Utils/Geocode/TestProvider.php'; + $sampleData = [ + ['geo_code_1' => \CRM_Utils_Geocode_TestProvider::GEO_CODE_1, 'geo_code_2' => \CRM_Utils_Geocode_TestProvider::GEO_CODE_2], + ['geo_code_1' => \CRM_Utils_Geocode_TestProvider::GEO_CODE_1 - .05, 'geo_code_2' => \CRM_Utils_Geocode_TestProvider::GEO_CODE_2 + .05], + ['geo_code_1' => '0', 'geo_code_2' => '0'], + ]; + $addresses = $this->saveTestRecords('Address', ['records' => $sampleData]) + ->column('id'); + + \Civi\Api4\Setting::set(FALSE) + ->addValue('geoProvider', 'TestProvider') + ->execute(); + + $params = [ + 'checkPermissions' => FALSE, + 'return' => 'page:1', + 'savedSearch' => [ + 'api_entity' => 'Address', + 'api_params' => [ + 'version' => 4, + // Hack proximity into select clause to allow filter + 'select' => ['id', 'proximity'], + 'where' => [ + ['id', 'IN', $addresses], + ], + ], + ], + 'display' => NULL, + 'filters' => ['proximity' => ['distance' => 1000, 'address' => \CRM_Utils_Geocode_TestProvider::ADDRESS]], + 'afform' => NULL, + 'debug' => TRUE, + ]; + + $result = civicrm_api4('SearchDisplay', 'run', $params); + $this->assertCount(2, $result); + } + /** * Returns all contacts in VIEW mode but only specified contact for EDIT. * diff --git a/tests/phpunit/CRM/Utils/Geocode/TestProvider.php b/tests/phpunit/CRM/Utils/Geocode/TestProvider.php index 580ffaa318..63b5d96c9f 100644 --- a/tests/phpunit/CRM/Utils/Geocode/TestProvider.php +++ b/tests/phpunit/CRM/Utils/Geocode/TestProvider.php @@ -1,6 +1,9 @@ '38.897957', 'geo_code_2' => '-77.036560']; + if (str_starts_with($address, self::ADDRESS)) { + return ['geo_code_1' => self::GEO_CODE_1, 'geo_code_2' => self::GEO_CODE_2]; } return []; } diff --git a/tests/phpunit/api/v4/Action/AddressGetCoordinatesTest.php b/tests/phpunit/api/v4/Action/AddressGetCoordinatesTest.php index ed0a37ded7..9669b8fe45 100644 --- a/tests/phpunit/api/v4/Action/AddressGetCoordinatesTest.php +++ b/tests/phpunit/api/v4/Action/AddressGetCoordinatesTest.php @@ -43,9 +43,9 @@ class AddressGetCoordinatesTest extends Api4TestBase implements TransactionalInt } public function testGetCoordinatesWhiteHouse(): void { - $coordinates = Address::getCoordinates()->setAddress('600 Pennsylvania Avenue NW, Washington, DC, USA')->execute()->first(); - $this->assertEquals('38.897957', $coordinates['geo_code_1']); - $this->assertEquals('-77.036560', $coordinates['geo_code_2']); + $coordinates = Address::getCoordinates()->setAddress(\CRM_Utils_Geocode_TestProvider::ADDRESS)->execute()->first(); + $this->assertEquals(\CRM_Utils_Geocode_TestProvider::GEO_CODE_1, $coordinates['geo_code_1']); + $this->assertEquals(\CRM_Utils_Geocode_TestProvider::GEO_CODE_2, $coordinates['geo_code_2']); } public function testGetCoordinatesNoAddress(): void { -- 2.25.1