Skip to content

Adds support for SRID. #111

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

Merged
merged 24 commits into from
Feb 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4ae8dc7
Added order by distance and distance_sphere on spatial fields (Resolv…
grimzy Mar 4, 2019
27b8920
Updated documentation :book:
grimzy Mar 4, 2019
4523cf4
Apply fixes from StyleCI
grimzy Mar 4, 2019
f124c23
Merge pull request #79 from grimzy/issue-64-scope-order-by-distance
grimzy Mar 4, 2019
2357704
upgrade laravel
MatanYadaev Aug 27, 2019
d54ae99
upgrade illuminate database
MatanYadaev Aug 27, 2019
8cab456
Fix Travis build memory exhaustion during composer install
grimzy Sep 2, 2019
738da36
Apply fixes from StyleCI
grimzy Sep 2, 2019
451da77
Typo
grimzy Sep 2, 2019
6c93b30
Merge remote-tracking branch 'origin/fix-build-memory-exhausted' into…
grimzy Sep 2, 2019
b314af0
Merge pull request #102 from grimzy/fix-build-memory-exhausted
grimzy Sep 4, 2019
6841f18
Merge pull request #100 from MatanYadaev/feature/laravel-6-support
grimzy Sep 4, 2019
eae31fa
Merge branch 'master' into srid
sikhlana Dec 7, 2019
0f94263
WKB parser now parses the SRID of the given WKB value.
sikhlana Dec 7, 2019
7d0578b
Fixes tests.
sikhlana Dec 7, 2019
2fbd40d
Updates dependency constraints.
sikhlana Dec 7, 2019
aa2a28a
Removes PHP 7.4 from .travis.yml
sikhlana Dec 7, 2019
81b8305
Merge branch 'srid-fix'
sikhlana Dec 7, 2019
11a6904
That was a weird condition.
sikhlana Dec 8, 2019
de5bd4d
Merge branch 'srid'
sikhlana Dec 8, 2019
c6462ff
Whops!
sikhlana Dec 8, 2019
01caece
Merge branch 'srid'
sikhlana Dec 8, 2019
e056dc3
Adds a new option to st_geomfromtext to make sure MySQL understands t…
sikhlana Dec 8, 2019
fe7d6bf
Merge branch 'srid'
sikhlana Dec 8, 2019
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
6 changes: 2 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
language: php

php:
- '5.5'
- '5.6'
- '7.0'
- '7.1'
- '7.2'
- '7.3'

env:
- MYSQL_VERSION=5.7
- MYSQL_VERSION=8.0

dist: trusty
Expand All @@ -19,6 +16,7 @@ services:
- docker

before_install:
- echo "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- sudo /etc/init.d/mysql stop
- make start_db V=$MYSQL_VERSION

Expand Down
248 changes: 145 additions & 103 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

[![Build Status](https://img.shields.io/travis/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://travis-ci.org/grimzy/laravel-mysql-spatial)
[![Code Climate](https://img.shields.io/codeclimate/maintainability/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/maintainability)
[![Code Climate](https://img.shields.io/codeclimate/c/grimzy/laravel-mysql-spatial.svg?style=flat-square&colorB=4BCA2A)](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/test_coverage)[![Packagist](https://img.shields.io/packagist/v/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial)
[![Packagist](https://img.shields.io/packagist/dt/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial)
[![Code Climate](https://img.shields.io/codeclimate/c/grimzy/laravel-mysql-spatial.svg?style=flat-square&colorB=4BCA2A)](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/test_coverage) [![Packagist](https://img.shields.io/packagist/v/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial)
[![Packagist](https://img.shields.io/packagist/dt/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial) [![StyleCI](https://github.styleci.io/repos/83766141/shield?branch=master)](https://github.styleci.io/repos/83766141)
[![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](LICENSE)

Laravel package to easily work with [MySQL Spatial Data Types](https://dev.mysql.com/doc/refman/5.7/en/spatial-datatypes.html) and [MySQL Spatial Functions](https://dev.mysql.com/doc/refman/5.7/en/spatial-function-reference.html).
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.

Expand Down Expand Up @@ -52,11 +52,14 @@ 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:
Then edit the migration you just created by adding at least one spatial data field. For Laravel versions prior to 5.5, you can use the Blueprint provided by this package (Grimzy\LaravelMysqlSpatial\Schema\Blueprint):

```php
use Illuminate\Database\Migrations\Migration;
use Grimzy\LaravelMysqlSpatial\Schema\Blueprint;
use Illuminate\Database\Schema\Blueprint;

// For Laravel < 5.5
// use Grimzy\LaravelMysqlSpatial\Schema\Blueprint;

class CreatePlacesTable extends Migration {

Expand Down Expand Up @@ -114,7 +117,8 @@ use Illuminate\Database\Eloquent\Model;
use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait;

/**
* @property \Grimzy\LaravelMysqlSpatial\Types\Point $location
* @property \Grimzy\LaravelMysqlSpatial\Types\Point $location
* @property \Grimzy\LaravelMysqlSpatial\Types\Polygon $area
*/
class Place extends Model
{
Expand Down Expand Up @@ -166,103 +170,19 @@ $lat = $place2->location->getLat(); // 40.7484404
$lng = $place2->location->getLng(); // -73.9878441
```

## Migrations

### Columns

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

-
`$table->geometry('column_name');`

- `$table->point('column_name');`
- `$table->lineString('column_name');`
- `$table->polygon('column_name');`
- `$table->multiPoint('column_name');`
- `$table->multiLineString('column_name');`
- `$table->multiPolygon('column_name');`
- `$table->geometryCollection('column_name');`

### 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/5.7/en/creating-spatial-indexes.html):

> For [`MyISAM`](https://dev.mysql.com/doc/refman/5.7/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:

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

Then edit the migration file that you just created:

```php
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();
});
}
}
```

## Geometry classes

### Available Geometry classes

| Grimzy\LaravelMysqlSpatial\Types | OpenGIS Class |
| ---------------------------------------- | ---------------------------------------- |
| `Point($lat, $lng)` | [Point](https://dev.mysql.com/doc/refman/5.7/en/gis-class-point.html) |
| `MultiPoint(Point[])` | [MultiPoint](https://dev.mysql.com/doc/refman/5.7/en/gis-class-multipoint.html) |
| `LineString(Point[])` | [LineString](https://dev.mysql.com/doc/refman/5.7/en/gis-class-linestring.html) |
| `MultiLineString(LineString[])` | [MultiLineString](https://dev.mysql.com/doc/refman/5.7/en/gis-class-multilinestring.html) |
| `Polygon(LineString[])` *([exterior and interior boundaries](https://dev.mysql.com/doc/refman/5.7/en/gis-class-polygon.html))* | [Polygon](https://dev.mysql.com/doc/refman/5.7/en/gis-class-polygon.html) |
| `MultiPolygon(Polygon[])` | [MultiPolygon](https://dev.mysql.com/doc/refman/5.7/en/gis-class-multipolygon.html) |
| `GeometryCollection(Geometry[])` | [GeometryCollection](https://dev.mysql.com/doc/refman/5.7/en/gis-class-geometrycollection.html) |
| Grimzy\LaravelMysqlSpatial\Types | OpenGIS Class |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| `Point($lat, $lng)` | [Point](https://dev.mysql.com/doc/refman/8.0/en/gis-class-point.html) |
| `MultiPoint(Point[])` | [MultiPoint](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multipoint.html) |
| `LineString(Point[])` | [LineString](https://dev.mysql.com/doc/refman/8.0/en/gis-class-linestring.html) |
| `MultiLineString(LineString[])` | [MultiLineString](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multilinestring.html) |
| `Polygon(LineString[])` *([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[])` | [MultiPolygon](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multipolygon.html) |
| `GeometryCollection(Geometry[])` | [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).

Expand Down Expand Up @@ -290,17 +210,21 @@ for($polygon as $i => $linestring) {

```php
// fromWKT($wkt)
$polygon = Polygon::fromWKT('POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))');
$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

```php
// fromString($wkt)
$polygon = Polygon::fromString('(0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)');
$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)
```

Expand All @@ -309,7 +233,7 @@ $polygon = Polygon::fromString('(0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)')
The Geometry classes implement [`JsonSerializable`](http://php.net/manual/en/class.jsonserializable.php) and `Illuminate\Contracts\Support\Jsonable` to help serialize into GeoJSON:

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

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

Expand All @@ -329,7 +253,7 @@ json_encode($point); // or $point->toJson();
To deserialize a GeoJSON string into a Geometry class, you can use `Geometry::fromJson($json_string)` :

```php
$locaction = Geometry::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
$location = Geometry::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
$location instanceof Point::class; // true
$location->getLat(); // 1.2
$location->getLng()); // 3.4
Expand All @@ -354,9 +278,127 @@ Available scopes:
- `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/5.7/en/spatial-function-reference.html)).*

## Migrations

For Laravel versions prior to 5.5, you can use the Blueprint provided with this package: `Grimzy\LaravelMysqlSpatial\Schema\Blueprint`.

```php
use Illuminate\Database\Migrations\Migration;
use Grimzy\LaravelMysqlSpatial\Schema\Blueprint;

class CreatePlacesTable extends Migration {
// ...
}
```

### Columns

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

- `$table->geometry('column_name')`
- `$table->point('column_name')`
- `$table->lineString('column_name')`
- `$table->polygon('column_name')`
- `$table->multiPoint('column_name')`
- `$table->multiLineString('column_name')`
- `$table->multiPolygon('column_name')`
- `$table->geometryCollection('column_name')`

### 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/5.7/en/creating-spatial-indexes.html):

> For [`MyISAM`](https://dev.mysql.com/doc/refman/5.7/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:

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

Then edit the migration file that you just created:

```php
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

```shell
composer test
# or
composer test:unit
composer test:integration
```

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

```shell
make start_db # starts MySQL 8.0
# or
make start_db V=5.7 # starts a MySQL 5.7
```

## 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

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

13 changes: 10 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"name": "grimzy/laravel-mysql-spatial",
"description": "MySQL spatial data types extension for Laravel.",
"scripts": {
"test": "phpunit -c phpunit.xml.dist",
"test:unit": "phpunit -c phpunit.xml.dist --testsuite unit",
"test:integration": "phpunit -c phpunit.xml.dist --testsuite integration"
},
"type": "library",
"license": "MIT",
"authors": [
Expand All @@ -10,15 +15,17 @@
}
],
"require": {
"php": ">=5.5",
"illuminate/database": "^5.2",
"php": ">=7.1.3",
"ext-pdo": "*",
"ext-json": "*",
"illuminate/database": "^5.6|^6.0",
"geo-io/wkb-parser": "^1.0",
"jmikola/geojson": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.8||~5.7",
"mockery/mockery": "^0.9.9",
"laravel/laravel": "^5.2",
"laravel/laravel": "^5.2|^6.0",
"doctrine/dbal": "^2.5",
"laravel/browser-kit-testing": "^2.0",
"php-coveralls/php-coveralls": "^2.0"
Expand Down
Loading