Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
16 changes: 7 additions & 9 deletions src/Casts/LocationCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace TarfinLabs\LaravelSpatial\Casts;

use Exception;
use InvalidArgumentException;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Contracts\Database\Eloquent\SerializesCastableAttributes;
use Illuminate\Database\Query\Expression;
Expand All @@ -31,24 +31,22 @@ public function get($model, string $key, $value, array $attributes): Point
public function set($model, string $key, $value, array $attributes): Expression
{
if (!$value instanceof Point) {
throw new Exception(message: 'The '.$key.' field must be instance of '.Point::class);
throw new InvalidArgumentException(
sprintf('The %s field must be instance of %s', $key, Point::class)
);
}

if ($value->getSrid() > 0) {
return DB::raw(
value: "ST_GeomFromText('POINT({$value->getLng()} {$value->getLat()})', {$value->getSrid()}, 'axis-order=long-lat')"
value: "ST_GeomFromText('{$value->toWkt()}', {$value->getSrid()}, 'axis-order=long-lat')"
);
}

return DB::raw(value: "ST_GeomFromText('POINT({$value->getLng()} {$value->getLat()})')");
return DB::raw(value: "ST_GeomFromText('{$value->toWkt()}')");
}

public function serialize($model, string $key, $value, array $attributes): array
{
return [
'lat' => $value->getLat(),
'lng' => $value->getLng(),
'srid' => $value->getSrid(),
];
return $value->toArray();
}
}
57 changes: 30 additions & 27 deletions src/Traits/HasSpatial.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,43 +18,46 @@ public function scopeSelectDistanceTo(Builder $query, string $column, Point $poi
$query->select('*');
}

$query->selectRaw("ST_Distance(
ST_SRID({$column}, ?),
ST_SRID(Point(?, ?), ?)
) as distance", [
$point->getSrid(),
$point->getLng(),
$point->getLat(),
$point->getSrid(),
]);
$query->selectRaw(
"ST_Distance(ST_SRID({$column}, ?), ST_SRID(Point(?, ?), ?)) as distance",
[
$point->getSrid(),
$point->getLng(),
$point->getLat(),
$point->getSrid(),
]
);
}

public function scopeWithinDistanceTo(Builder $query, string $column, Point $point, int $distance): void
{
$query->whereRaw("ST_Distance(
ST_SRID({$column}, ?),
ST_SRID(Point(?, ?), ?)
) <= ?", [...[
$point->getSrid(),
$point->getLng(),
$point->getLat(),
$point->getSrid(),
], $distance]);
$query->whereRaw(
"ST_Distance(ST_SRID({$column}, ?), ST_SRID(Point(?, ?), ?)) <= ?",
[
...[
$point->getSrid(),
$point->getLng(),
$point->getLat(),
$point->getSrid(),
],
$distance,
]
);
}

public function scopeOrderByDistanceTo(Builder $query, string $column, Point $point, string $direction = 'asc'): void
{
$direction = strtolower($direction) === 'asc' ? 'asc' : 'desc';

$query->orderByRaw("ST_Distance(
ST_SRID({$column}, ?),
ST_SRID(Point(?, ?), ?)
) ".$direction, [
$point->getSrid(),
$point->getLng(),
$point->getLat(),
$point->getSrid(),
]);
$query->orderByRaw(
"ST_Distance(ST_SRID({$column}, ?), ST_SRID(Point(?, ?), ?)) " . $direction,
[
$point->getSrid(),
$point->getLng(),
$point->getLat(),
$point->getSrid(),
]
);
}

public function newQuery(): Builder
Expand Down
19 changes: 19 additions & 0 deletions src/Types/Point.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,23 @@ public function getSrid(): int
{
return $this->srid;
}

public function toWkt(): string
{
return sprintf('POINT(%s)', $this->toPair());
}

public function toPair(): string
{
return "{$this->getLng()} {$this->getLat()}";
}

public function toArray(): array
{
return [
'lat' => $this->lat,
'lng' => $this->lng,
'srid' => $this->srid,
];
}
}
45 changes: 9 additions & 36 deletions tests/HasSpatialTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@

class HasSpatialTest extends TestCase
{
/**
* @test
* @see
*/
/** @test */
public function it_generates_sql_query_for_selectDistanceTo_scope(): void
{
// Arrange
Expand All @@ -22,18 +19,12 @@ public function it_generates_sql_query_for_selectDistanceTo_scope(): void

// Assert
$this->assertEquals(
expected: "select *, CONCAT(ST_AsText(addresses.$castedAttr, 'axis-order=long-lat'), ',', ST_SRID(addresses.$castedAttr)) as $castedAttr, ST_Distance(
ST_SRID($castedAttr, ?),
ST_SRID(Point(?, ?), ?)
) as distance from `addresses`",
expected: "select *, CONCAT(ST_AsText(addresses.$castedAttr, 'axis-order=long-lat'), ',', ST_SRID(addresses.$castedAttr)) as $castedAttr, ST_Distance(ST_SRID($castedAttr, ?), ST_SRID(Point(?, ?), ?)) as distance from `addresses`",
actual: $query->toSql()
);
}

/**
* @test
* @see
*/
/** @test */
public function it_generates_sql_query_for_withinDistanceTo_scope(): void
{
// 1. Arrange
Expand All @@ -45,18 +36,12 @@ public function it_generates_sql_query_for_withinDistanceTo_scope(): void

// 3. Assert
$this->assertEquals(
expected: "select *, CONCAT(ST_AsText(addresses.$castedAttr, 'axis-order=long-lat'), ',', ST_SRID(addresses.$castedAttr)) as $castedAttr from `addresses` where ST_Distance(
ST_SRID($castedAttr, ?),
ST_SRID(Point(?, ?), ?)
) <= ?",
expected: "select *, CONCAT(ST_AsText(addresses.$castedAttr, 'axis-order=long-lat'), ',', ST_SRID(addresses.$castedAttr)) as $castedAttr from `addresses` where ST_Distance(ST_SRID($castedAttr, ?), ST_SRID(Point(?, ?), ?)) <= ?",
actual: $query->toSql()
);
}

