From 85c2e7f4fd33e7aded295e709e69abe459d08871 Mon Sep 17 00:00:00 2001 From: Matan Yadaev Date: Sat, 3 Aug 2024 22:31:12 +0300 Subject: [PATCH 1/2] fix geometry types --- src/GeometryCast.php | 11 ++- tests/Objects/GeometryTest.php | 96 +++++++++++++++++++ tests/TestModels/TestPlace.php | 4 + ..._00_00_000000_create_test_places_table.php | 1 + ..._00_00_000000_create_test_places_table.php | 1 + 5 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/GeometryCast.php b/src/GeometryCast.php index fbe00c6..37fcf98 100644 --- a/src/GeometryCast.php +++ b/src/GeometryCast.php @@ -66,7 +66,7 @@ public function set($model, string $key, $value, array $attributes): ?Expression return $value; } - if (! ($value instanceof $this->className) || get_class($value) !== $this->className) { + if (! $this->isCorrectGeometryType($value)) { $geometryType = is_object($value) ? $value::class : gettype($value); throw new InvalidArgumentException( sprintf('Expected %s, %s given.', $this->className, $geometryType) @@ -76,6 +76,15 @@ public function set($model, string $key, $value, array $attributes): ?Expression return $value->toSqlExpression($model->getConnection()); } + private function isCorrectGeometryType(mixed $value): bool + { + if ($this->className === Geometry::class && $value instanceof Geometry) { + return true; + } + + return $value instanceof $this->className && get_class($value) === $this->className; + } + private function extractWktFromExpression(ExpressionContract $expression, Connection $connection): string { $grammar = $connection->getQueryGrammar(); diff --git a/tests/Objects/GeometryTest.php b/tests/Objects/GeometryTest.php index d157f4b..45a17d2 100644 --- a/tests/Objects/GeometryTest.php +++ b/tests/Objects/GeometryTest.php @@ -8,6 +8,11 @@ use MatanYadaev\EloquentSpatial\GeometryExpression; use MatanYadaev\EloquentSpatial\Objects\Geometry; use MatanYadaev\EloquentSpatial\Objects\LineString; +use MatanYadaev\EloquentSpatial\Objects\MultiPoint; +use MatanYadaev\EloquentSpatial\Objects\MultiLineString; +use MatanYadaev\EloquentSpatial\Objects\Polygon; +use MatanYadaev\EloquentSpatial\Objects\MultiPolygon; +use MatanYadaev\EloquentSpatial\Objects\GeometryCollection; use MatanYadaev\EloquentSpatial\Objects\Point; use MatanYadaev\EloquentSpatial\Tests\TestModels\TestPlace; @@ -135,3 +140,94 @@ LineString::fromArray($pointGeoJsonArray); })->toThrow(InvalidArgumentException::class); }); + +it('creates a model record with geometry (point)', function (): void { + // Arrange + $point = Point::fromJson('{"type":"Point","coordinates":[0,180]}'); + + // Act + /** @var TestPlace $testPlace */ + $testPlace = TestPlace::factory()->create(['geometry' => $point]); + + // Assert + expect($testPlace->geometry)->toBeInstanceOf(Point::class); + expect($testPlace->geometry)->toEqual($point); +}); + +it('creates a model record with geometry (line string)', function (): void { + // Arrange + $lineString = LineString::fromJson('{"type":"LineString","coordinates":[[180,0],[179,1]]}'); + + // Act + /** @var TestPlace $testPlace */ + $testPlace = TestPlace::factory()->create(['geometry' => $lineString]); + + // Assert + expect($testPlace->geometry)->toBeInstanceOf(LineString::class); + expect($testPlace->geometry)->toEqual($lineString); +}); + +it('creates a model record with geometry (multi point)', function (): void { + // Arrange + $multiPoint = MultiPoint::fromJson('{"type":"MultiPoint","coordinates":[[180,0],[179,1]]}'); + + // Act + /** @var TestPlace $testPlace */ + $testPlace = TestPlace::factory()->create(['geometry' => $multiPoint]); + + // Assert + expect($testPlace->geometry)->toBeInstanceOf(MultiPoint::class); + expect($testPlace->geometry)->toEqual($multiPoint); +}); + +it('creates a model record with geometry (multi line string)', function (): void { + // Arrange + $multiLineString = MultiLineString::fromJson('{"type":"MultiLineString","coordinates":[[[180,0],[179,1]]]}'); + + // Act + /** @var TestPlace $testPlace */ + $testPlace = TestPlace::factory()->create(['geometry' => $multiLineString]); + + // Assert + expect($testPlace->geometry)->toBeInstanceOf(MultiLineString::class); + expect($testPlace->geometry)->toEqual($multiLineString); +}); + +it('creates a model record with geometry (polygon)', function (): void { + // Arrange + $polygon = Polygon::fromJson('{"type":"Polygon","coordinates":[[[180,0],[179,1],[180,1],[180,0]]]}'); + + // Act + /** @var TestPlace $testPlace */ + $testPlace = TestPlace::factory()->create(['geometry' => $polygon]); + + // Assert + expect($testPlace->geometry)->toBeInstanceOf(Polygon::class); + expect($testPlace->geometry)->toEqual($polygon); +}); + +it('creates a model record with geometry (multi polygon)', function (): void { + // Arrange + $multiPolygon = MultiPolygon::fromJson('{"type":"MultiPolygon","coordinates":[[[[180,0],[179,1],[180,1],[180,0]]]]}'); + + // Act + /** @var TestPlace $testPlace */ + $testPlace = TestPlace::factory()->create(['geometry' => $multiPolygon]); + + // Assert + expect($testPlace->geometry)->toBeInstanceOf(MultiPolygon::class); + expect($testPlace->geometry)->toEqual($multiPolygon); +}); + +it('creates a model record with geometry (geometry collection)', function (): void { + // Arrange + $geometryCollection = GeometryCollection::fromJson('{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[0,180]}]}'); + + // Act + /** @var TestPlace $testPlace */ + $testPlace = TestPlace::factory()->create(['geometry' => $geometryCollection]); + + // Assert + expect($testPlace->geometry)->toBeInstanceOf(GeometryCollection::class); + expect($testPlace->geometry)->toEqual($geometryCollection); +}); diff --git a/tests/TestModels/TestPlace.php b/tests/TestModels/TestPlace.php index e9dc0d1..46ee482 100644 --- a/tests/TestModels/TestPlace.php +++ b/tests/TestModels/TestPlace.php @@ -4,6 +4,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use MatanYadaev\EloquentSpatial\Objects\Geometry; use MatanYadaev\EloquentSpatial\Objects\GeometryCollection; use MatanYadaev\EloquentSpatial\Objects\LineString; use MatanYadaev\EloquentSpatial\Objects\MultiLineString; @@ -15,6 +16,7 @@ use MatanYadaev\EloquentSpatial\Traits\HasSpatial; /** + * @property Geometry $geometry * @property Point $point * @property MultiPoint $multi_point * @property LineString $line_string @@ -35,6 +37,7 @@ class TestPlace extends Model protected $fillable = [ 'address', + 'geometry', 'point', 'multi_point', 'line_string', @@ -46,6 +49,7 @@ class TestPlace extends Model ]; protected $casts = [ + 'geometry' => Geometry::class, 'point' => Point::class, 'multi_point' => MultiPoint::class, 'line_string' => LineString::class, diff --git a/tests/database/migrations-laravel-<=10/0000_00_00_000000_create_test_places_table.php b/tests/database/migrations-laravel-<=10/0000_00_00_000000_create_test_places_table.php index 1bc60d8..66f2b0c 100644 --- a/tests/database/migrations-laravel-<=10/0000_00_00_000000_create_test_places_table.php +++ b/tests/database/migrations-laravel-<=10/0000_00_00_000000_create_test_places_table.php @@ -13,6 +13,7 @@ public function up(): void $table->timestamps(); $table->string('name'); $table->string('address'); + $table->geometry('geometry')->isGeometry()->nullable(); $table->point('point')->isGeometry()->nullable(); $table->multiPoint('multi_point')->isGeometry()->nullable(); $table->lineString('line_string')->isGeometry()->nullable(); diff --git a/tests/database/migrations-laravel->=11/0000_00_00_000000_create_test_places_table.php b/tests/database/migrations-laravel->=11/0000_00_00_000000_create_test_places_table.php index cf6c4fe..cf8d2ae 100644 --- a/tests/database/migrations-laravel->=11/0000_00_00_000000_create_test_places_table.php +++ b/tests/database/migrations-laravel->=11/0000_00_00_000000_create_test_places_table.php @@ -13,6 +13,7 @@ public function up(): void $table->timestamps(); $table->string('name'); $table->string('address'); + $table->geometry('geometry', subtype: 'geometry')->nullable(); $table->geometry('point', subtype: 'point')->nullable(); $table->geometry('multi_point', subtype: 'multipoint')->nullable(); $table->geometry('line_string', subtype: 'linestring')->nullable(); From 0208bec0e15baa6fe7ade994b1c835a89296f832 Mon Sep 17 00:00:00 2001 From: Matan Yadaev Date: Sat, 3 Aug 2024 22:37:14 +0300 Subject: [PATCH 2/2] fixes --- src/GeometryCast.php | 2 ++ tests/Objects/GeometryTest.php | 6 +++--- .../0000_00_00_000000_create_test_places_table.php | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/GeometryCast.php b/src/GeometryCast.php index 37fcf98..fe60b88 100644 --- a/src/GeometryCast.php +++ b/src/GeometryCast.php @@ -73,6 +73,8 @@ public function set($model, string $key, $value, array $attributes): ?Expression ); } + /** @var Geometry $value */ + return $value->toSqlExpression($model->getConnection()); } diff --git a/tests/Objects/GeometryTest.php b/tests/Objects/GeometryTest.php index 45a17d2..a496c2c 100644 --- a/tests/Objects/GeometryTest.php +++ b/tests/Objects/GeometryTest.php @@ -7,13 +7,13 @@ use MatanYadaev\EloquentSpatial\Enums\Srid; use MatanYadaev\EloquentSpatial\GeometryExpression; use MatanYadaev\EloquentSpatial\Objects\Geometry; +use MatanYadaev\EloquentSpatial\Objects\GeometryCollection; use MatanYadaev\EloquentSpatial\Objects\LineString; -use MatanYadaev\EloquentSpatial\Objects\MultiPoint; use MatanYadaev\EloquentSpatial\Objects\MultiLineString; -use MatanYadaev\EloquentSpatial\Objects\Polygon; +use MatanYadaev\EloquentSpatial\Objects\MultiPoint; use MatanYadaev\EloquentSpatial\Objects\MultiPolygon; -use MatanYadaev\EloquentSpatial\Objects\GeometryCollection; use MatanYadaev\EloquentSpatial\Objects\Point; +use MatanYadaev\EloquentSpatial\Objects\Polygon; use MatanYadaev\EloquentSpatial\Tests\TestModels\TestPlace; it('throws exception when generating geometry from other geometry WKB', function (): void { diff --git a/tests/database/migrations-laravel-<=10/0000_00_00_000000_create_test_places_table.php b/tests/database/migrations-laravel-<=10/0000_00_00_000000_create_test_places_table.php index 66f2b0c..b608cc4 100644 --- a/tests/database/migrations-laravel-<=10/0000_00_00_000000_create_test_places_table.php +++ b/tests/database/migrations-laravel-<=10/0000_00_00_000000_create_test_places_table.php @@ -13,7 +13,7 @@ public function up(): void $table->timestamps(); $table->string('name'); $table->string('address'); - $table->geometry('geometry')->isGeometry()->nullable(); + $table->geometry('geometry')->nullable(); $table->point('point')->isGeometry()->nullable(); $table->multiPoint('multi_point')->isGeometry()->nullable(); $table->lineString('line_string')->isGeometry()->nullable();