Skip to content

Commit 46f1a46

Browse files
* Add support for distance calculation between multidimension geometries in meters
* Exprted a method from spatial validator to know the type of the spatial object
1 parent b5ea4d1 commit 46f1a46

9 files changed

Lines changed: 276 additions & 9 deletions

File tree

src/Database/Adapter.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,13 @@ abstract public function getSupportForSpatialIndexOrder(): bool;
10771077
*/
10781078
abstract public function getSupportForBoundaryInclusiveContains(): bool;
10791079

1080+
/**
1081+
* Does the adapter support calculating distance(in meters) between multidimension geometry(line, polygon,etc)?
1082+
*
1083+
* @return bool
1084+
*/
1085+
abstract public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bool;
1086+
10801087
/**
10811088
* Get current attribute count from collection document
10821089
*

src/Database/Adapter/MariaDB.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,17 +1355,19 @@ public function deleteDocument(string $collection, string $id): bool
13551355
/**
13561356
* Handle distance spatial queries
13571357
*
1358+
* @param string $spatialAttributeType
13581359
* @param Query $query
13591360
* @param array<string, mixed> $binds
13601361
* @param string $attribute
13611362
* @param string $alias
13621363
* @param string $placeholder
13631364
* @return string
13641365
*/
1365-
protected function handleDistanceSpatialQueries(Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
1366+
protected function handleDistanceSpatialQueries(string $spatialAttributeType, Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
13661367
{
13671368
$distanceParams = $query->getValues()[0];
1368-
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
1369+
$wkt = $this->convertArrayToWKT($distanceParams[0]);
1370+
$binds[":{$placeholder}_0"] = $wkt;
13691371
$binds[":{$placeholder}_1"] = $distanceParams[1];
13701372

13711373
$useMeters = isset($distanceParams[2]) && $distanceParams[2] === true;
@@ -1388,6 +1390,11 @@ protected function handleDistanceSpatialQueries(Query $query, array &$binds, str
13881390
}
13891391

13901392
if ($useMeters) {
1393+
$wktType = $this->getSpatialTypeFromWKT($wkt);
1394+
$attrType = strtolower($spatialAttributeType);
1395+
if ($wktType != Database::VAR_POINT || $attrType != Database::VAR_POINT) {
1396+
throw new DatabaseException('Distance in meters is not supported between '.$attrType . ' and '. $wkt);
1397+
}
13911398
return "ST_DISTANCE_SPHERE({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0), 6371000) {$operator} :{$placeholder}_1";
13921399
}
13931400
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) {$operator} :{$placeholder}_1";
@@ -1396,14 +1403,15 @@ protected function handleDistanceSpatialQueries(Query $query, array &$binds, str
13961403
/**
13971404
* Handle spatial queries
13981405
*
1406+
* @param string $type
13991407
* @param Query $query
14001408
* @param array<string, mixed> $binds
14011409
* @param string $attribute
14021410
* @param string $alias
14031411
* @param string $placeholder
14041412
* @return string
14051413
*/
1406-
protected function handleSpatialQueries(Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
1414+
protected function handleSpatialQueries(string $type, Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
14071415
{
14081416
switch ($query->getMethod()) {
14091417
case Query::TYPE_CROSSES:
@@ -1418,7 +1426,7 @@ protected function handleSpatialQueries(Query $query, array &$binds, string $att
14181426
case Query::TYPE_DISTANCE_NOT_EQUAL:
14191427
case Query::TYPE_DISTANCE_GREATER_THAN:
14201428
case Query::TYPE_DISTANCE_LESS_THAN:
1421-
return $this->handleDistanceSpatialQueries($query, $binds, $attribute, $alias, $placeholder);
1429+
return $this->handleDistanceSpatialQueries($type, $query, $binds, $attribute, $alias, $placeholder);
14221430

14231431
case Query::TYPE_INTERSECTS:
14241432
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
@@ -1487,7 +1495,7 @@ protected function getSQLCondition(Query $query, array &$binds, array $attribute
14871495
$attributeType = $this->getAttributeType($query->getAttribute(), $attributes);
14881496

14891497
if (in_array($attributeType, Database::SPATIAL_TYPES)) {
1490-
return $this->handleSpatialQueries($query, $binds, $attribute, $alias, $placeholder);
1498+
return $this->handleSpatialQueries($attributeType, $query, $binds, $attribute, $alias, $placeholder);
14911499
}
14921500

14931501
switch ($query->getMethod()) {
@@ -1868,4 +1876,14 @@ public function getSupportForSpatialIndexOrder(): bool
18681876
{
18691877
return true;
18701878
}
1879+
1880+
/**
1881+
* Does the adapter support calculating distance(in meters) between multidimension geometry(line, polygon,etc)?
1882+
*
1883+
* @return bool
1884+
*/
1885+
public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bool
1886+
{
1887+
return false;
1888+
}
18711889
}

src/Database/Adapter/MySQL.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,15 @@ public function getSizeOfCollectionOnDisk(string $collection): int
8282
/**
8383
* Handle distance spatial queries
8484
*
85+
* @param string $spatialAttributeType
8586
* @param Query $query
8687
* @param array<string, mixed> $binds
8788
* @param string $attribute
8889
* @param string $alias
8990
* @param string $placeholder
9091
* @return string
9192
*/
92-
protected function handleDistanceSpatialQueries(Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
93+
protected function handleDistanceSpatialQueries(string $spatialAttributeType, Query $query, array &$binds, string $attribute, string $alias, string $placeholder): string
9394
{
9495
$distanceParams = $query->getValues()[0];
9596
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($distanceParams[0]);
@@ -173,4 +174,14 @@ public function getSupportForSpatialIndexOrder(): bool
173174
{
174175
return false;
175176
}
177+
178+
/**
179+
* Does the adapter support calculating distance(in meters) between multidimension geometry(line, polygon,etc)?
180+
*
181+
* @return bool
182+
*/
183+
public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bool
184+
{
185+
return true;
186+
}
176187
}

src/Database/Adapter/Pool.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,4 +530,13 @@ public function getSupportForSpatialIndexOrder(): bool
530530
{
531531
return $this->delegate(__FUNCTION__, \func_get_args());
532532
}
533+
/**
534+
* Does the adapter support calculating distance(in meters) between multidimension geometry(line, polygon,etc)?
535+
*
536+
* @return bool
537+
*/
538+
public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bool
539+
{
540+
return $this->delegate(__FUNCTION__, \func_get_args());
541+
}
533542
}

src/Database/Adapter/Postgres.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,9 +1488,8 @@ protected function handleDistanceSpatialQueries(Query $query, array &$binds, str
14881488
}
14891489

14901490
if ($meters) {
1491-
// Transform both attribute and input geometry to 3857 (meters) for distance calculation
1492-
$attr = "ST_Transform({$alias}.{$attribute}, 3857)";
1493-
$geom = "ST_Transform(ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . "), 3857)";
1491+
$attr = "({$alias}.{$attribute}::geography)";
1492+
$geom = "ST_SetSRID(ST_GeomFromText(:{$placeholder}_0), " . Database::SRID . ")::geography";
14941493
return "ST_Distance({$attr}, {$geom}) {$operator} :{$placeholder}_1";
14951494
}
14961495

@@ -1982,4 +1981,14 @@ public function getSupportForSpatialIndexOrder(): bool
19821981
{
19831982
return false;
19841983
}
1984+
1985+
/**
1986+
* Does the adapter support calculating distance(in meters) between multidimension geometry(line, polygon,etc)?
1987+
*
1988+
* @return bool
1989+
*/
1990+
public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bool
1991+
{
1992+
return true;
1993+
}
19851994
}

src/Database/Adapter/SQL.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2657,4 +2657,11 @@ public function sum(Document $collection, string $attribute, array $queries = []
26572657

26582658
return $result['sum'] ?? 0;
26592659
}
2660+
2661+
public function getSpatialTypeFromWKT(string $wkt): string
2662+
{
2663+
$wkt = trim($wkt);
2664+
$pos = strpos($wkt, '(');
2665+
return strtolower(trim(substr($wkt, 0, $pos)));
2666+
}
26602667
}

src/Database/Adapter/SQLite.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1263,4 +1263,14 @@ public function getSupportForBoundaryInclusiveContains(): bool
12631263
{
12641264
return false;
12651265
}
1266+
1267+
/**
1268+
* Does the adapter support calculating distance(in meters) between multidimension geometry(line, polygon,etc)?
1269+
*
1270+
* @return bool
1271+
*/
1272+
public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bool
1273+
{
1274+
return false;
1275+
}
12661276
}

src/Database/Validator/Spatial.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,11 @@ public function getType(): string
144144
return self::TYPE_ARRAY;
145145
}
146146

147+
public function getSptialType(): string
148+
{
149+
return $this->spatialType;
150+
}
151+
147152
/**
148153
* Main validation entrypoint
149154
*/

0 commit comments

Comments
 (0)