Skip to content
Snippets Groups Projects
Commit 4ff04e72 authored by colemanw's avatar colemanw
Browse files

APIv4 - Add address proximity search filter

parent 7c63299d
No related branches found
No related tags found
No related merge requests found
<?php
/*
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC. All rights reserved. |
| |
| This work is published under the GNU AGPLv3 license with some |
| permitted exceptions and without any warranty. For full license |
| and copyright information, see https://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
namespace Civi\Api4\Service\Spec\Provider;
use Civi\Api4\Query\Api4SelectQuery;
use Civi\Api4\Service\Spec\FieldSpec;
use Civi\Api4\Service\Spec\RequestSpec;
class AddressGetSpecProvider implements Generic\SpecProviderInterface {
/**
* @param \Civi\Api4\Service\Spec\RequestSpec $spec
*/
public function modifySpec(RequestSpec $spec) {
// Groups field
$field = new FieldSpec('proximity', 'Address', 'Boolean');
$field->setLabel(ts('Address Proximity'))
->setTitle(ts('Address Proximity'))
->setColumnName('geo_code_1')
->setDescription(ts('Address is within a given distance to a location'))
->setType('Filter')
->setOperators(['<='])
->addSqlFilter([__CLASS__, 'getProximitySql']);
$spec->addFieldSpec($field);
}
/**
* @param string $entity
* @param string $action
*
* @return bool
*/
public function applies($entity, $action) {
return $entity === 'Address' && $action === 'get';
}
/**
* @param array $field
* @param string $fieldAlias
* @param string $operator
* @param mixed $value
* @param \Civi\Api4\Query\Api4SelectQuery $query
* @param int $depth
* return string
*/
public static function getProximitySql(array $field, string $fieldAlias, string $operator, $value, Api4SelectQuery $query, int $depth): string {
$unit = $value['distance_unit'] ?? 'km';
$distance = $value['distance'] ?? 0;
if ($unit === 'miles') {
$distance = $distance * 1609.344;
}
else {
$distance = $distance * 1000.00;
}
if (
isset($value['geo_code_1']) && is_numeric($value['geo_code_1']) &&
isset($value['geo_code_2']) && is_numeric($value['geo_code_2'])
) {
return \CRM_Contact_BAO_ProximityQuery::where(
$value['geo_code_1'],
$value['geo_code_2'],
$distance,
explode('.', $fieldAlias)[0]
);
}
// Todo: If address string given without lat/long, convert it.
return '(0)';
}
}
......@@ -59,4 +59,29 @@ class AddressTest extends Api4TestBase implements TransactionalInterface {
$this->assertTrue($addresses[1]['is_primary']);
}
public function testSearchProximity() {
$cid = $this->createTestRecord('Contact')['id'];
$sampleData = [
['geo_code_1' => 20, 'geo_code_2' => 20],
['geo_code_1' => 21, 'geo_code_2' => 21],
['geo_code_1' => 19, 'geo_code_2' => 19],
['geo_code_1' => 15, 'geo_code_2' => 15],
];
$addreses = $this->saveTestRecords('Address', [
'records' => $sampleData,
'defaults' => ['contact_id' => $cid],
])->column('id');
$result = Address::get(FALSE)
->addWhere('contact_id', '=', $cid)
->addWhere('proximity', '<=', ['distance' => 600, 'geo_code_1' => 20, 'geo_code_2' => 20])
->execute()->column('id');
$this->assertCount(3, $result);
$this->assertContains($addreses[0], $result);
$this->assertContains($addreses[1], $result);
$this->assertContains($addreses[2], $result);
$this->assertNotContains($addreses[3], $result);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment