PHPackages                             limenet/laravel-mysql-spatial - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. limenet/laravel-mysql-spatial

ActiveLibrary[Database &amp; ORM](/categories/database)

limenet/laravel-mysql-spatial
=============================

MySQL spatial data types extension for Laravel.

10.0.0(2y ago)1214.2k↓17.8%8[1 issues](https://github.com/limenet/laravel-mysql-spatial/issues)[1 PRs](https://github.com/limenet/laravel-mysql-spatial/pulls)MITPHPPHP ^8.1

Since Jun 4Pushed 2y ago1 watchersCompare

[ Source](https://github.com/limenet/laravel-mysql-spatial)[ Packagist](https://packagist.org/packages/limenet/laravel-mysql-spatial)[ Docs](https://github.com/limenet/laravel-mysql-spatial)[ RSS](/packages/limenet-laravel-mysql-spatial/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (18)Versions (38)Used By (0)

Laravel MySQL Spatial extension
===============================

[](#laravel-mysql-spatial-extension)

[![Packagist](https://camo.githubusercontent.com/6bd8b822116dffbebf0883597b44fa0d12ea55dd2de5df130262a0d6ee32dce1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6c696d656e65742f6c61726176656c2d6d7973716c2d7370617469616c2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/limenet/laravel-mysql-spatial)[![license](https://camo.githubusercontent.com/2d16ff714b6c28c6147f9ba0c29999ab3e43172206a2a40f5eb4a11bc269c75b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6c696d656e65742f6c61726176656c2d6d7973716c2d7370617469616c2e7376673f7374796c653d666c61742d737175617265)](LICENSE)

Laravel package to easily work with [MySQL Spatial Data Types](https://dev.mysql.com/doc/refman/8.0/en/spatial-type-overview.html) and [MySQL Spatial Functions](https://dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html).

Please check the documentation for your MySQL version. MySQL's Extension for Spatial Data was added in MySQL 5.5 but many Spatial Functions were changed in 5.6 and 5.7.

**This package is a fork of  and virtually all code was written by the contributors to that repo. Thank you!**

This package also works with MariaDB. Please refer to the [MySQL/MariaDB Spatial Support Matrix](https://mariadb.com/kb/en/library/mysqlmariadb-spatial-support-matrix/) for compatibility.

Installation
------------

[](#installation)

Add the package using composer:

```
$ composer require limenet/laravel-mysql-spatial
```

If you need support for older versions, please consider using the package `grimzy/laravel-mysql-spatial` instead.

### Migration from `grimzy/laravel-mysql-spatial`

[](#migration-from-grimzylaravel-mysql-spatial)

1. Run `composer remove grimzy/laravel-mysql-spatial`
2. Run `composer require limenet/laravel-mysql-spatial`
3. Replace `Grimzy\` with `Limenet\` throughout your codebase (most likely, this only affects `use` statements)

Quickstart
----------

[](#quickstart)

### Create a migration

[](#create-a-migration)

From the command line:

```
php artisan make:migration create_places_table
```

Then edit the migration you just created by adding at least one spatial data field.

```
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreatePlacesTable extends Migration {
    public function up(): void
    {
        Schema::create('places', function(Blueprint $table)
        {
            $table->increments('id');
            $table->string('name')->unique();
            // Add a Point spatial data field named location
            $table->point('location')->nullable();
            // Add a Polygon spatial data field named area
            $table->polygon('area')->nullable();
            $table->timestamps();
        });

        // Or create the spatial fields with an SRID (e.g. 4326 WGS84 spheroid)

        // Schema::create('places', function(Blueprint $table)
        // {
        //     $table->increments('id');
        //     $table->string('name')->unique();
        //     // Add a Point spatial data field named location with SRID 4326
        //     $table->point('location', 4326)->nullable();
        //     // Add a Polygon spatial data field named area with SRID 4326
        //     $table->polygon('area', 4326)->nullable();
        //     $table->timestamps();
        // });
    }

    public function down(): void
    {
        Schema::drop('places');
    }
}
```

Run the migration:

```
php artisan migrate
```

### Create a model

[](#create-a-model)

From the command line:

```
php artisan make:model Place
```

Then edit the model you just created. It must use the `SpatialTrait` and define an array called `$spatialFields` with the name of the MySQL Spatial Data field(s) created in the migration:

```
namespace App;

use Illuminate\Database\Eloquent\Model;
use Limenet\LaravelMysqlSpatial\Eloquent\SpatialTrait;

/**
 * @property \Limenet\LaravelMysqlSpatial\Types\Point   $location
 * @property \Limenet\LaravelMysqlSpatial\Types\Polygon $area
 */
class Place extends Model
{
    use SpatialTrait;

    protected $fillable = [
        'name'
    ];

    protected $spatialFields = [
        'location',
        'area'
    ];
}
```

### Saving a model

[](#saving-a-model)

```
use Limenet\LaravelMysqlSpatial\Types\Point;
use Limenet\LaravelMysqlSpatial\Types\Polygon;
use Limenet\LaravelMysqlSpatial\Types\LineString;

$place1 = new Place();
$place1->name = 'Empire State Building';

// saving a point
$place1->location = new Point(40.7484404, -73.9878441);	// (lat, lng)
$place1->save();

// saving a polygon
$place1->area = new Polygon([new LineString([
    new Point(40.74894149554006, -73.98615270853043),
    new Point(40.74848633046773, -73.98648262023926),
    new Point(40.747925497790725, -73.9851602911949),
    new Point(40.74837050671544, -73.98482501506805),
    new Point(40.74894149554006, -73.98615270853043)
])]);
$place1->save();
```

Or if your database fields were created with a specific SRID:

```
use Limenet\LaravelMysqlSpatial\Types\Point;
use Limenet\LaravelMysqlSpatial\Types\Polygon;
use Limenet\LaravelMysqlSpatial\Types\LineString;

$place1 = new Place();
$place1->name = 'Empire State Building';

// saving a point with SRID 4326 (WGS84 spheroid)
$place1->location = new Point(40.7484404, -73.9878441, 4326);	// (lat, lng, srid)
$place1->save();

// saving a polygon with SRID 4326 (WGS84 spheroid)
$place1->area = new Polygon([new LineString([
    new Point(40.74894149554006, -73.98615270853043),
    new Point(40.74848633046773, -73.98648262023926),
    new Point(40.747925497790725, -73.9851602911949),
    new Point(40.74837050671544, -73.98482501506805),
    new Point(40.74894149554006, -73.98615270853043)
])], 4326);
$place1->save();
```

> **Note**: When saving collection Geometries (`LineString`, `Polygon`, `MultiPoint`, `MultiLineString`, and `GeometryCollection`), only the top-most geometry should have an SRID set in the constructor.
>
> In the example above, when creating a `new Polygon()`, we only set the SRID on the `Polygon` and use the default for the `LineString` and the `Point` objects.

### Retrieving a model

[](#retrieving-a-model)

```
$place2 = Place::first();
$lat = $place2->location->getLat();	// 40.7484404
$lng = $place2->location->getLng();	// -73.9878441
```

Geometry classes
----------------

[](#geometry-classes)

### Available Geometry classes

[](#available-geometry-classes)

`Limenet\LaravelMysqlSpatial\Types`OpenGIS Class`Point($lat, $lng, $srid = 0)`[Point](https://dev.mysql.com/doc/refman/8.0/en/gis-class-point.html)`MultiPoint(Point[], $srid = 0)`[MultiPoint](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multipoint.html)`LineString(Point[], $srid = 0)`[LineString](https://dev.mysql.com/doc/refman/8.0/en/gis-class-linestring.html)`MultiLineString(LineString[], $srid = 0)`[MultiLineString](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multilinestring.html)`Polygon(LineString[], $srid = 0)` *([exterior and interior boundaries](https://dev.mysql.com/doc/refman/8.0/en/gis-class-polygon.html))*[Polygon](https://dev.mysql.com/doc/refman/8.0/en/gis-class-polygon.html)`MultiPolygon(Polygon[], $srid = 0)`[MultiPolygon](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multipolygon.html)`GeometryCollection(Geometry[], $srid = 0)`[GeometryCollection](https://dev.mysql.com/doc/refman/8.0/en/gis-class-geometrycollection.html)Check out the [Class diagram](https://user-images.githubusercontent.com/1837678/30788608-a5afd894-a16c-11e7-9a51-0a08b331d4c4.png).

### Using Geometry classes

[](#using-geometry-classes)

In order for your Eloquent Model to handle the Geometry classes, it must use the `Limenet\LaravelMysqlSpatial\Eloquent\SpatialTrait` trait and define a `protected` property `$spatialFields` as an array of MySQL Spatial Data Type column names (example in [Quickstart](#user-content-create-a-model)).

#### IteratorAggregate and ArrayAccess

[](#iteratoraggregate-and-arrayaccess)

The collection Geometries (`LineString`, `Polygon`, `MultiPoint`, `MultiLineString`, and `GeometryCollection`) implement [`IteratorAggregate`](http://php.net/manual/en/class.iteratoraggregate.php) and [`ArrayAccess`](http://php.net/manual/en/class.arrayaccess.php); making it easy to perform Iterator and Array operations. For example:

```
$polygon = $multipolygon[10];	// ArrayAccess

// IteratorAggregate
for($polygon as $i => $linestring) {
  echo (string) $linestring;
}
```

#### Helpers

[](#helpers)

##### From/To Well Known Text ([WKT](https://dev.mysql.com/doc/refman/8.0/en/gis-data-formats.html#gis-wkt-format))

[](#fromto-well-known-text-wkt)

```
// fromWKT($wkt, $srid = 0)
$point = Point::fromWKT('POINT(2 1)');
$point->toWKT();	// POINT(2 1)

$polygon = Polygon::fromWKT('POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))');
$polygon->toWKT();	// POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))
```

##### From/To String

[](#fromto-string)

```
// fromString($wkt, $srid = 0)
$point = new Point(1, 2);	// lat, lng
(string)$point			// lng, lat: 2 1

$polygon = Polygon::fromString('(0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)');
(string)$polygon;	// (0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)
```

##### From/To JSON ([GeoJSON](http://geojson.org/))

[](#fromto-json-geojson)

The Geometry classes implement [`JsonSerializable`](http://php.net/manual/en/class.jsonserializable.php) and `Illuminate\Contracts\Support\Jsonable` to help serialize into GeoJSON:

```
$point = new Point(40.7484404, -73.9878441);

json_encode($point); // or $point->toJson();

// {
//   "type": "Feature",
//   "properties": {},
//   "geometry": {
//     "type": "Point",
//     "coordinates": [
//       -73.9878441,
//       40.7484404
//     ]
//   }
// }
```

To deserialize a GeoJSON string into a Geometry class, you can use `Geometry::fromJson($json_string)` :

```
$location = Geometry::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
$location instanceof Point::class;  // true
$location->getLat();  // 1.2
$location->getLng()); // 3.4
```

Scopes: Spatial analysis functions
----------------------------------

[](#scopes-spatial-analysis-functions)

Spatial analysis functions are implemented using [Eloquent Local Scopes](https://laravel.com/docs/5.4/eloquent#local-scopes).

Available scopes:

- `distance($geometryColumn, $geometry, $distance)`
- `distanceExcludingSelf($geometryColumn, $geometry, $distance)`
- `distanceSphere($geometryColumn, $geometry, $distance)`
- `distanceSphereExcludingSelf($geometryColumn, $geometry, $distance)`
- `comparison($geometryColumn, $geometry, $relationship)`
- `within($geometryColumn, $polygon)`
- `crosses($geometryColumn, $geometry)`
- `contains($geometryColumn, $geometry)`
- `disjoint($geometryColumn, $geometry)`
- `equals($geometryColumn, $geometry)`
- `intersects($geometryColumn, $geometry)`
- `overlaps($geometryColumn, $geometry)`
- `doesTouch($geometryColumn, $geometry)`
- `orderBySpatial($geometryColumn, $geometry, $orderFunction, $direction = 'asc')`
- `orderByDistance($geometryColumn, $geometry, $direction = 'asc')`
- `orderByDistanceSphere($geometryColumn, $geometry, $direction = 'asc')`

*Note that behavior and availability of MySQL spatial analysis functions differs in each MySQL version (cf. [documentation](https://dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html)).*

### Columns

[](#columns)

Available [MySQL Spatial Types](https://dev.mysql.com/doc/refman/8.0/en/spatial-type-overview.html) migration blueprints:

- `$table->geometry(string $column_name, int $srid = 0)`
- `$table->point(string $column_name, int $srid = 0)`
- `$table->lineString(string $column_name, int $srid = 0)`
- `$table->polygon(string $column_name, int $srid = 0)`
- `$table->multiPoint(string $column_name, int $srid = 0)`
- `$table->multiLineString(string $column_name, int $srid = 0)`
- `$table->multiPolygon(string $column_name, int $srid = 0)`
- `$table->geometryCollection(string $column_name, int $srid = 0)`

### Spatial indexes

[](#spatial-indexes)

You can add or drop spatial indexes in your migrations with the `spatialIndex` and `dropSpatialIndex` blueprints.

- `$table->spatialIndex('column_name')`
- `$table->dropSpatialIndex(['column_name'])` or `$table->dropSpatialIndex('index_name')`

Note about spatial indexes from the [MySQL documentation](https://dev.mysql.com/doc/refman/8.0/en/creating-spatial-indexes.html):

> For [`MyISAM`](https://dev.mysql.com/doc/refman/8.0/en/myisam-storage-engine.html) and (as of MySQL 5.7.5) `InnoDB` tables, MySQL can create spatial indexes using syntax similar to that for creating regular indexes, but using the `SPATIAL` keyword. Columns in spatial indexes must be declared `NOT NULL`.

Also please read this [**important note**](https://laravel.com/docs/5.5/migrations#indexes) regarding Index Lengths in the Laravel 5.6 documentation.

For example, as a follow up to the [Quickstart](#user-content-create-a-migration); from the command line, generate a new migration:

```
php artisan make:migration update_places_table
```

Then edit the migration file that you just created:

```
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class UpdatePlacesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // MySQL < 5.7.5: table has to be MyISAM
        // \DB::statement('ALTER TABLE places ENGINE = MyISAM');

        Schema::table('places', function (Blueprint $table) {
            // Make sure point is not nullable
            $table->point('location')->change();

            // Add a spatial index on the location field
            $table->spatialIndex('location');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('places', function (Blueprint $table) {
            $table->dropSpatialIndex(['location']); // either an array of column names or the index name
        });

        // \DB::statement('ALTER TABLE places ENGINE = InnoDB');

        Schema::table('places', function (Blueprint $table) {
            $table->point('location')->nullable()->change();
        });
    }
}
```

Tests
-----

[](#tests)

```
$ composer test
```

Integration tests require a running MySQL database. If you have Docker installed, you can start easily start one:

```
$ make start_db		# starts MySQL 8.0
# or
$ make start_db V=5.7	# starts MySQL 5.7
```

Contributing
------------

[](#contributing)

Recommendations and pull request are most welcome! Pull requests with tests are the best! There are still a lot of MySQL spatial functions to implement or creative ways to use spatial functions.

Credits
-------

[](#credits)

Originally inspired from [njbarrett's Laravel postgis package](https://github.com/njbarrett/laravel-postgis).

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance18

Infrequent updates — may be unmaintained

Popularity35

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity84

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 71.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~85 days

Recently: every ~304 days

Total

27

Last Release

1047d ago

Major Versions

1.3.1 → 2.2.22020-03-08

1.3.2 → 2.2.32020-03-09

1.3.3 → 3.0.02020-04-14

3.0.0 → v4.x-dev2020-09-21

4.0.0 → 10.0.02023-07-07

PHP version history (4 changes)1.0.0PHP &gt;=5.5

1.1.0PHP &gt;=5.5.9

v4.x-devPHP &gt;=7.3

10.0.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/60ffeab38b702282a7178b82152e912d8a5e934fe5cb63df272a9392f00b8f84?d=identicon)[limenet](/maintainers/limenet)

---

Top Contributors

[![grimzy](https://avatars.githubusercontent.com/u/1837678?v=4)](https://github.com/grimzy "grimzy (152 commits)")[![limenet](https://avatars.githubusercontent.com/u/474329?v=4)](https://github.com/limenet "limenet (19 commits)")[![sikhlana](https://avatars.githubusercontent.com/u/1730777?v=4)](https://github.com/sikhlana "sikhlana (12 commits)")[![Dylan-DutchAndBold](https://avatars.githubusercontent.com/u/36036362?v=4)](https://github.com/Dylan-DutchAndBold "Dylan-DutchAndBold (8 commits)")[![davidpiesse](https://avatars.githubusercontent.com/u/800650?v=4)](https://github.com/davidpiesse "davidpiesse (6 commits)")[![antonkomarev](https://avatars.githubusercontent.com/u/1849174?v=4)](https://github.com/antonkomarev "antonkomarev (4 commits)")[![astrogin](https://avatars.githubusercontent.com/u/13066161?v=4)](https://github.com/astrogin "astrogin (3 commits)")[![d3radicated](https://avatars.githubusercontent.com/u/22888549?v=4)](https://github.com/d3radicated "d3radicated (2 commits)")[![MatanYadaev](https://avatars.githubusercontent.com/u/13586343?v=4)](https://github.com/MatanYadaev "MatanYadaev (2 commits)")[![georgeboot](https://avatars.githubusercontent.com/u/884482?v=4)](https://github.com/georgeboot "georgeboot (2 commits)")[![kocoten1992](https://avatars.githubusercontent.com/u/7130705?v=4)](https://github.com/kocoten1992 "kocoten1992 (1 commits)")[![jl9404](https://avatars.githubusercontent.com/u/1576809?v=4)](https://github.com/jl9404 "jl9404 (1 commits)")[![bricehartmann](https://avatars.githubusercontent.com/u/9779486?v=4)](https://github.com/bricehartmann "bricehartmann (1 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisRector

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/limenet-laravel-mysql-spatial/health.svg)

```
[![Health](https://phpackages.com/badges/limenet-laravel-mysql-spatial/health.svg)](https://phpackages.com/packages/limenet-laravel-mysql-spatial)
```

###  Alternatives

[silber/bouncer

Eloquent roles and abilities.

3.6k4.4M25](/packages/silber-bouncer)[watson/validating

Eloquent model validating trait.

9723.3M47](/packages/watson-validating)[bavix/laravel-wallet

It's easy to work with a virtual wallet.

1.3k1.1M11](/packages/bavix-laravel-wallet)[dyrynda/laravel-model-uuid

This package allows you to easily work with UUIDs in your Laravel models.

4802.8M8](/packages/dyrynda-laravel-model-uuid)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

423715.4k1](/packages/clickbar-laravel-magellan)[reedware/laravel-relation-joins

Adds the ability to join on a relationship by name.

2121.2M13](/packages/reedware-laravel-relation-joins)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
