jackardios/laravel-eloquent-spatial is a Laravel package for spatial library for laravel.
It currently has 0 GitHub stars and 720 downloads on Packagist (latest version v4.0.0).
Install it with composer require jackardios/laravel-eloquent-spatial.
Discover more Laravel packages by jackardios
or browse all Laravel packages to compare alternatives.
Last updated
Laravel package for working with spatial data types and functions in Eloquent.
composer require jackardios/laravel-eloquent-spatial
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('places', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->geometry('location', subtype: 'point')->nullable();
$table->geometry('area', subtype: 'polygon')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('places');
}
};
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Jackardios\EloquentSpatial\Objects\Point;
use Jackardios\EloquentSpatial\Objects\Polygon;
use Jackardios\EloquentSpatial\Traits\HasSpatial;
/**
* @property Point $location
* @property Polygon $area
*/
class Place extends Model
{
use HasSpatial;
protected $fillable = [
'name',
'location',
'area',
];
protected $casts = [
'location' => Point::class,
'area' => Polygon::class,
];
}
use App\Models\Place;
use Jackardios\EloquentSpatial\Objects\Point;
use Jackardios\EloquentSpatial\Objects\Polygon;
use Jackardios\EloquentSpatial\Objects\LineString;
use Jackardios\EloquentSpatial\Enums\Srid;
// Create a place with a point location
// Note: Point constructor uses (longitude, latitude) order
$place = Place::create([
'name' => 'Eiffel Tower',
'location' => new Point(2.2945, 48.8584),
]);
// Create with SRID
$place = Place::create([
'name' => 'Big Ben',
'location' => new Point(-0.1246, 51.5007, Srid::WGS84),
]);
// Create with polygon area
$place = Place::create([
'name' => 'Central Park',
'area' => new Polygon([
new LineString([
new Point(-73.9819, 40.7681),
new Point(-73.9580, 40.8006),
new Point(-73.9498, 40.7969),
new Point(-73.9737, 40.7644),
new Point(-73.9819, 40.7681), // Close the ring
]),
]),
]);
// Access coordinates
echo $place->location->longitude; // 2.2945
echo $place->location->latitude; // 48.8584
echo $place->location->srid; // 4326 (if using WGS84)
// Convert to different formats
$place->location->toWkt(); // POINT(2.2945 48.8584)
$place->location->toJson(); // {"type":"Point","coordinates":[2.2945,48.8584]}
$place->location->toArray(); // ['type' => 'Point', 'coordinates' => [2.2945, 48.8584]]
All geometry classes support creating instances from various formats:
use Jackardios\EloquentSpatial\Objects\Point;
// From constructor
$point = new Point(longitude: 2.2945, latitude: 48.8584, srid: 4326);
// From WKT
$point = Point::fromWkt('POINT(2.2945 48.8584)', srid: 4326);
// From GeoJSON
$point = Point::fromJson('{"type":"Point","coordinates":[2.2945,48.8584]}');
// From array
$point = Point::fromArray(['type' => 'Point', 'coordinates' => [2.2945, 48.8584]]);
// From WKB
$point = Point::fromWkb($binaryData);
| Class | Description |
|-------|-------------|
| Point | Single coordinate (longitude, latitude) |
| LineString | Ordered sequence of Points |
| Polygon | Closed shape defined by LineStrings |
| MultiPoint | Collection of Points |
| MultiLineString | Collection of LineStrings |
| MultiPolygon | Collection of Polygons |
| GeometryCollection | Mixed collection of any geometry types |
| BoundingBox | Rectangular bounds with antimeridian support |
The Point class validates coordinates automatically:
// Valid coordinates
$point = new Point(180, 90); // OK
$point = new Point(-180, -90); // OK
// Invalid coordinates throw InvalidArgumentException
$point = new Point(200, 0); // Error: Longitude must be between -180 and 180
$point = new Point(0, 100); // Error: Latitude must be between -90 and 90
The HasSpatial trait provides query scopes for spatial operations:
use App\Models\Place;
use Jackardios\EloquentSpatial\Objects\Point;
$referencePoint = new Point(-0.1246, 51.5007, 4326);
// Add distance to results
$places = Place::query()
->withDistanceSphere('location', $referencePoint)
->get();
foreach ($places as $place) {
echo $place->distance; // Distance in meters
}
// Filter by distance
$nearbyPlaces = Place::query()
->whereDistanceSphere('location', $referencePoint, '<', 5000) // Within 5km
->get();
// Order by distance
$closestPlaces = Place::query()
->orderByDistanceSphere('location', $referencePoint)
->limit(10)
->get();
use Jackardios\EloquentSpatial\Objects\Polygon;
$searchArea = Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[1,-1],[1,1],[-1,1],[-1,-1]]]}');
// Find places within an area
Place::whereWithin('location', $searchArea)->get();
Place::whereNotWithin('location', $searchArea)->get();
// Find places containing a point
Place::whereContains('area', $point)->get();
Place::whereNotContains('area', $point)->get();
// Other spatial relationships
Place::whereTouches('area', $geometry)->get();
Place::whereIntersects('location', $geometry)->get();
Place::whereCrosses('route', $geometry)->get();
Place::whereDisjoint('location', $geometry)->get();
Place::whereOverlaps('area', $geometry)->get();
Place::whereEquals('location', $point)->get();
// Filter by SRID
Place::whereSrid('location', '=', 4326)->get();
// Get centroid
Place::query()
->withCentroid('area')
->withCasts(['centroid' => Point::class])
->get();
The BoundingBox class represents rectangular geographic bounds:
use Jackardios\EloquentSpatial\Objects\BoundingBox;
use Jackardios\EloquentSpatial\Objects\Point;
// Create from corner points
$bbox = new BoundingBox(
leftBottom: new Point(-74.0, 40.7),
rightTop: new Point(-73.9, 40.8)
);
// Create from geometry
$bbox = BoundingBox::fromGeometry($polygon);
// Create from points with padding
$bbox = BoundingBox::fromPoints($pointsArray, minPadding: 0.01);
// Access bounds
$bbox->getLeftBottom(); // Bottom-left Point
$bbox->getRightTop(); // Top-right Point
// Convert to geometry
$polygon = $bbox->toPolygon();
$geometry = $bbox->toGeometry(); // Returns MultiPolygon if crosses antimeridian
// Check if crosses antimeridian (dateline)
$bbox->crossesAntimeridian(); // true/false
// Serialize
$bbox->toArray(); // ['left' => ..., 'bottom' => ..., 'right' => ..., 'top' => ...]
$bbox->toJson();
use Jackardios\EloquentSpatial\Objects\BoundingBox;
class Region extends Model
{
use HasSpatial;
protected $casts = [
// Store as geometry column
'bounds' => BoundingBox::class,
// Or store as JSON
'bounds' => BoundingBox::class . ':json',
];
}
Spatial Reference Identifiers define coordinate systems:
use Jackardios\EloquentSpatial\Enums\Srid;
use Jackardios\EloquentSpatial\EloquentSpatial;
// Available SRID constants
Srid::WGS84; // 4326 - GPS coordinates
Srid::WEB_MERCATOR; // 3857 - Web maps (Google Maps, etc.)
// Set default SRID for all geometries
EloquentSpatial::setDefaultSrid(Srid::WGS84);
use Jackardios\EloquentSpatial\Objects\Geometry;
// Register in a service provider
Geometry::macro('distanceToKm', function (Point $other): float {
/** @var Geometry $this */
// Custom distance calculation
});
// Usage
$point->distanceToKm($otherPoint);
use Jackardios\EloquentSpatial\Objects\Point;
use Jackardios\EloquentSpatial\EloquentSpatial;
class CustomPoint extends Point
{
public function toLatLngArray(): array
{
return ['lat' => $this->latitude, 'lng' => $this->longitude];
}
}
// Register in service provider
EloquentSpatial::usePoint(CustomPoint::class);
For complete API documentation, see API.md.
See UPGRADE.md for upgrade instructions from previous versions.
# Start database containers
docker-compose up -d
# Run tests
composer pest:mysql
composer pest:mariadb
composer pest:postgres
# Static analysis
composer phpstan
# Code formatting
composer pint
MIT License. See LICENSE.md for details.