Skip to content

Commit

Permalink
SearchKit - Expose Address.proximity filter as Afform search filter
Browse files Browse the repository at this point in the history
  • Loading branch information
colemanw committed Sep 25, 2023
1 parent f697b4e commit b820ace
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 9 deletions.
11 changes: 7 additions & 4 deletions Civi/Api4/Generic/Traits/SavedSearchInspectorTrait.php
Expand Up @@ -282,21 +282,23 @@ protected function applyFilter($fieldName, $value) {
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']);
// If array does not contain operators as keys, assume array of values
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];
}
Expand Down Expand Up @@ -326,7 +328,8 @@ protected function applyFilter($fieldName, $value) {
$filterClauses[] = [$fieldName, 'IN', (array) $value];
}
else {
$filterClauses[] = [$fieldName, '=', $value];
$op = in_array('=', $operators, TRUE) ? '=' : $operators[0];
$filterClauses[] = [$fieldName, $op, $value];
}
}
// Single field
Expand Down
8 changes: 8 additions & 0 deletions ext/afform/core/ang/af/fields/Location.html
@@ -0,0 +1,8 @@
<div class="form-inline">
<input class="form-control" type="number" ng-model="dataProvider.getFieldData()[$ctrl.fieldName].distance" placeholder="{{:: ts('Distance') }}" >
<select class="form-control" ng-model="dataProvider.getFieldData()[$ctrl.fieldName].distance_unit">
<option value="km">{{:: ts('Km') }}</option>
<option value="miles">{{:: ts('Miles') }}</option>
</select>
<input class="form-control" ng-model="dataProvider.getFieldData()[$ctrl.fieldName].address" placeholder="{{:: ts('Street, City, State, Country') }}" ng-model-options="{updateOn: 'blur'}" >
</div>
Expand Up @@ -31,6 +31,17 @@ public function setUpHeadless(): CiviEnvBuilder {
->apply();
}

/**
* @inheritDoc
*/
public function tearDown(): void {
\Civi\Api4\Setting::revert(FALSE)
->addSelect('geoProvider')
->execute();
parent::tearDown();
}


/**
* Test running a searchDisplay with various filters.
*/
Expand Down Expand Up @@ -2184,6 +2195,44 @@ public function testRunWithEntityFile(): void {
$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.
*
Expand Down
7 changes: 5 additions & 2 deletions tests/phpunit/CRM/Utils/Geocode/TestProvider.php
@@ -1,6 +1,9 @@
<?php

class CRM_Utils_Geocode_TestProvider {
public const ADDRESS = '600 Pennsylvania Avenue NW, Washington';
public const GEO_CODE_1 = '38.897957';
public const GEO_CODE_2 = '-77.036560';

public static function format(&$values, $stateName = FALSE) {
$address = ($values['street_address'] ?? '') . ($values['city'] ?? '');
Expand All @@ -18,8 +21,8 @@ public static function format(&$values, $stateName = FALSE) {
}

public static function getCoordinates($address): array {
if (strpos($address, '600 Pennsylvania Avenue NW, Washington') === 0) {
return ['geo_code_1' => '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 [];
}
Expand Down
6 changes: 3 additions & 3 deletions tests/phpunit/api/v4/Action/AddressGetCoordinatesTest.php
Expand Up @@ -43,9 +43,9 @@ public function tearDown(): void {
}

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 {
Expand Down

0 comments on commit b820ace

Please sign in to comment.