Skip to content
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: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

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

## 3.0.1 - 2025-05-14
- Expression support added to `get()` method in `LocationCast`.
- Replaced `@test` annotations with `#[Test]` attributes across the test suite for modern PHPUnit syntax.

## 3.0.0 - 2025-02-20
- Laravel 12 and PHP 8.4 support added.
- Laravel 10 and below versions are not supported anymore.
Expand Down
20 changes: 19 additions & 1 deletion src/Casts/LocationCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function get($model, string $key, $value, array $attributes): ?Point
return null;
}

$coordinates = explode(',', $value);
$coordinates = $this->getCoordinates($model, $value);

if (count($coordinates) > 1) {
$location = explode(',', str_replace(['POINT(', ')', ' '], ['', '', ','], $coordinates[0]));
Expand Down Expand Up @@ -51,4 +51,22 @@ public function serialize($model, string $key, $value, array $attributes): array
{
return $value->toArray();
}

private function getCoordinates($model, $value): array
{
if ($value instanceof Expression) {
preg_match(
pattern: "/ST_GeomFromText\(\s*'([^']+)'\s*(?:,\s*(\d+))?\s*(?:,\s*'([^']+)')?\s*\)/",
subject: (string) $value->getValue($model->getConnection()->getQueryGrammar()),
matches: $matches,
);

return [
$matches[1],
(int) ($matches[2] ?? 0),
];
}

return explode(',', $value);
}
}
11 changes: 6 additions & 5 deletions tests/HasSpatialTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

namespace TarfinLabs\LaravelSpatial\Tests;

use PHPUnit\Framework\Attributes\Test;
use TarfinLabs\LaravelSpatial\Tests\TestModels\Address;
use TarfinLabs\LaravelSpatial\Types\Point;

class HasSpatialTest extends TestCase
{
/** @test */
#[Test]
public function it_generates_sql_query_for_selectDistanceTo_scope(): void
{
// Arrange
Expand All @@ -24,7 +25,7 @@ public function it_generates_sql_query_for_selectDistanceTo_scope(): void
);
}

/** @test */
#[Test]
public function it_generates_sql_query_for_withinDistanceTo_scope(): void
{
// 1. Arrange
Expand All @@ -41,7 +42,7 @@ public function it_generates_sql_query_for_withinDistanceTo_scope(): void
);
}

/** @test */
#[Test]
public function it_generates_sql_query_for_orderByDistanceTo_scope(): void
{
// 1. Arrange
Expand All @@ -64,7 +65,7 @@ public function it_generates_sql_query_for_orderByDistanceTo_scope(): void
);
}

/** @test */
#[Test]
public function it_generates_sql_query_for_location_casted_attributes(): void
{
// 1. Arrange
Expand All @@ -78,7 +79,7 @@ public function it_generates_sql_query_for_location_casted_attributes(): void
);
}