/**
* @test
* @see
*/
/** @test */
public function it_generates_sql_query_for_orderByDistanceTo_scope(): void
{
// 1. Arrange
Expand All @@ -69,26 +54,17 @@ public function it_generates_sql_query_for_orderByDistanceTo_scope(): void

// 3. Assert
$this->assertEquals(
expected: "select *, CONCAT(ST_AsText(addresses.$castedAttr, 'axis-order=long-lat'), ',', ST_SRID(addresses.$castedAttr)) as $castedAttr from `addresses` order by ST_Distance(
ST_SRID($castedAttr, ?),
ST_SRID(Point(?, ?), ?)
) asc",
expected: "select *, CONCAT(ST_AsText(addresses.$castedAttr, 'axis-order=long-lat'), ',', ST_SRID(addresses.$castedAttr)) as $castedAttr from `addresses` order by ST_Distance(ST_SRID($castedAttr, ?), ST_SRID(Point(?, ?), ?)) asc",
actual: $queryForAsc->toSql()
);

$this->assertEquals(
expected: "select *, CONCAT(ST_AsText(addresses.$castedAttr, 'axis-order=long-lat'), ',', ST_SRID(addresses.$castedAttr)) as $castedAttr from `addresses` order by ST_Distance(
ST_SRID($castedAttr, ?),
ST_SRID(Point(?, ?), ?)
) desc",
expected: "select *, CONCAT(ST_AsText(addresses.$castedAttr, 'axis-order=long-lat'), ',', ST_SRID(addresses.$castedAttr)) as $castedAttr from `addresses` order by ST_Distance(ST_SRID($castedAttr, ?), ST_SRID(Point(?, ?), ?)) desc",
actual: $queryForDesc->toSql()
);
}

/**
* @test
* @see
*/
/** @test */
public function it_generates_sql_query_for_location_casted_attributes(): void
{
// 1. Arrange
Expand All @@ -102,10 +78,7 @@ public function it_generates_sql_query_for_location_casted_attributes(): void
);
}

/**
* @test
* @see
*/
/** @test */
public function it_returns_location_casted_attributes(): void
{
// 1. Arrange
Expand Down
12 changes: 6 additions & 6 deletions tests/LocationCastTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace TarfinLabs\LaravelSpatial\Tests;

use Exception;
use InvalidArgumentException;
use Illuminate\Support\Facades\DB;
use TarfinLabs\LaravelSpatial\Casts\LocationCast;
use TarfinLabs\LaravelSpatial\Tests\TestModels\Address;
Expand All @@ -16,10 +16,10 @@ public function it_throws_an_exception_if_casted_attribute_set_to_a_non_point_va
// 1. Arrange
$address = new Address();

// 3. Expect
$this->expectException(Exception::class);
// 2. Expect
$this->expectException(InvalidArgumentException::class);

// 2. Act
// 3. Act
$address->location = 'dummy';
}

Expand All @@ -36,7 +36,7 @@ public function it_can_set_the_casted_attribute_to_a_point(): void
$response = $cast->set($address, 'location', $point, $address->getAttributes());

// 3. Assert
$this->assertEquals(DB::raw("ST_GeomFromText('POINT({$point->getLng()} {$point->getLat()})')"), $response);
$this->assertEquals(DB::raw("ST_GeomFromText('{$point->toWkt()}')"), $response);
}

/** @test */
Expand All @@ -52,7 +52,7 @@ public function it_can_set_the_casted_attribute_to_a_point_with_srid(): void
$response = $cast->set($address, 'location', $point, $address->getAttributes());

// 3. Assert
$this->assertEquals(DB::raw("ST_GeomFromText('POINT({$point->getLng()} {$point->getLat()})', {$point->getSrid()}, 'axis-order=long-lat')"), $response);
$this->assertEquals(DB::raw("ST_GeomFromText('{$point->toWkt()}', {$point->getSrid()}, 'axis-order=long-lat')"), $response);
}

/** @test */
Expand Down
45 changes: 45 additions & 0 deletions tests/PointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,49 @@ public function it_returns_default_srid_in_config_if_it_is_not_null(): void
$this->assertSame(expected: 0.0, actual: $point->getLng());
$this->assertSame(expected: 4326, actual: $point->getSrid());
}

/** @test */
public function it_returns_point_as_wkt(): void
{
// 1. Arrange
$point = new Point(25.1515, 36.1212, 4326);

// 2. Act
$wkt = $point->toWkt();

// 3. Assert
$this->assertSame("POINT({$point->getLng()} {$point->getLat()})", $wkt);
}

/** @test */
public function it_returns_point_as_pair(): void
{
// 1. Arrange
$point = new Point(25.1515, 36.1212, 4326);

// 2. Act
$pair = $point->toPair();

// 3. Assert
$this->assertSame("{$point->getLng()} {$point->getLat()}", $pair);
}

/** @test */
public function it_returns_points_as_array(): void
{
// 1. Arrange
$point = new Point(25.1515, 36.1212, 4326);

// 2. Act
$array = $point->toArray();

$expected = [
'lat' => $point->getLat(),
'lng' => $point->getLng(),
'srid' => $point->getSrid(),
];

// 3. Assert
$this->assertSame($expected, $array);
}
}