Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Geometry class extension #125

Merged
merged 9 commits into from
Jul 24, 2024
Merged
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
4 changes: 3 additions & 1 deletion .run/Test - MySQL 8.0.run.xml → .run/Test - MySQL.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Test - MySQL 8.0" type="PestRunConfigurationType">
<configuration default="false" name="Test - MySQL" type="PestRunConfigurationType">
<CommandLine>
<envs>
<env name="DB_COLLATION" value="utf8mb4_unicode_ci"/>
<env name="DB_CONNECTION" value="mysql"/>
<env name="DB_PORT" value="3307"/>
</envs>
</CommandLine>
Expand Down
12 changes: 0 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,6 @@

All notable changes to `laravel-eloquent-spatial` will be documented in this file.

## v4.2.1 - 2024-04-02

### What's Changed

* `Geometry::fromArray` added optional`$srid` paramter by @ju-gow in https://github.com/MatanYadaev/laravel-eloquent-spatial/pull/118

### New Contributors

* @ju-gow made their first contribution in https://github.com/MatanYadaev/laravel-eloquent-spatial/pull/118

**Full Changelog**: https://github.com/MatanYadaev/laravel-eloquent-spatial/compare/4.2.0...4.2.1

## v4.2.0 - 2024-03-13

### What's Changed
Expand Down
79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ For more comprehensive documentation on the API, please refer to the [API](API.m

## Extension

### Extend Geometry class with macros

You can add new methods to the `Geometry` class through macros.

Here's an example of how to register a macro in your service provider's `boot` method:
Expand All @@ -177,6 +179,83 @@ $londonEyePoint = new Point(51.5032973, -0.1217424);
echo $londonEyePoint->getName(); // Point
```

### Extend with custom geometry classes

You can extend the geometry classes by creating custom geometry classes and add functionality. You can also override existing methods, although it is not recommended, as it may lead to unexpected behavior.

1. Create a custom geometry class that extends the base geometry class.

```php
use MatanYadaev\EloquentSpatial\Objects\Point;

class ExtendedPoint extends Point
{
public function toCustomArray(): array
{
return 'coordinates' => [
'latitude' => $this->latitude,
'longitude' => $this->longitude
]
}
}
```

2. Update the geometry class mapping in a service provider file.

```php
use App\ValueObjects\ExtendedPoint;
use Illuminate\Support\ServiceProvider;
use MatanYadaev\EloquentSpatial\EloquentSpatial;

class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
EloquentSpatial::usePoint(ExtendedPoint::class);
}
}
```

3. Update your model to use the custom geometry class in the `$casts` property or `casts()` method.

```php
use App\ValueObjects\ExtendedPoint;
use Illuminate\Database\Eloquent\Model;
use MatanYadaev\EloquentSpatial\Traits\HasSpatial;

class Place extends Model
{
use HasSpatial;

protected $casts = [
'coordinates' => ExtendedPoint::class,
];

// Or:

protected function casts(): array
{
return [
'coordinates' => ExtendedPoint::class,
];
}
}
```

4. Use the custom geometry class in your code.

```php
use App\Models\Location;
use App\ValueObjects\ExtendedPoint;

$place = Place::create([
'name' => 'London Eye',
'coordinates' => new ExtendedPoint(51.5032973, -0.1217424),
]);

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

## Development

Here are some useful commands for development:
Expand Down
3 changes: 2 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ parameters:
-
message: '#Call to an undefined method Pest\\Expectation\<.+\>\:\:toBe(InstanceOf)?On(Postgres|Mysql)\(\)#'
path: tests/*.php
-
identifier: missingType.generics

level: max
checkMissingIterableValueType: true
checkGenericClassInNonGenericObjectType: false
107 changes: 107 additions & 0 deletions src/EloquentSpatial.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace MatanYadaev\EloquentSpatial;

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 EloquentSpatial
{
/** @var class-string<GeometryCollection> */
public static string $geometryCollection = GeometryCollection::class;

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

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

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

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

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

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

/**
* @param class-string<GeometryCollection> $class
*/
public static function useGeometryCollection(string $class): string
{
static::$geometryCollection = $class;

return static::$geometryCollection;
}

/**
* @param class-string<LineString> $class
*/
public static function useLineString(string $class): string
{
static::$lineString = $class;

return static::$lineString;
}

/**
* @param class-string<MultiLineString> $class
*/
public static function useMultiLineString(string $class): string
{
static::$multiLineString = $class;

return static::$multiLineString;
}

/**
* @param class-string<MultiPoint> $class
*/
public static function useMultiPoint(string $class): string
{
static::$multiPoint = $class;

return static::$multiPoint;
}

/**
* @param class-string<MultiPolygon> $class
*/
public static function useMultiPolygon(string $class): string
{
static::$multiPolygon = $class;

return static::$multiPolygon;
}

/**
* @param class-string<Point> $class
*/
public static function usePoint(string $class): string
{
static::$point = $class;

return static::$point;
}

/**
* @param class-string<Polygon> $class
*/
public static function usePolygon(string $class): string
{
static::$polygon = $class;

return static::$polygon;
}
}
21 changes: 7 additions & 14 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@
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 MultiLineString as geoPHPMultiLineString;
use MultiPoint as geoPHPMultiPoint;
use MultiPolygon as geoPHPMultiPolygon;
Expand Down Expand Up @@ -48,7 +41,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 EloquentSpatial::$point($geometry->coords[1], $geometry->coords[0], $srid);
}

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

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

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

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

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

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

return new GeometryCollection($components, $srid);
return new EloquentSpatial::$geometryCollection($components, $srid);
}
}
2 changes: 1 addition & 1 deletion src/GeometryCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function set($model, string $key, $value, array $attributes): ?Expression
return $value;
}

if (! ($value instanceof $this->className)) {
if (! ($value instanceof $this->className) || get_class($value) !== $this->className) {
$geometryType = is_object($value) ? $value::class : gettype($value);
throw new InvalidArgumentException(
sprintf('Expected %s, %s given.', $this->className, $geometryType)
Expand Down
4 changes: 1 addition & 3 deletions src/GeometryExpression.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
/** @codeCoverageIgnore */
class GeometryExpression
{
public function __construct(readonly private string $expression)
{
}
public function __construct(readonly private string $expression) {}

public function normalize(ConnectionInterface $connection): string
{
Expand Down
6 changes: 3 additions & 3 deletions tests/HasSpatialTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@
});

it('toExpressionString can handle a Expression input', function (): void {
$spatialBuilder = new TestPlace();
$spatialBuilder = new TestPlace;
$toExpressionStringMethod = (new ReflectionClass($spatialBuilder))->getMethod('toExpressionString');

$result = $toExpressionStringMethod->invoke($spatialBuilder, DB::raw('POINT(longitude, latitude)'));
Expand All @@ -456,7 +456,7 @@
});

it('toExpressionString can handle a Geometry input', function (): void {
$testPlace = new TestPlace();
$testPlace = new TestPlace;
$toExpressionStringMethod = (new ReflectionClass($testPlace))->getMethod('toExpressionString');
$polygon = Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[1,-1],[1,1],[-1,1],[-1,-1]]]}');

Expand All @@ -469,7 +469,7 @@
});

it('toExpressionString can handle a string input', function (): void {
$spatialBuilder = new TestPlace();
$spatialBuilder = new TestPlace;
$toExpressionStringMethod = (new ReflectionClass($spatialBuilder))->getMethod('toExpressionString');

$result = $toExpressionStringMethod->invoke($spatialBuilder, 'test_places.point');
Expand Down
Loading
Loading