/** @test */
#[Test]
public function it_returns_location_casted_attributes(): void
{
// 1. Arrange
Expand Down
32 changes: 26 additions & 6 deletions tests/LocationCastTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

namespace TarfinLabs\LaravelSpatial\Tests;

use Illuminate\Database\Query\Expression;
use InvalidArgumentException;
use Illuminate\Support\Facades\DB;
use PHPUnit\Framework\Attributes\Test;
use TarfinLabs\LaravelSpatial\Casts\LocationCast;
use TarfinLabs\LaravelSpatial\Tests\TestModels\Address;
use TarfinLabs\LaravelSpatial\Types\Point;

class LocationCastTest extends TestCase
{
/** @test */
#[Test]
public function it_throws_an_exception_if_casted_attribute_set_to_a_non_point_value(): void
{
// 1. Arrange
Expand All @@ -23,7 +25,7 @@ public function it_throws_an_exception_if_casted_attribute_set_to_a_non_point_va
$address->location = 'dummy';
}

/** @test */
#[Test]
public function it_can_set_the_casted_attribute_to_a_point(): void
{
// 1. Arrange
Expand All @@ -39,7 +41,7 @@ public function it_can_set_the_casted_attribute_to_a_point(): void
$this->assertEquals(DB::raw("ST_GeomFromText('{$point->toWkt()}', 4326, 'axis-order=long-lat')"), $response);
}

/** @test */
#[Test]
public function it_can_set_the_casted_attribute_to_a_point_with_srid(): void
{
// 1. Arrange
Expand All @@ -55,7 +57,7 @@ public function it_can_set_the_casted_attribute_to_a_point_with_srid(): void
$this->assertEquals(DB::raw("ST_GeomFromText('{$point->toWkt()}', {$point->getSrid()}, 'axis-order=long-lat')"), $response);
}

/** @test */
#[Test]
public function it_can_get_a_casted_attribute(): void
{
// 1. Arrange
Expand All @@ -73,7 +75,25 @@ public function it_can_get_a_casted_attribute(): void
$this->assertEquals($point->getSrid(), $address->location->getSrid());
}

/** @test */
#[Test]
public function it_can_get_a_casted_attribute_using_expression(): void
{
// 1. Arrange
$address = new Address();
$point = new Point(27.1234, 39.1234);

// 2. Act
$cast = new LocationCast();
$result = $cast->get($address, 'location', new Expression($point->toGeomFromText()), $address->getAttributes());

// 3. Assert
$this->assertInstanceOf(Point::class, $result);
$this->assertEquals($point->getLat(), $result->getLat());
$this->assertEquals($point->getLng(), $result->getLng());
$this->assertEquals($point->getSrid(), $result->getSrid());
}

#[Test]
public function it_returns_null_if_the_value_of_the_casted_column_is_null(): void
{
// 1. Arrange
Expand All @@ -86,7 +106,7 @@ public function it_returns_null_if_the_value_of_the_casted_column_is_null(): voi
$this->assertNull($address->location);
}

/** @test */
#[Test]
public function it_can_serialize_a_casted_attribute(): void
{
// 1. Arrange
Expand Down
18 changes: 8 additions & 10 deletions tests/PointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
namespace TarfinLabs\LaravelSpatial\Tests;

use Illuminate\Support\Facades\Config;
use PHPUnit\Framework\Attributes\Test;
use TarfinLabs\LaravelSpatial\Types\Point;

class PointTest extends TestCase
{
/** @test */
#[Test]
public function it_sets_lat_lng_and_srid_in_constructor(): void
{
// 1. Arrange
Expand All @@ -26,7 +27,7 @@ public function it_sets_lat_lng_and_srid_in_constructor(): void
$this->assertSame(expected: $srid, actual: $point->getSrid());
}

/** @test */
#[Test]
public function it_returns_default_lat_lng_and_srid_if_they_are_not_given_in_the_constructor(): void
{
// 1. Act
Expand All @@ -38,7 +39,7 @@ public function it_returns_default_lat_lng_and_srid_if_they_are_not_given_in_the
$this->assertSame(expected: 4326, actual: $point->getSrid());
}

/** @test */
#[Test]
public function it_returns_default_srid_in_config_if_it_is_not_null(): void
{
// 1. Arrange
Expand All @@ -53,7 +54,7 @@ public function it_returns_default_srid_in_config_if_it_is_not_null(): void
$this->assertSame(expected: 4326, actual: $point->getSrid());
}

/** @test */
#[Test]
public function it_returns_point_as_wkt(): void
{
// 1. Arrange
Expand All @@ -66,7 +67,7 @@ public function it_returns_point_as_wkt(): void
$this->assertSame("POINT({$point->getLng()} {$point->getLat()})", $wkt);
}

/** @test */
#[Test]
public function it_returns_point_as_pair(): void
{
// 1. Arrange
Expand All @@ -79,10 +80,7 @@ public function it_returns_point_as_pair(): void
$this->assertSame("{$point->getLng()} {$point->getLat()}", $pair);
}

/**
* @test
* @see
*/
#[Test]
public function it_returns_points_as_geometry(): void
{
// 1. Arrange
Expand All @@ -95,7 +93,7 @@ public function it_returns_points_as_geometry(): void
$this->assertSame("ST_GeomFromText('{$point->toWkt()}', {$point->getSrid()}, 'axis-order=long-lat')", $geometry);
}

/** @test */
#[Test]
public function it_returns_points_as_array(): void
{
// 1. Arrange
Expand Down