Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,52 @@ Place::query()->whereDistance(...); // This is IDE-friendly
Place::whereDistance(...); // This is not
```

## Extension

You can extend the package by creating your own geometry classes.

1. Create an extended geometry class:
```php
class ExtendedPoint extends Point
{
public function toCustomArray(): array
{
return [
'latitude' => $this->latitude,
'longitude' => $this->longitude,
];
}
}
```
2. Update the geometry class mapping in a service provider file.
```php
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
LaravelEloquentSpatial::$pointClass = ExtendedPoint::class;
}
}
```
3. Cast the extended geometry class.
```php
class Place extends Model
{
protected $casts = [
'location' => ExtendedPoint::class,
];
}
```
4. Retrieve a record with the extended geometry class.
```php
$place = Place::create([
'name' => 'London Eye',
'location' => new ExtendedPoint(51.5032973, -0.1217424),
]);

$place->fresh()->location->toCustomArray(); // ['latitude' => 51.5032973, 'longitude' => -0.1217424]
```

## Development

* Test: `composer pest`
Expand Down
22 changes: 8 additions & 14 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,7 @@
use InvalidArgumentException;
use LineString as geoPHPLineString;
use MatanYadaev\EloquentSpatial\Objects\Geometry;
use MatanYadaev\EloquentSpatial\Objects\GeometryCollection;
use MatanYadaev\EloquentSpatial\Objects\LineString;
use MatanYadaev\EloquentSpatial\Objects\MultiLineString;
use MatanYadaev\EloquentSpatial\Objects\MultiPoint;
use MatanYadaev\EloquentSpatial\Objects\MultiPolygon;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Objects\Polygon;
use MatanYadaev\EloquentSpatial\Tests\LaravelEloquentSpatial;
use MultiLineString as geoPHPMultiLineString;
use MultiPoint as geoPHPMultiPoint;
use MultiPolygon as geoPHPMultiPolygon;
Expand Down Expand Up @@ -48,7 +42,7 @@ protected static function createFromGeometry(geoPHPGeometry $geometry): Geometry
throw new InvalidArgumentException('Invalid spatial value');
}

return new Point($geometry->coords[1], $geometry->coords[0], $srid);
return new LaravelEloquentSpatial::$pointClass($geometry->coords[1], $geometry->coords[0], $srid);
}

/** @var geoPHPGeometryCollection $geometry */
Expand All @@ -58,25 +52,25 @@ protected static function createFromGeometry(geoPHPGeometry $geometry): Geometry
});

if ($geometry::class === geoPHPMultiPoint::class) {
return new MultiPoint($components, $srid);
return new LaravelEloquentSpatial::$multiPointClass($components, $srid);
}

if ($geometry::class === geoPHPLineString::class) {
return new LineString($components, $srid);
return new LaravelEloquentSpatial::$lineStringClass($components, $srid);
}

if ($geometry::class === geoPHPPolygon::class) {
return new Polygon($components, $srid);
return new LaravelEloquentSpatial::$polygonClass($components, $srid);
}

if ($geometry::class === geoPHPMultiLineString::class) {
return new MultiLineString($components, $srid);
return new LaravelEloquentSpatial::$multiLineStringClass($components, $srid);
}

if ($geometry::class === geoPHPMultiPolygon::class) {
return new MultiPolygon($components, $srid);
return new LaravelEloquentSpatial::$multiPolygonClass($components, $srid);
}

return new GeometryCollection($components, $srid);
return new LaravelEloquentSpatial::$geometryCollectionClass($components, $srid);
}
}
2 changes: 1 addition & 1 deletion src/GeometryCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function set($model, string $key, $value, array $attributes): Expression|
if (! ($value instanceof $this->className)) {
$geometryType = is_object($value) ? $value::class : gettype($value);
throw new InvalidArgumentException(
sprintf('Expected %s, %s given.', static::class, $geometryType)
sprintf('Expected %s, %s given.', $this->className, $geometryType)
);
}

Expand Down
35 changes: 35 additions & 0 deletions tests/LaravelEloquentSpatial.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace MatanYadaev\EloquentSpatial\Tests;

use MatanYadaev\EloquentSpatial\Objects\GeometryCollection;
use MatanYadaev\EloquentSpatial\Objects\LineString;
use MatanYadaev\EloquentSpatial\Objects\MultiLineString;
use MatanYadaev\EloquentSpatial\Objects\MultiPoint;
use MatanYadaev\EloquentSpatial\Objects\MultiPolygon;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Objects\Polygon;

class LaravelEloquentSpatial
{
/** @var class-string<Point> */
public static string $pointClass = Point::class;

/** @var class-string<LineString> */
public static string $lineStringClass = LineString::class;

/** @var class-string<MultiPoint> */
public static string $multiPointClass = MultiPoint::class;

/** @var class-string<Polygon> */
public static string $polygonClass = Polygon::class;

/** @var class-string<MultiLineString> */
public static string $multiLineStringClass = MultiLineString::class;

/** @var class-string<MultiPolygon> */
public static string $multiPolygonClass = MultiPolygon::class;

/** @var class-string<GeometryCollection> */
public static string $geometryCollectionClass = GeometryCollection::class;
}
47 changes: 47 additions & 0 deletions tests/Objects/GeometryCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
use MatanYadaev\EloquentSpatial\Objects\LineString;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Objects\Polygon;
use MatanYadaev\EloquentSpatial\Tests\LaravelEloquentSpatial;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestExtendedPlace;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestPlace;
use MatanYadaev\EloquentSpatial\Tests\TestObjects\ExtendedGeometryCollection;

uses(DatabaseMigrations::class);

Expand Down Expand Up @@ -365,3 +368,47 @@

expect($geometryCollection->__toString())->toEqual('GEOMETRYCOLLECTION(POLYGON((180 0, 179 1, 178 2, 177 3, 180 0)), POINT(180 0))');
});

it('uses an extended GeometryCollection class', function (): void {
LaravelEloquentSpatial::$geometryCollectionClass = ExtendedGeometryCollection::class;

$geometryCollection = new ExtendedGeometryCollection([
new Polygon([
new LineString([
new Point(0, 180),
new Point(1, 179),
new Point(2, 178),
new Point(3, 177),
new Point(0, 180),
]),
]),
new Point(0, 180),
], 4326);

/** @var TestExtendedPlace $testPlace */
$testPlace = TestExtendedPlace::factory()->create(['geometry_collection' => $geometryCollection])->fresh();

expect($testPlace->geometry_collection)->toBeInstanceOf(ExtendedGeometryCollection::class);
expect($testPlace->geometry_collection)->toEqual($geometryCollection);
});

it('throws exception when storing a record with regular GeometryCollection instead of the extended one', function (): void {
LaravelEloquentSpatial::$geometryCollectionClass = ExtendedGeometryCollection::class;

$geometryCollection = new GeometryCollection([
new Polygon([
new LineString([
new Point(0, 180),
new Point(1, 179),
new Point(2, 178),
new Point(3, 177),
new Point(0, 180),
]),
]),
new Point(0, 180),
], 4326);

expect(function () use ($geometryCollection): void {
TestExtendedPlace::factory()->create(['geometry_collection' => $geometryCollection]);
})->toThrow(InvalidArgumentException::class);
});
3 changes: 3 additions & 0 deletions tests/Objects/GeometryTest.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<?php

use Illuminate\Database\QueryException;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Support\Facades\DB;
use MatanYadaev\EloquentSpatial\AxisOrder;
use MatanYadaev\EloquentSpatial\Objects\LineString;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestPlace;

uses(DatabaseMigrations::class);

it('throws exception when generating geometry from other geometry WKB', function (): void {
expect(function (): void {
$pointWkb = (new Point(0, 180))->toWkb();
Expand Down
31 changes: 31 additions & 0 deletions tests/Objects/LineStringTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
use MatanYadaev\EloquentSpatial\Objects\LineString;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Objects\Polygon;
use MatanYadaev\EloquentSpatial\Tests\LaravelEloquentSpatial;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestExtendedPlace;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestPlace;
use MatanYadaev\EloquentSpatial\Tests\TestObjects\ExtendedLineString;

uses(DatabaseMigrations::class);

Expand Down Expand Up @@ -160,3 +163,31 @@

expect($lineString->__toString())->toEqual('LINESTRING(180 0, 179 1)');
});

it('uses an extended LineString class', function (): void {
LaravelEloquentSpatial::$lineStringClass = ExtendedLineString::class;

$lineString = new ExtendedLineString([
new Point(0, 180),
new Point(1, 179),
], 4326);

/** @var TestExtendedPlace $testPlace */
$testPlace = TestExtendedPlace::factory()->create(['line_string' => $lineString])->fresh();

expect($testPlace->line_string)->toBeInstanceOf(ExtendedLineString::class);
expect($testPlace->line_string)->toEqual($lineString);
});

it('throws exception when storing a record with regular LineString instead of the extended one', function (): void {
LaravelEloquentSpatial::$lineStringClass = ExtendedLineString::class;

$lineString = new LineString([
new Point(0, 180),
new Point(1, 179),
], 4326);

expect(function () use ($lineString): void {
TestExtendedPlace::factory()->create(['line_string' => $lineString]);
})->toThrow(InvalidArgumentException::class);
});
35 changes: 35 additions & 0 deletions tests/Objects/MultiLineStringTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
use MatanYadaev\EloquentSpatial\Objects\LineString;
use MatanYadaev\EloquentSpatial\Objects\MultiLineString;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Tests\LaravelEloquentSpatial;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestExtendedPlace;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestPlace;
use MatanYadaev\EloquentSpatial\Tests\TestObjects\ExtendedMultiLineString;

uses(DatabaseMigrations::class);

Expand Down Expand Up @@ -182,3 +185,35 @@

expect($multiLineString->__toString())->toEqual('MULTILINESTRING((180 0, 179 1))');
});

it('uses an extended MultiLineString class', function (): void {
LaravelEloquentSpatial::$multiLineStringClass = ExtendedMultiLineString::class;

$multiLineString = new ExtendedMultiLineString([
new LineString([
new Point(0, 180),
new Point(1, 179),
]),
], 4326);

/** @var TestExtendedPlace $testPlace */
$testPlace = TestExtendedPlace::factory()->create(['multi_line_string' => $multiLineString])->fresh();

expect($testPlace->multi_line_string)->toBeInstanceOf(ExtendedMultiLineString::class);
expect($testPlace->multi_line_string)->toEqual($multiLineString);
});

it('throws exception when storing a record with regular MultiLineString instead of the extended one', function (): void {
LaravelEloquentSpatial::$multiLineStringClass = ExtendedMultiLineString::class;

$multiLineString = new MultiLineString([
new LineString([
new Point(0, 180),
new Point(1, 179),
]),
], 4326);

expect(function () use ($multiLineString): void {
TestExtendedPlace::factory()->create(['multi_line_string' => $multiLineString]);
})->toThrow(InvalidArgumentException::class);
});
29 changes: 29 additions & 0 deletions tests/Objects/MultiPointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
use MatanYadaev\EloquentSpatial\Objects\MultiPoint;
use MatanYadaev\EloquentSpatial\Objects\Point;
use MatanYadaev\EloquentSpatial\Objects\Polygon;
use MatanYadaev\EloquentSpatial\Tests\LaravelEloquentSpatial;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestExtendedPlace;
use MatanYadaev\EloquentSpatial\Tests\TestModels\TestPlace;
use MatanYadaev\EloquentSpatial\Tests\TestObjects\ExtendedMultiPoint;

uses(DatabaseMigrations::class);

Expand Down Expand Up @@ -146,3 +149,29 @@

expect($multiPoint->__toString())->toEqual('MULTIPOINT(180 0)');
});

it('uses an extended MultiPoint class', function (): void {
LaravelEloquentSpatial::$multiPointClass = ExtendedMultiPoint::class;

$multiPoint = new ExtendedMultiPoint([
new Point(0, 180),
], 4326);

/** @var TestExtendedPlace $testPlace */
$testPlace = TestExtendedPlace::factory()->create(['multi_point' => $multiPoint])->fresh();

expect($testPlace->multi_point)->toBeInstanceOf(ExtendedMultiPoint::class);
expect($testPlace->multi_point)->toEqual($multiPoint);
});

it('throws exception when storing a record with regular MultiPoint instead of the extended one', function (): void {
LaravelEloquentSpatial::$multiPointClass = ExtendedMultiPoint::class;

$multiPoint = new MultiPoint([
new Point(0, 180),
], 4326);

expect(function () use ($multiPoint): void {
TestExtendedPlace::factory()->create(['multi_point' => $multiPoint]);
})->toThrow(InvalidArgumentException::class);
});
Loading