Skip to content

Commit

Permalink
Fix SRID not being optional for expression in GeometryCast (#124)
Browse files Browse the repository at this point in the history
* Add test case to illustrate problems with regex to convert WKT to geometry

* Adjust GeometryCast regex to support geometry expression without SRID

* Formatting
  • Loading branch information
nickknissen authored Aug 7, 2024
1 parent 31c6882 commit d11470b
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 16 deletions.
24 changes: 8 additions & 16 deletions src/GeometryCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ public function get($model, string $key, $value, array $attributes): ?Geometry
}

if ($value instanceof ExpressionContract) {
$wkt = $this->extractWktFromExpression($value, $model->getConnection());
$srid = $this->extractSridFromExpression($value, $model->getConnection());
$expressionValues = $this->extractFromExpression($value, $model->getConnection());

return $this->className::fromWkt($wkt, $srid);
return $this->className::fromWkt($expressionValues['wkt'], $expressionValues['srid']);
}

return $this->className::fromWkb($value);
Expand Down Expand Up @@ -87,23 +86,16 @@ private function isCorrectGeometryType(mixed $value): bool
return $value instanceof $this->className && get_class($value) === $this->className;
}

private function extractWktFromExpression(ExpressionContract $expression, Connection $connection): string
{
$grammar = $connection->getQueryGrammar();
$expressionValue = $expression->getValue($grammar);

preg_match('/ST_GeomFromText\(\'(.+)\', .+(, .+)?\)/', (string) $expressionValue, $match);

return $match[1];
}

private function extractSridFromExpression(ExpressionContract $expression, Connection $connection): int
/**
* @return array{wkt: string, srid: int}
*/
private function extractFromExpression(ExpressionContract $expression, Connection $connection): array
{
$grammar = $connection->getQueryGrammar();
$expressionValue = $expression->getValue($grammar);

preg_match('/ST_GeomFromText\(\'.+\', (.+)(, .+)?\)/', (string) $expressionValue, $match);
preg_match("/ST_GeomFromText\(\s*'([^']+)'\s*(?:,\s*(\d+))?\s*(?:,\s*'([^']+)')?\s*\)/", (string) $expressionValue, $matches);

return (int) $match[1];
return ['wkt' => $matches[1], 'srid' => (int) ($matches[2] ?? 0)];
}
}
28 changes: 28 additions & 0 deletions tests/GeometryCastTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

use Illuminate\Support\Facades\DB;
use MatanYadaev\EloquentSpatial\AxisOrder;
use MatanYadaev\EloquentSpatial\Enums\Srid;
use MatanYadaev\EloquentSpatial\GeometryExpression;
use MatanYadaev\EloquentSpatial\Objects\LineString;
Expand Down Expand Up @@ -189,3 +190,30 @@

expect($testPlace->isDirty())->toBeFalse();
});

it('handles ST_GeomFromText optional values on a raw expression', function (string $expression): void {
// Arrange
$testPlace = TestPlace::factory()->create(['point' => DB::raw($expression)]);

// Act
$testPlace->point = null;

// Assert
// Will trigger 'point' attribute to cast raw expression to a Point object
expect($testPlace->isDirty())->toBeTrue();
})->with([
'without SRID' => "ST_GeomFromText('POINT(12.38057 55.73406)')",
'with SRID' => "ST_GeomFromText('POINT(12.38057 55.73406)', 4326)",
]);

it('handles ST_GeomFromText option for mysql on a raw expression', function (): void {
// Arrange
$testPlace = TestPlace::factory()->create(['point' => DB::raw("ST_GeomFromText('POINT(12.38057 55.73406)', 4326, 'axis-order=long-lat')")]);

// Act
$testPlace->point = null;

// Assert
// Will trigger 'point' attribute to cast raw expression to a Point object
expect($testPlace->isDirty())->toBeTrue();
})->skip(fn () => ! AxisOrder::supported(DB::connection()));

0 comments on commit d11470b

Please sign in to comment.