Skip to content

Commit e68f2e3

Browse files
authored
Merge pull request #701 from utopia-php/1.x
1.x
2 parents 44af82d + dbecdf8 commit e68f2e3

File tree

11 files changed

+426
-85
lines changed

11 files changed

+426
-85
lines changed

src/Database/Adapter.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,13 @@ abstract public function getSupportForSpatialIndexNull(): bool;
10711071
*/
10721072
abstract public function getSupportForSpatialIndexOrder(): bool;
10731073

1074+
/**
1075+
* Does the adapter support spatial axis order specification?
1076+
*
1077+
* @return bool
1078+
*/
1079+
abstract public function getSupportForSpatialAxisOrder(): bool;
1080+
10741081
/**
10751082
* Does the adapter includes boundary during spatial contains?
10761083
*

src/Database/Adapter/MariaDB.php

Lines changed: 56 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ public function createDocument(Document $collection, Document $document): Docume
846846
$bindKey = 'key_' . $bindIndex;
847847
$columns .= "`{$column}`, ";
848848
if (in_array($attribute, $spatialAttributes)) {
849-
$columnNames .= 'ST_GeomFromText(:' . $bindKey . '), ';
849+
$columnNames .= $this->getSpatialGeomFromText(':' . $bindKey) . ", ";
850850
} else {
851851
$columnNames .= ':' . $bindKey . ', ';
852852
}
@@ -1116,7 +1116,7 @@ public function updateDocument(Document $collection, string $id, Document $docum
11161116
$bindKey = 'key_' . $bindIndex;
11171117

11181118
if (in_array($attribute, $spatialAttributes)) {
1119-
$columns .= "`{$column}`" . '=ST_GeomFromText(:' . $bindKey . '),';
1119+
$columns .= "`{$column}`" . '=' . $this->getSpatialGeomFromText(':' . $bindKey) . ',';
11201120
} else {
11211121
$columns .= "`{$column}`" . '=:' . $bindKey . ',';
11221122
}
@@ -1396,9 +1396,9 @@ protected function handleDistanceSpatialQueries(Query $query, array &$binds, str
13961396
if ($wktType != Database::VAR_POINT || $attrType != Database::VAR_POINT) {
13971397
throw new QueryException('Distance in meters is not supported between '.$attrType . ' and '. $wktType);
13981398
}
1399-
return "ST_DISTANCE_SPHERE({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0), 6371000) {$operator} :{$placeholder}_1";
1399+
return "ST_DISTANCE_SPHERE({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ", " . Database::EARTH_RADIUS . ") {$operator} :{$placeholder}_1";
14001400
}
1401-
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) {$operator} :{$placeholder}_1";
1401+
return "ST_Distance({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ") {$operator} :{$placeholder}_1";
14021402
}
14031403

14041404
/**
@@ -1417,11 +1417,11 @@ protected function handleSpatialQueries(Query $query, array &$binds, string $att
14171417
switch ($query->getMethod()) {
14181418
case Query::TYPE_CROSSES:
14191419
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1420-
return "ST_Crosses({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1420+
return "ST_Crosses({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14211421

14221422
case Query::TYPE_NOT_CROSSES:
14231423
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1424-
return "NOT ST_Crosses({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1424+
return "NOT ST_Crosses({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14251425

14261426
case Query::TYPE_DISTANCE_EQUAL:
14271427
case Query::TYPE_DISTANCE_NOT_EQUAL:
@@ -1431,43 +1431,43 @@ protected function handleSpatialQueries(Query $query, array &$binds, string $att
14311431

14321432
case Query::TYPE_INTERSECTS:
14331433
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1434-
return "ST_Intersects({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1434+
return "ST_Intersects({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14351435

14361436
case Query::TYPE_NOT_INTERSECTS:
14371437
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1438-
return "NOT ST_Intersects({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1438+
return "NOT ST_Intersects({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14391439

14401440
case Query::TYPE_OVERLAPS:
14411441
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1442-
return "ST_Overlaps({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1442+
return "ST_Overlaps({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14431443

14441444
case Query::TYPE_NOT_OVERLAPS:
14451445
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1446-
return "NOT ST_Overlaps({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1446+
return "NOT ST_Overlaps({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14471447

14481448
case Query::TYPE_TOUCHES:
14491449
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1450-
return "ST_Touches({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1450+
return "ST_Touches({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14511451

14521452
case Query::TYPE_NOT_TOUCHES:
14531453
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1454-
return "NOT ST_Touches({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1454+
return "NOT ST_Touches({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14551455

14561456
case Query::TYPE_EQUAL:
14571457
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1458-
return "ST_Equals({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1458+
return "ST_Equals({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14591459

14601460
case Query::TYPE_NOT_EQUAL:
14611461
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1462-
return "NOT ST_Equals({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1462+
return "NOT ST_Equals({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14631463

14641464
case Query::TYPE_CONTAINS:
14651465
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1466-
return "ST_Contains({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1466+
return "ST_Contains({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14671467

14681468
case Query::TYPE_NOT_CONTAINS:
14691469
$binds[":{$placeholder}_0"] = $this->convertArrayToWKT($query->getValues()[0]);
1470-
return "NOT ST_Contains({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0, 'axis-order=long-lat'))";
1470+
return "NOT ST_Contains({$alias}.{$attribute}, " . $this->getSpatialGeomFromText(":{$placeholder}_0", null) . ")";
14711471

14721472
default:
14731473
throw new DatabaseException('Unknown spatial query method: ' . $query->getMethod());
@@ -1593,6 +1593,9 @@ protected function getSQLCondition(Query $query, array &$binds, array $attribute
15931593
*/
15941594
protected function getSQLType(string $type, int $size, bool $signed = true, bool $array = false, bool $required = false): string
15951595
{
1596+
if (in_array($type, Database::SPATIAL_TYPES)) {
1597+
return $this->getSpatialSQLType($type, $required);
1598+
}
15961599
if ($array === true) {
15971600
return 'JSON';
15981601
}
@@ -1639,42 +1642,6 @@ protected function getSQLType(string $type, int $size, bool $signed = true, bool
16391642
case Database::VAR_DATETIME:
16401643
return 'DATETIME(3)';
16411644

1642-
1643-
case Database::VAR_POINT:
1644-
$type = 'POINT';
1645-
if (!$this->getSupportForSpatialIndexNull()) {
1646-
if ($required) {
1647-
$type .= ' NOT NULL';
1648-
} else {
1649-
$type .= ' NULL';
1650-
}
1651-
}
1652-
return $type;
1653-
1654-
case Database::VAR_LINESTRING:
1655-
$type = 'LINESTRING';
1656-
if (!$this->getSupportForSpatialIndexNull()) {
1657-
if ($required) {
1658-
$type .= ' NOT NULL';
1659-
} else {
1660-
$type .= ' NULL';
1661-
}
1662-
}
1663-
return $type;
1664-
1665-
1666-
case Database::VAR_POLYGON:
1667-
$type = 'POLYGON';
1668-
if (!$this->getSupportForSpatialIndexNull()) {
1669-
if ($required) {
1670-
$type .= ' NOT NULL';
1671-
} else {
1672-
$type .= ' NULL';
1673-
}
1674-
}
1675-
return $type;
1676-
1677-
16781645
default:
16791646
throw new DatabaseException('Unknown type: ' . $type . '. Must be one of ' . Database::VAR_STRING . ', ' . Database::VAR_INTEGER . ', ' . Database::VAR_FLOAT . ', ' . Database::VAR_BOOLEAN . ', ' . Database::VAR_DATETIME . ', ' . Database::VAR_RELATIONSHIP . ', ' . ', ' . Database::VAR_POINT . ', ' . Database::VAR_LINESTRING . ', ' . Database::VAR_POLYGON);
16801647
}
@@ -1913,4 +1880,41 @@ public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bo
19131880
{
19141881
return false;
19151882
}
1883+
1884+
public function getSpatialSQLType(string $type, bool $required): string
1885+
{
1886+
$srid = Database::SRID;
1887+
$nullability = '';
1888+
1889+
if (!$this->getSupportForSpatialIndexNull()) {
1890+
if ($required) {
1891+
$nullability = ' NOT NULL';
1892+
} else {
1893+
$nullability = ' NULL';
1894+
}
1895+
}
1896+
1897+
switch ($type) {
1898+
case Database::VAR_POINT:
1899+
return "POINT($srid)$nullability";
1900+
1901+
case Database::VAR_LINESTRING:
1902+
return "LINESTRING($srid)$nullability";
1903+
1904+
case Database::VAR_POLYGON:
1905+
return "POLYGON($srid)$nullability";
1906+
}
1907+
1908+
return '';
1909+
}
1910+
1911+
/**
1912+
* Does the adapter support spatial axis order specification?
1913+
*
1914+
* @return bool
1915+
*/
1916+
public function getSupportForSpatialAxisOrder(): bool
1917+
{
1918+
return false;
1919+
}
19161920
}

src/Database/Adapter/MySQL.php

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,13 @@ protected function handleDistanceSpatialQueries(Query $query, array &$binds, str
117117

118118
if ($useMeters) {
119119
$attr = "ST_SRID({$alias}.{$attribute}, " . Database::SRID . ")";
120-
$geom = "ST_GeomFromText(:{$placeholder}_0, " . Database::SRID . ",'axis-order=long-lat')";
120+
$geom = $this->getSpatialGeomFromText(":{$placeholder}_0", null);
121121
return "ST_Distance({$attr}, {$geom}, 'metre') {$operator} :{$placeholder}_1";
122122
}
123-
124-
// Without meters, use default behavior
125-
return "ST_Distance({$alias}.{$attribute}, ST_GeomFromText(:{$placeholder}_0)) {$operator} :{$placeholder}_1";
123+
// need to use srid 0 because of geometric distance
124+
$attr = "ST_SRID({$alias}.{$attribute}, " . 0 . ")";
125+
$geom = $this->getSpatialGeomFromText(":{$placeholder}_0", 0);
126+
return "ST_Distance({$attr}, {$geom}) {$operator} :{$placeholder}_1";
126127
}
127128

128129
public function getSupportForIndexArray(): bool
@@ -184,4 +185,68 @@ public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bo
184185
{
185186
return true;
186187
}
188+
189+
/**
190+
* Spatial type attribute
191+
*/
192+
public function getSpatialSQLType(string $type, bool $required): string
193+
{
194+
switch ($type) {
195+
case Database::VAR_POINT:
196+
$type = 'POINT SRID 4326';
197+
if (!$this->getSupportForSpatialIndexNull()) {
198+
if ($required) {
199+
$type .= ' NOT NULL';
200+
} else {
201+
$type .= ' NULL';
202+
}
203+
}
204+
return $type;
205+
206+
case Database::VAR_LINESTRING:
207+
$type = 'LINESTRING SRID 4326';
208+
if (!$this->getSupportForSpatialIndexNull()) {
209+
if ($required) {
210+
$type .= ' NOT NULL';
211+
} else {
212+
$type .= ' NULL';
213+
}
214+
}
215+
return $type;
216+
217+
218+
case Database::VAR_POLYGON:
219+
$type = 'POLYGON SRID 4326';
220+
if (!$this->getSupportForSpatialIndexNull()) {
221+
if ($required) {
222+
$type .= ' NOT NULL';
223+
} else {
224+
$type .= ' NULL';
225+
}
226+
}
227+
return $type;
228+
}
229+
return '';
230+
}
231+
232+
/**
233+
* Does the adapter support spatial axis order specification?
234+
*
235+
* @return bool
236+
*/
237+
public function getSupportForSpatialAxisOrder(): bool
238+
{
239+
return true;
240+
}
241+
242+
/**
243+
* Get the spatial axis order specification string for MySQL
244+
* MySQL with SRID 4326 expects lat-long by default, but our data is in long-lat format
245+
*
246+
* @return string
247+
*/
248+
protected function getSpatialAxisOrderSpec(): string
249+
{
250+
return "'axis-order=long-lat'";
251+
}
187252
}

src/Database/Adapter/Pool.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,4 +539,14 @@ public function getSupportForDistanceBetweenMultiDimensionGeometryInMeters(): bo
539539
{
540540
return $this->delegate(__FUNCTION__, \func_get_args());
541541
}
542+
543+
/**
544+
* Does the adapter support spatial axis order specification?
545+
*
546+
* @return bool
547+
*/
548+
public function getSupportForSpatialAxisOrder(): bool
549+
{
550+
return $this->delegate(__FUNCTION__, \func_get_args());
551+
}
542552
}

0 commit comments

Comments
 (0)