diff --git a/.travis.yml b/.travis.yml
index be0bd54a..f6a2a31f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,10 @@
language: php
php:
- - '5.5'
- - '5.6'
- - '7.0'
- - '7.1'
- - '7.2'
+ - '7.3'
+ - '7.4'
env:
- - MYSQL_VERSION=5.7
- MYSQL_VERSION=8.0
dist: trusty
@@ -19,6 +15,7 @@ services:
- docker
before_install:
+ - echo "memory_limit=3G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- sudo /etc/init.d/mysql stop
- make start_db V=$MYSQL_VERSION
@@ -32,7 +29,5 @@ before_script:
script: vendor/bin/phpunit --coverage-clover build/logs/clover.xml
-after_script:
- - php vendor/bin/coveralls -v
- - ./cc-test-reporter after-build --coverage-input-type clover --exit-code $TRAVIS_TEST_RESULT
+after_script: ./cc-test-reporter after-build --coverage-input-type clover --exit-code $TRAVIS_TEST_RESULT
diff --git a/Makefile b/Makefile
index cb716a28..62db4599 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-V=5.7
+V=8.0
DB_DIR=$(shell pwd)/_db-$(V)
mV=10.3
mDB_DIR=$(shell pwd)/_db-$(mV)
diff --git a/README.md b/README.md
index d1318946..39d5303c 100644
--- a/README.md
+++ b/README.md
@@ -2,18 +2,21 @@
[](https://travis-ci.org/grimzy/laravel-mysql-spatial)
[](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/maintainability)
-[](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/test_coverage)[](https://packagist.org/packages/grimzy/laravel-mysql-spatial)
-[](https://packagist.org/packages/grimzy/laravel-mysql-spatial)
+[](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/test_coverage) [](https://packagist.org/packages/grimzy/laravel-mysql-spatial)
+[](https://packagist.org/packages/grimzy/laravel-mysql-spatial) [](https://github.styleci.io/repos/83766141)
[](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.
**Versions**
- `1.x.x`: MySQL 5.6 (also supports MySQL 5.5 but not all spatial analysis functions)
-- `2.x.x`: MySQL 5.7 and 8.0
+- `2.x.x`: MySQL 5.7 and 8.0 (Laravel version < 8.0)
+- `3.x.x`: MySQL 8.0 with SRID support (Laravel version < 8.0)
+- **`4.x.x`: MySQL 8.0 with SRID support (Laravel 8+) [Current branch]**
+- `5.x.x`: MySQL 5.7 and 8.0 (Laravel 8+)
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.
@@ -21,14 +24,23 @@ This package also works with MariaDB. Please refer to the [MySQL/MariaDB Spatial
Add the package using composer:
+```sh
+$ composer require grimzy/laravel-mysql-spatial:^4.0
+
+# or for Laravel version < 8.0
+$ composer require grimzy/laravel-mysql-spatial:^3.0
+```
+
+For MySQL 5.7:
+
```shell
-composer require grimzy/laravel-mysql-spatial
+$ composer require grimzy/laravel-mysql-spatial:^2.0
```
For MySQL 5.6 and 5.5:
```shell
-composer require grimzy/laravel-mysql-spatial:^1.0
+$ composer require grimzy/laravel-mysql-spatial:^1.0
```
For Laravel versions before 5.5 or if not using auto-discovery, register the service provider in `config/app.php`:
@@ -52,11 +64,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 {
@@ -77,6 +92,19 @@ class CreatePlacesTable extends Migration {
$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();
+ // });
}
/**
@@ -114,7 +142,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
{
@@ -136,6 +165,7 @@ class Place extends Model
```php
use Grimzy\LaravelMysqlSpatial\Types\Point;
use Grimzy\LaravelMysqlSpatial\Types\Polygon;
+use Grimzy\LaravelMysqlSpatial\Types\LineString;
$place1 = new Place();
$place1->name = 'Empire State Building';
@@ -153,116 +183,58 @@ $place1->area = new Polygon([new LineString([
new Point(40.74894149554006, -73.98615270853043)
])]);
$place1->save();
-
-$place1->area = new Polygon();
-
```
-### Retrieving a model
+Or if your database fields were created with a specific SRID:
```php
-$place2 = Place::first();
-$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`.
+use Grimzy\LaravelMysqlSpatial\Types\Point;
+use Grimzy\LaravelMysqlSpatial\Types\Polygon;
+use Grimzy\LaravelMysqlSpatial\Types\LineString;
-Also please read this [**important note**](https://laravel.com/docs/5.5/migrations#indexes) regarding Index Lengths in the Laravel 5.6 documentation.
+$place1 = new Place();
+$place1->name = 'Empire State Building';
-For example, as a follow up to the [Quickstart](#user-content-create-a-migration); from the command line, generate a new migration:
+// saving a point with SRID 4326 (WGS84 spheroid)
+$place1->location = new Point(40.7484404, -73.9878441, 4326); // (lat, lng, srid)
+$place1->save();
-```shell
-php artisan make:migration update_places_table
+// 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();
```
-Then edit the migration file that you just created:
+> **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.
-```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');
+### Retrieving a model
- Schema::table('places', function (Blueprint $table) {
- $table->point('location')->nullable()->change();
- });
- }
-}
+```php
+$place2 = Place::first();
+$lat = $place2->location->getLat(); // 40.7484404
+$lng = $place2->location->getLng(); // -73.9878441
```
## 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, $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).
@@ -272,7 +244,7 @@ In order for your Eloquent Model to handle the Geometry classes, it must use the
#### IteratorAggregate and ArrayAccess
-The "composite" 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:
+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:
```php
$polygon = $multipolygon[10]; // ArrayAccess
@@ -286,21 +258,25 @@ for($polygon as $i => $linestring) {
#### Helpers
-##### From/To Well Known Text ([WKT](https://dev.mysql.com/doc/refman/5.7/en/gis-data-formats.html#gis-wkt-format))
+##### From/To Well Known Text ([WKT](https://dev.mysql.com/doc/refman/8.0/en/gis-data-formats.html#gis-wkt-format))
```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))');
+// 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
```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)');
+// 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)
```
@@ -309,7 +285,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();
@@ -329,10 +305,10 @@ 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 instanceof Point::class; // true
-$location->getLat(); // 1.2
-$location->getLng()); // 3.4
+$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
@@ -354,9 +330,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/8.0/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/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
+
+You can add or drop spatial indexes in your migrations with the `spatialIndex` and `dropSpatialIndex` blueprints.
-*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)).*
+- `$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:
+
+```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 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).
+
diff --git a/composer.json b/composer.json
index 4b37e283..4451cb50 100644
--- a/composer.json
+++ b/composer.json
@@ -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": [
@@ -10,18 +15,19 @@
}
],
"require": {
- "php": ">=5.5",
- "illuminate/database": "^5.2",
+ "php": ">=7.3",
+ "ext-pdo": "*",
+ "ext-json": "*",
+ "illuminate/database": "^8.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",
+ "phpunit/phpunit": "~6.5",
+ "laravel/laravel": "^8.0",
"doctrine/dbal": "^2.5",
"laravel/browser-kit-testing": "^2.0",
- "php-coveralls/php-coveralls": "^2.0"
+ "mockery/mockery": "^1.3"
},
"autoload": {
"psr-4": {
@@ -36,7 +42,7 @@
},
"extra": {
"branch-alias": {
- "dev-master": "2.0.x-dev"
+ "dev-master": "4.0.x-dev"
},
"laravel": {
"providers": [
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 3e54db39..1456a6ac 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -9,10 +9,10 @@
processIsolation="false"
stopOnFailure="false">
-
+
./tests/Unit
-
+
./tests/Integration
@@ -36,5 +36,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Eloquent/BaseBuilder.php b/src/Eloquent/BaseBuilder.php
index 33c0f21c..a2130840 100644
--- a/src/Eloquent/BaseBuilder.php
+++ b/src/Eloquent/BaseBuilder.php
@@ -6,12 +6,18 @@
class BaseBuilder extends QueryBuilder
{
- protected function cleanBindings(array $bindings)
+ public function cleanBindings(array $bindings)
{
- $bindings = array_map(function ($binding) {
- return $binding instanceof SpatialExpression ? $binding->getSpatialValue() : $binding;
- }, $bindings);
+ $spatialBindings = [];
+ foreach ($bindings as &$binding) {
+ if ($binding instanceof SpatialExpression) {
+ $spatialBindings[] = $binding->getSpatialValue();
+ $spatialBindings[] = $binding->getSrid();
+ } else {
+ $spatialBindings[] = $binding;
+ }
+ }
- return parent::cleanBindings($bindings);
+ return parent::cleanBindings($spatialBindings);
}
}
diff --git a/src/Eloquent/SpatialExpression.php b/src/Eloquent/SpatialExpression.php
index 7bc88178..9224af0f 100644
--- a/src/Eloquent/SpatialExpression.php
+++ b/src/Eloquent/SpatialExpression.php
@@ -8,11 +8,16 @@ class SpatialExpression extends Expression
{
public function getValue()
{
- return 'ST_GeomFromText(?)';
+ return "ST_GeomFromText(?, ?, 'axis-order=long-lat')";
}
public function getSpatialValue()
{
return $this->value->toWkt();
}
+
+ public function getSrid()
+ {
+ return $this->value->getSrid();
+ }
}
diff --git a/src/Eloquent/SpatialTrait.php b/src/Eloquent/SpatialTrait.php
index 5132a622..5cc3f4b1 100755
--- a/src/Eloquent/SpatialTrait.php
+++ b/src/Eloquent/SpatialTrait.php
@@ -3,6 +3,7 @@
namespace Grimzy\LaravelMysqlSpatial\Eloquent;
use Grimzy\LaravelMysqlSpatial\Exceptions\SpatialFieldsNotDefinedException;
+use Grimzy\LaravelMysqlSpatial\Exceptions\UnknownSpatialFunctionException;
use Grimzy\LaravelMysqlSpatial\Exceptions\UnknownSpatialRelationFunction;
use Grimzy\LaravelMysqlSpatial\Types\Geometry;
use Grimzy\LaravelMysqlSpatial\Types\GeometryInterface;
@@ -24,6 +25,9 @@
* @method static intersects($geometryColumn, $geometry)
* @method static overlaps($geometryColumn, $geometry)
* @method static doesTouch($geometryColumn, $geometry)
+ * @method static orderBySpatial($geometryColumn, $geometry, $orderFunction, $direction = 'asc')
+ * @method static orderByDistance($geometryColumn, $geometry, $direction = 'asc')
+ * @method static orderByDistanceSphere($geometryColumn, $geometry, $direction = 'asc')
*/
trait SpatialTrait
{
@@ -49,6 +53,11 @@ trait SpatialTrait
'touches',
];
+ protected $stOrderFunctions = [
+ 'distance',
+ 'distance_sphere',
+ ];
+
/**
* Create a new Eloquent query builder for the model.
*
@@ -66,7 +75,9 @@ protected function newBaseQueryBuilder()
$connection = $this->getConnection();
return new BaseBuilder(
- $connection, $connection->getQueryGrammar(), $connection->getPostProcessor()
+ $connection,
+ $connection->getQueryGrammar(),
+ $connection->getPostProcessor()
);
}
@@ -93,7 +104,7 @@ public function setRawAttributes(array $attributes, $sync = false)
$spatial_fields = $this->getSpatialFields();
foreach ($attributes as $attribute => &$value) {
- if (in_array($attribute, $spatial_fields) && is_string($value) && strlen($value) >= 15) {
+ if (in_array($attribute, $spatial_fields) && is_string($value) && strlen($value) >= 13) {
$value = Geometry::fromWKB($value);
}
}
@@ -123,8 +134,9 @@ public function scopeDistance($query, $geometryColumn, $geometry, $distance)
{
$this->isColumnAllowed($geometryColumn);
- $query->whereRaw("st_distance(`$geometryColumn`, ST_GeomFromText(?)) <= ?", [
+ $query->whereRaw("st_distance(`$geometryColumn`, ST_GeomFromText(?, ?, 'axis-order=long-lat')) <= ?", [
$geometry->toWkt(),
+ $geometry->getSrid(),
$distance,
]);
@@ -137,8 +149,9 @@ public function scopeDistanceExcludingSelf($query, $geometryColumn, $geometry, $
$query = $this->scopeDistance($query, $geometryColumn, $geometry, $distance);
- $query->whereRaw("st_distance(`$geometryColumn`, ST_GeomFromText(?)) != 0", [
+ $query->whereRaw("st_distance(`$geometryColumn`, ST_GeomFromText(?, ?, 'axis-order=long-lat')) != 0", [
$geometry->toWkt(),
+ $geometry->getSrid(),
]);
return $query;
@@ -154,8 +167,9 @@ public function scopeDistanceValue($query, $geometryColumn, $geometry)
$query->select('*');
}
- $query->selectRaw("st_distance(`$geometryColumn`, ST_GeomFromText(?)) as distance", [
+ $query->selectRaw("st_distance(`$geometryColumn`, ST_GeomFromText(?, ?, 'axis-order=long-lat')) as distance", [
$geometry->toWkt(),
+ $geometry->getSrid(),
]);
}
@@ -163,8 +177,9 @@ public function scopeDistanceSphere($query, $geometryColumn, $geometry, $distanc
{
$this->isColumnAllowed($geometryColumn);
- $query->whereRaw("st_distance_sphere(`$geometryColumn`, ST_GeomFromText(?)) <= ?", [
+ $query->whereRaw("st_distance_sphere(`$geometryColumn`, ST_GeomFromText(?, ?, 'axis-order=long-lat')) <= ?", [
$geometry->toWkt(),
+ $geometry->getSrid(),
$distance,
]);
@@ -177,8 +192,9 @@ public function scopeDistanceSphereExcludingSelf($query, $geometryColumn, $geome
$query = $this->scopeDistanceSphere($query, $geometryColumn, $geometry, $distance);
- $query->whereRaw("st_distance_sphere($geometryColumn, ST_GeomFromText(?)) != 0", [
+ $query->whereRaw("st_distance_sphere($geometryColumn, ST_GeomFromText(?, ?, 'axis-order=long-lat')) != 0", [
$geometry->toWkt(),
+ $geometry->getSrid(),
]);
return $query;
@@ -193,8 +209,9 @@ public function scopeDistanceSphereValue($query, $geometryColumn, $geometry)
if (!$columns) {
$query->select('*');
}
- $query->selectRaw("st_distance_sphere(`$geometryColumn`, ST_GeomFromText(?)) as distance", [
+ $query->selectRaw("st_distance_sphere(`$geometryColumn`, ST_GeomFromText(?, ?, 'axis-order=long-lat')) as distance", [
$geometry->toWkt(),
+ $geometry->getSrid(),
]);
}
@@ -206,8 +223,9 @@ public function scopeComparison($query, $geometryColumn, $geometry, $relationshi
throw new UnknownSpatialRelationFunction($relationship);
}
- $query->whereRaw("st_{$relationship}(`$geometryColumn`, ST_GeomFromText(?))", [
+ $query->whereRaw("st_{$relationship}(`$geometryColumn`, ST_GeomFromText(?, ?, 'axis-order=long-lat'))", [
$geometry->toWkt(),
+ $geometry->getSrid(),
]);
return $query;
@@ -252,4 +270,30 @@ public function scopeDoesTouch($query, $geometryColumn, $geometry)
{
return $this->scopeComparison($query, $geometryColumn, $geometry, 'touches');
}
+
+ public function scopeOrderBySpatial($query, $geometryColumn, $geometry, $orderFunction, $direction = 'asc')
+ {
+ $this->isColumnAllowed($geometryColumn);
+
+ if (!in_array($orderFunction, $this->stOrderFunctions)) {
+ throw new UnknownSpatialFunctionException($orderFunction);
+ }
+
+ $query->orderByRaw("st_{$orderFunction}(`$geometryColumn`, ST_GeomFromText(?, ?, 'axis-order=long-lat')) {$direction}", [
+ $geometry->toWkt(),
+ $geometry->getSrid(),
+ ]);
+
+ return $query;
+ }
+
+ public function scopeOrderByDistance($query, $geometryColumn, $geometry, $direction = 'asc')
+ {
+ return $this->scopeOrderBySpatial($query, $geometryColumn, $geometry, 'distance', $direction);
+ }
+
+ public function scopeOrderByDistanceSphere($query, $geometryColumn, $geometry, $direction = 'asc')
+ {
+ return $this->scopeOrderBySpatial($query, $geometryColumn, $geometry, 'distance_sphere', $direction);
+ }
}
diff --git a/src/Exceptions/UnknownSpatialFunctionException.php b/src/Exceptions/UnknownSpatialFunctionException.php
new file mode 100644
index 00000000..19f5b6e9
--- /dev/null
+++ b/src/Exceptions/UnknownSpatialFunctionException.php
@@ -0,0 +1,7 @@
+addColumn('geometry', $column);
+ return $this->addColumn('geometry', $column, compact('srid'));
}
/**
@@ -34,73 +35,79 @@ public function point($column, $srid = null)
/**
* Add a linestring column on the table.
*
- * @param $column
+ * @param string $column
+ * @param null|int $srid
*
* @return \Illuminate\Support\Fluent
*/
- public function lineString($column)
+ public function lineString($column, $srid = null)
{
- return $this->addColumn('linestring', $column);
+ return $this->addColumn('linestring', $column, compact('srid'));
}
/**
* Add a polygon column on the table.
*
- * @param $column
+ * @param string $column
+ * @param null|int $srid
*
* @return \Illuminate\Support\Fluent
*/
- public function polygon($column)
+ public function polygon($column, $srid = null)
{
- return $this->addColumn('polygon', $column);
+ return $this->addColumn('polygon', $column, compact('srid'));
}
/**
* Add a multipoint column on the table.
*
- * @param $column
+ * @param string $column
+ * @param null|int $srid
*
* @return \Illuminate\Support\Fluent
*/
- public function multiPoint($column)
+ public function multiPoint($column, $srid = null)
{
- return $this->addColumn('multipoint', $column);
+ return $this->addColumn('multipoint', $column, compact('srid'));
}
/**
* Add a multilinestring column on the table.
*
- * @param $column
+ * @param string $column
+ * @param null|int $srid
*
* @return \Illuminate\Support\Fluent
*/
- public function multiLineString($column)
+ public function multiLineString($column, $srid = null)
{
- return $this->addColumn('multilinestring', $column);
+ return $this->addColumn('multilinestring', $column, compact('srid'));
}
/**
* Add a multipolygon column on the table.
*
- * @param $column
+ * @param string $column
+ * @param null|int $srid
*
* @return \Illuminate\Support\Fluent
*/
- public function multiPolygon($column)
+ public function multiPolygon($column, $srid = null)
{
- return $this->addColumn('multipolygon', $column);
+ return $this->addColumn('multipolygon', $column, compact('srid'));
}
/**
* Add a geometrycollection column on the table.
*
- * @param $column
+ * @param string $column
+ * @param null|int $srid
*
* @return \Illuminate\Support\Fluent
*/
- public function geometryCollection($column)
+ public function geometryCollection($column, $srid = null)
{
- return $this->addColumn('geometrycollection', $column);
+ return $this->addColumn('geometrycollection', $column, compact('srid'));
}
/**
diff --git a/src/Schema/Grammars/MySqlGrammar.php b/src/Schema/Grammars/MySqlGrammar.php
index 61f015d1..9afe4513 100644
--- a/src/Schema/Grammars/MySqlGrammar.php
+++ b/src/Schema/Grammars/MySqlGrammar.php
@@ -8,10 +8,20 @@
class MySqlGrammar extends IlluminateMySqlGrammar
{
+ const COLUMN_MODIFIER_SRID = 'Srid';
+
+ public function __construct()
+ {
+ // Enable SRID as a column modifier
+ if (!in_array(self::COLUMN_MODIFIER_SRID, $this->modifiers)) {
+ $this->modifiers[] = self::COLUMN_MODIFIER_SRID;
+ }
+ }
+
/**
* Adds a statement to add a geometry column.
*
- * @param \Illuminate\Support\Fluent $column
+ * @param Fluent $column
*
* @return string
*/
@@ -23,7 +33,7 @@ public function typeGeometry(Fluent $column)
/**
* Adds a statement to add a point column.
*
- * @param \Illuminate\Support\Fluent $column
+ * @param Fluent $column
*
* @return string
*/
@@ -35,7 +45,7 @@ public function typePoint(Fluent $column)
/**
* Adds a statement to add a linestring column.
*
- * @param \Illuminate\Support\Fluent $column
+ * @param Fluent $column
*
* @return string
*/
@@ -47,7 +57,7 @@ public function typeLinestring(Fluent $column)
/**
* Adds a statement to add a polygon column.
*
- * @param \Illuminate\Support\Fluent $column
+ * @param Fluent $column
*
* @return string
*/
@@ -59,7 +69,7 @@ public function typePolygon(Fluent $column)
/**
* Adds a statement to add a multipoint column.
*
- * @param \Illuminate\Support\Fluent $column
+ * @param Fluent $column
*
* @return string
*/
@@ -71,7 +81,7 @@ public function typeMultipoint(Fluent $column)
/**
* Adds a statement to add a multilinestring column.
*
- * @param \Illuminate\Support\Fluent $column
+ * @param Fluent $column
*
* @return string
*/
@@ -83,7 +93,7 @@ public function typeMultilinestring(Fluent $column)
/**
* Adds a statement to add a multipolygon column.
*
- * @param \Illuminate\Support\Fluent $column
+ * @param Fluent $column
*
* @return string
*/
@@ -95,7 +105,7 @@ public function typeMultipolygon(Fluent $column)
/**
* Adds a statement to add a geometrycollection column.
*
- * @param \Illuminate\Support\Fluent $column
+ * @param Fluent $column
*
* @return string
*/
@@ -107,8 +117,8 @@ public function typeGeometrycollection(Fluent $column)
/**
* Compile a spatial index key command.
*
- * @param \Grimzy\LaravelMysqlSpatial\Schema\Blueprint $blueprint
- * @param \Illuminate\Support\Fluent $command
+ * @param Blueprint $blueprint
+ * @param Fluent $command
*
* @return string
*/
@@ -116,4 +126,19 @@ public function compileSpatial(Blueprint $blueprint, Fluent $command)
{
return $this->compileKey($blueprint, $command, 'spatial');
}
+
+ /**
+ * Get the SQL for a SRID column modifier.
+ *
+ * @param \Illuminate\Database\Schema\Blueprint $blueprint
+ * @param Fluent $column
+ *
+ * @return string|null
+ */
+ protected function modifySrid(\Illuminate\Database\Schema\Blueprint $blueprint, Fluent $column)
+ {
+ if (!is_null($column->srid) && is_int($column->srid) && $column->srid > 0) {
+ return ' srid '.$column->srid;
+ }
+ }
}
diff --git a/src/Types/Factory.php b/src/Types/Factory.php
index 087348fa..ed04ac2d 100755
--- a/src/Types/Factory.php
+++ b/src/Types/Factory.php
@@ -6,41 +6,41 @@ class Factory implements \GeoIO\Factory
{
public function createPoint($dimension, array $coordinates, $srid = null)
{
- return new Point($coordinates['y'], $coordinates['x']);
+ return new Point($coordinates['y'], $coordinates['x'], $srid);
}
public function createLineString($dimension, array $points, $srid = null)
{
- return new LineString($points);
+ return new LineString($points, $srid);
}
public function createLinearRing($dimension, array $points, $srid = null)
{
- return new LineString($points);
+ return new LineString($points, $srid);
}
public function createPolygon($dimension, array $lineStrings, $srid = null)
{
- return new Polygon($lineStrings);
+ return new Polygon($lineStrings, $srid);
}
public function createMultiPoint($dimension, array $points, $srid = null)
{
- return new MultiPoint($points);
+ return new MultiPoint($points, $srid);
}
public function createMultiLineString($dimension, array $lineStrings, $srid = null)
{
- return new MultiLineString($lineStrings);
+ return new MultiLineString($lineStrings, $srid);
}
public function createMultiPolygon($dimension, array $polygons, $srid = null)
{
- return new MultiPolygon($polygons);
+ return new MultiPolygon($polygons, $srid);
}
public function createGeometryCollection($dimension, array $geometries, $srid = null)
{
- return new GeometryCollection($geometries);
+ return new GeometryCollection($geometries, $srid);
}
}
diff --git a/src/Types/Geometry.php b/src/Types/Geometry.php
index a46baed3..f840874c 100644
--- a/src/Types/Geometry.php
+++ b/src/Types/Geometry.php
@@ -19,6 +19,23 @@ abstract class Geometry implements GeometryInterface, Jsonable, \JsonSerializabl
7 => GeometryCollection::class,
];
+ protected $srid;
+
+ public function __construct($srid = 0)
+ {
+ $this->srid = (int) $srid;
+ }
+
+ public function getSrid()
+ {
+ return $this->srid;
+ }
+
+ public function setSrid($srid)
+ {
+ $this->srid = (int) $srid;
+ }
+
public static function getWKTArgument($value)
{
$left = strpos($value, '(');
@@ -54,22 +71,27 @@ public static function getWKTClass($value)
public static function fromWKB($wkb)
{
- // mysql adds 4 NUL bytes at the start of the binary
- $prefix = "\0\0\0\0";
- if (substr($wkb, 0, strlen($prefix)) == $prefix) {
- $wkb = substr($wkb, strlen($prefix));
- }
+ $srid = substr($wkb, 0, 4);
+ $srid = unpack('L', $srid)[1];
+ $wkb = substr($wkb, 4);
$parser = new Parser(new Factory());
- return $parser->parse($wkb);
+ /** @var Geometry $parsed */
+ $parsed = $parser->parse($wkb);
+
+ if ($srid > 0) {
+ $parsed->setSrid($srid);
+ }
+
+ return $parsed;
}
- public static function fromWKT($wkt)
+ public static function fromWKT($wkt, $srid = null)
{
$wktArgument = static::getWKTArgument($wkt);
- return static::fromString($wktArgument);
+ return static::fromString($wktArgument, $srid);
}
public static function fromJson($geoJson)
diff --git a/src/Types/GeometryCollection.php b/src/Types/GeometryCollection.php
index 2e1f0321..35f093f7 100755
--- a/src/Types/GeometryCollection.php
+++ b/src/Types/GeometryCollection.php
@@ -14,6 +14,20 @@
class GeometryCollection extends Geometry implements IteratorAggregate, ArrayAccess, Arrayable, Countable
{
+ /**
+ * The minimum number of items required to create this collection.
+ *
+ * @var int
+ */
+ protected $minimumCollectionItems = 0;
+
+ /**
+ * The class of the items in the collection.
+ *
+ * @var string
+ */
+ protected $collectionItemType = GeometryInterface::class;
+
/**
* The items contained in the spatial collection.
*
@@ -23,18 +37,15 @@ class GeometryCollection extends Geometry implements IteratorAggregate, ArrayAcc
/**
* @param GeometryInterface[] $geometries
+ * @param int $srid
*
* @throws InvalidArgumentException
*/
- public function __construct(array $geometries)
+ public function __construct(array $geometries, $srid = 0)
{
- $validated = array_filter($geometries, function ($value) {
- return $value instanceof GeometryInterface;
- });
+ parent::__construct($srid);
- if (count($geometries) !== count($validated)) {
- throw new InvalidArgumentException('$geometries must be an array of Geometry objects');
- }
+ $this->validateItems($geometries);
$this->items = $geometries;
}
@@ -56,15 +67,19 @@ public function __toString()
}, $this->items));
}
- public static function fromString($wktArgument)
+ public static function fromString($wktArgument, $srid = 0)
{
+ if (empty($wktArgument)) {
+ return new static([]);
+ }
+
$geometry_strings = preg_split('/,\s*(?=[A-Za-z])/', $wktArgument);
return new static(array_map(function ($geometry_string) {
$klass = Geometry::getWKTClass($geometry_string);
return call_user_func($klass.'::fromWKT', $geometry_string);
- }, $geometry_strings));
+ }, $geometry_strings), $srid);
}
public function toArray()
@@ -89,9 +104,7 @@ public function offsetGet($offset)
public function offsetSet($offset, $value)
{
- if (!($value instanceof GeometryInterface)) {
- throw new InvalidArgumentException('$value must be an instance of GeometryInterface');
- }
+ $this->validateItemType($value);
if (is_null($offset)) {
$this->items[] = $value;
@@ -142,4 +155,57 @@ public function jsonSerialize()
return new \GeoJson\Geometry\GeometryCollection($geometries);
}
+
+ /**
+ * Checks whether the items are valid to create this collection.
+ *
+ * @param array $items
+ */
+ protected function validateItems(array $items)
+ {
+ $this->validateItemCount($items);
+
+ foreach ($items as $item) {
+ $this->validateItemType($item);
+ }
+ }
+
+ /**
+ * Checks whether the array has enough items to generate a valid WKT.
+ *
+ * @param array $items
+ *
+ * @see $minimumCollectionItems
+ */
+ protected function validateItemCount(array $items)
+ {
+ if (count($items) < $this->minimumCollectionItems) {
+ $entries = $this->minimumCollectionItems === 1 ? 'entry' : 'entries';
+
+ throw new InvalidArgumentException(sprintf(
+ '%s must contain at least %d %s',
+ get_class($this),
+ $this->minimumCollectionItems,
+ $entries
+ ));
+ }
+ }
+
+ /**
+ * Checks the type of the items in the array.
+ *
+ * @param $item
+ *
+ * @see $collectionItemType
+ */
+ protected function validateItemType($item)
+ {
+ if (!$item instanceof $this->collectionItemType) {
+ throw new InvalidArgumentException(sprintf(
+ '%s must be a collection of %s',
+ get_class($this),
+ $this->collectionItemType
+ ));
+ }
+ }
}
diff --git a/src/Types/GeometryInterface.php b/src/Types/GeometryInterface.php
index aca2bfb0..4f0dd1ef 100644
--- a/src/Types/GeometryInterface.php
+++ b/src/Types/GeometryInterface.php
@@ -6,11 +6,11 @@ interface GeometryInterface
{
public function toWKT();
- public static function fromWKT($wkt);
+ public static function fromWKT($wkt, $srid = 0);
public function __toString();
- public static function fromString($wktArgument);
+ public static function fromString($wktArgument, $srid = 0);
public static function fromJson($geoJson);
}
diff --git a/src/Types/LineString.php b/src/Types/LineString.php
index 02097edd..1cc4a410 100644
--- a/src/Types/LineString.php
+++ b/src/Types/LineString.php
@@ -8,26 +8,33 @@
class LineString extends PointCollection
{
+ /**
+ * The minimum number of items required to create this collection.
+ *
+ * @var int
+ */
+ protected $minimumCollectionItems = 2;
+
public function toWKT()
{
return sprintf('LINESTRING(%s)', $this->toPairList());
}
- public static function fromWkt($wkt)
+ public static function fromWkt($wkt, $srid = 0)
{
$wktArgument = Geometry::getWKTArgument($wkt);
- return static::fromString($wktArgument);
+ return static::fromString($wktArgument, $srid);
}
- public static function fromString($wktArgument)
+ public static function fromString($wktArgument, $srid = 0)
{
$pairs = explode(',', trim($wktArgument));
$points = array_map(function ($pair) {
return Point::fromPair($pair);
}, $pairs);
- return new static($points);
+ return new static($points, $srid);
}
public function __toString()
diff --git a/src/Types/MultiLineString.php b/src/Types/MultiLineString.php
index dd3342fd..62c4d576 100644
--- a/src/Types/MultiLineString.php
+++ b/src/Types/MultiLineString.php
@@ -5,29 +5,22 @@
use GeoJson\GeoJson;
use GeoJson\Geometry\MultiLineString as GeoJsonMultiLineString;
use Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException;
-use InvalidArgumentException;
class MultiLineString extends GeometryCollection
{
/**
- * @param LineString[] $lineStrings
+ * The minimum number of items required to create this collection.
+ *
+ * @var int
*/
- public function __construct(array $lineStrings)
- {
- if (count($lineStrings) < 1) {
- throw new InvalidArgumentException('$lineStrings must contain at least one entry');
- }
-
- $validated = array_filter($lineStrings, function ($value) {
- return $value instanceof LineString;
- });
-
- if (count($lineStrings) !== count($validated)) {
- throw new InvalidArgumentException('$lineStrings must be an array of LineString');
- }
+ protected $minimumCollectionItems = 1;
- parent::__construct($lineStrings);
- }
+ /**
+ * The class of the items in the collection.
+ *
+ * @var string
+ */
+ protected $collectionItemType = LineString::class;
public function getLineStrings()
{
@@ -39,14 +32,14 @@ public function toWKT()
return sprintf('MULTILINESTRING(%s)', (string) $this);
}
- public static function fromString($wktArgument)
+ public static function fromString($wktArgument, $srid = 0)
{
$str = preg_split('/\)\s*,\s*\(/', substr(trim($wktArgument), 1, -1));
$lineStrings = array_map(function ($data) {
return LineString::fromString($data);
}, $str);
- return new static($lineStrings);
+ return new static($lineStrings, $srid);
}
public function __toString()
@@ -58,9 +51,7 @@ public function __toString()
public function offsetSet($offset, $value)
{
- if (!($value instanceof LineString)) {
- throw new InvalidArgumentException('$value must be an instance of LineString');
- }
+ $this->validateItemType($value);
parent::offsetSet($offset, $value);
}
diff --git a/src/Types/MultiPoint.php b/src/Types/MultiPoint.php
index fb55f9e8..752967eb 100644
--- a/src/Types/MultiPoint.php
+++ b/src/Types/MultiPoint.php
@@ -8,19 +8,26 @@
class MultiPoint extends PointCollection
{
+ /**
+ * The minimum number of items required to create this collection.
+ *
+ * @var int
+ */
+ protected $minimumCollectionItems = 1;
+
public function toWKT()
{
return sprintf('MULTIPOINT(%s)', (string) $this);
}
- public static function fromWkt($wkt)
+ public static function fromWkt($wkt, $srid = 0)
{
$wktArgument = Geometry::getWKTArgument($wkt);
- return static::fromString($wktArgument);
+ return static::fromString($wktArgument, $srid);
}
- public static function fromString($wktArgument)
+ public static function fromString($wktArgument, $srid = 0)
{
$matches = [];
preg_match_all('/\(\s*(\d+\s+\d+)\s*\)/', trim($wktArgument), $matches);
@@ -29,7 +36,7 @@ public static function fromString($wktArgument)
return Point::fromPair($pair);
}, $matches[1]);
- return new static($points);
+ return new static($points, $srid);
}
public function __toString()
diff --git a/src/Types/MultiPolygon.php b/src/Types/MultiPolygon.php
index aba2b6d1..cdea3a9c 100644
--- a/src/Types/MultiPolygon.php
+++ b/src/Types/MultiPolygon.php
@@ -5,24 +5,22 @@
use GeoJson\GeoJson;
use GeoJson\Geometry\MultiPolygon as GeoJsonMultiPolygon;
use Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException;
-use InvalidArgumentException;
class MultiPolygon extends GeometryCollection
{
/**
- * @param Polygon[] $polygons
+ * The minimum number of items required to create this collection.
+ *
+ * @var int
*/
- public function __construct(array $polygons)
- {
- $validated = array_filter($polygons, function ($value) {
- return $value instanceof Polygon;
- });
+ protected $minimumCollectionItems = 1;
- if (count($polygons) !== count($validated)) {
- throw new InvalidArgumentException('$polygons must be an array of Polygon');
- }
- parent::__construct($polygons);
- }
+ /**
+ * The class of the items in the collection.
+ *
+ * @var string
+ */
+ protected $collectionItemType = Polygon::class;
public function toWKT()
{
@@ -36,14 +34,14 @@ public function __toString()
}, $this->items));
}
- public static function fromString($wktArgument)
+ public static function fromString($wktArgument, $srid = 0)
{
$parts = preg_split('/(\)\s*\)\s*,\s*\(\s*\()/', $wktArgument, -1, PREG_SPLIT_DELIM_CAPTURE);
$polygons = static::assembleParts($parts);
return new static(array_map(function ($polygonString) {
return Polygon::fromString($polygonString);
- }, $polygons));
+ }, $polygons), $srid);
}
/**
@@ -93,9 +91,7 @@ protected static function assembleParts(array $parts)
public function offsetSet($offset, $value)
{
- if (!($value instanceof Polygon)) {
- throw new InvalidArgumentException('$value must be an instance of Polygon');
- }
+ $this->validateItemType($value);
parent::offsetSet($offset, $value);
}
diff --git a/src/Types/Point.php b/src/Types/Point.php
index 40719af4..d424ec5e 100644
--- a/src/Types/Point.php
+++ b/src/Types/Point.php
@@ -12,8 +12,10 @@ class Point extends Geometry
protected $lng;
- public function __construct($lat, $lng)
+ public function __construct($lat, $lng, $srid = 0)
{
+ parent::__construct($srid);
+
$this->lat = (float) $lat;
$this->lng = (float) $lng;
}
@@ -43,11 +45,11 @@ public function toPair()
return $this->getLng().' '.$this->getLat();
}
- public static function fromPair($pair)
+ public static function fromPair($pair, $srid = 0)
{
list($lng, $lat) = explode(' ', trim($pair, "\t\n\r \x0B()"));
- return new static((float) $lat, (float) $lng);
+ return new static((float) $lat, (float) $lng, (int) $srid);
}
public function toWKT()
@@ -55,9 +57,9 @@ public function toWKT()
return sprintf('POINT(%s)', (string) $this);
}
- public static function fromString($wktArgument)
+ public static function fromString($wktArgument, $srid = 0)
{
- return static::fromPair($wktArgument);
+ return static::fromPair($wktArgument, $srid);
}
public function __toString()
diff --git a/src/Types/PointCollection.php b/src/Types/PointCollection.php
index af586b28..30d1b8de 100755
--- a/src/Types/PointCollection.php
+++ b/src/Types/PointCollection.php
@@ -8,24 +8,11 @@
abstract class PointCollection extends GeometryCollection
{
/**
- * @param Point[] $points
+ * The class of the items in the collection.
+ *
+ * @var string
*/
- public function __construct(array $points)
- {
- if (count($points) < 2) {
- throw new InvalidArgumentException('$points must contain at least two entries');
- }
-
- $validated = array_filter($points, function ($value) {
- return $value instanceof Point;
- });
-
- if (count($points) !== count($validated)) {
- throw new InvalidArgumentException('$points must be an array of Points');
- }
-
- parent::__construct($points);
- }
+ protected $collectionItemType = Point::class;
public function toPairList()
{
@@ -36,9 +23,7 @@ public function toPairList()
public function offsetSet($offset, $value)
{
- if (!($value instanceof Point)) {
- throw new InvalidArgumentException('$value must be an instance of Point');
- }
+ $this->validateItemType($value);
parent::offsetSet($offset, $value);
}
diff --git a/tests/Integration/IntegrationBaseTestCase.php b/tests/Integration/IntegrationBaseTestCase.php
new file mode 100644
index 00000000..04634734
--- /dev/null
+++ b/tests/Integration/IntegrationBaseTestCase.php
@@ -0,0 +1,110 @@
+register(SpatialServiceProvider::class);
+
+ $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
+
+ $app['config']->set('database.default', 'mysql');
+ $app['config']->set('database.connections.mysql.host', env('DB_HOST'));
+ $app['config']->set('database.connections.mysql.port', env('DB_PORT'));
+ $app['config']->set('database.connections.mysql.database', env('DB_DATABASE'));
+ $app['config']->set('database.connections.mysql.username', env('DB_USERNAME'));
+ $app['config']->set('database.connections.mysql.password', env('DB_PASSWORD'));
+ $app['config']->set('database.connections.mysql.modes', [
+ 'ONLY_FULL_GROUP_BY',
+ 'STRICT_TRANS_TABLES',
+ 'NO_ZERO_IN_DATE',
+ 'NO_ZERO_DATE',
+ 'ERROR_FOR_DIVISION_BY_ZERO',
+ 'NO_ENGINE_SUBSTITUTION',
+ ]);
+
+ return $app;
+ }
+
+ /**
+ * Setup DB before each test.
+ *
+ * @return void
+ */
+ public function setUp()
+ {
+ parent::setUp();
+
+ $this->after_fix = $this->isMySQL8AfterFix();
+
+ $this->onMigrations(function ($migrationClass) {
+ (new $migrationClass())->up();
+ });
+
+ //\DB::listen(function($sql) {
+ // var_dump($sql);
+ //});
+ }
+
+ public function tearDown()
+ {
+ $this->onMigrations(function ($migrationClass) {
+ (new $migrationClass())->down();
+ }, true);
+
+ parent::tearDown();
+ }
+
+ // MySQL 8.0.4 fixed bug #26941370 and bug #88031
+ private function isMySQL8AfterFix()
+ {
+ $results = DB::select(DB::raw('select version()'));
+ $mysql_version = $results[0]->{'version()'};
+
+ return version_compare($mysql_version, '8.0.4', '>=');
+ }
+
+ protected function assertDatabaseHas($table, array $data, $connection = null)
+ {
+ if (method_exists($this, 'seeInDatabase')) {
+ $this->seeInDatabase($table, $data, $connection);
+ } else {
+ parent::assertDatabaseHas($table, $data, $connection);
+ }
+ }
+
+ protected function assertException($exceptionName, $exceptionMessage = null)
+ {
+ if (method_exists(parent::class, 'expectException')) {
+ parent::expectException($exceptionName);
+ if (!is_null($exceptionMessage)) {
+ $this->expectExceptionMessage($exceptionMessage);
+ }
+ } else {
+ $this->setExpectedException($exceptionName, $exceptionMessage);
+ }
+ }
+
+ private function onMigrations(\Closure $closure, $reverse_sort = false)
+ {
+ $migrations = $this->migrations;
+ $reverse_sort ? rsort($migrations, SORT_STRING) : sort($migrations, SORT_STRING);
+
+ foreach ($migrations as $migrationClass) {
+ $closure($migrationClass);
+ }
+ }
+}
diff --git a/tests/Integration/MigrationTest.php b/tests/Integration/MigrationTest.php
new file mode 100644
index 00000000..6b740d0f
--- /dev/null
+++ b/tests/Integration/MigrationTest.php
@@ -0,0 +1,56 @@
+assertEquals('geometry', $result->Table);
+ $this->assertEquals($expected, $result->{'Create Table'});
+ }
+
+ public function testTableWasCreatedWithSrid()
+ {
+ $result = DB::selectOne('SHOW CREATE TABLE with_srid');
+
+ $expected = 'CREATE TABLE `with_srid` (
+ `id` int unsigned NOT NULL AUTO_INCREMENT,
+ `geo` geometry /*!80003 SRID 3857 */ DEFAULT NULL,
+ `location` point /*!80003 SRID 3857 */ DEFAULT NULL,
+ `line` linestring /*!80003 SRID 3857 */ DEFAULT NULL,
+ `shape` polygon /*!80003 SRID 3857 */ DEFAULT NULL,
+ `multi_locations` multipoint /*!80003 SRID 3857 */ DEFAULT NULL,
+ `multi_lines` multilinestring /*!80003 SRID 3857 */ DEFAULT NULL,
+ `multi_shapes` multipolygon /*!80003 SRID 3857 */ DEFAULT NULL,
+ `multi_geometries` geomcollection /*!80003 SRID 3857 */ DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci';
+
+ $this->assertEquals('with_srid', $result->Table);
+ $this->assertEquals($expected, $result->{'Create Table'});
+ }
+}
diff --git a/tests/Integration/Migrations/CreateTables.php b/tests/Integration/Migrations/CreateTables.php
index 93f08704..fdff4f58 100644
--- a/tests/Integration/Migrations/CreateTables.php
+++ b/tests/Integration/Migrations/CreateTables.php
@@ -1,7 +1,7 @@
charset = 'utf8mb4';
+ $table->collation = 'utf8mb4_unicode_ci';
$table->increments('id');
$table->geometry('geo')->default(null)->nullable();
$table->point('location'); // required to be not null in order to add an index
@@ -30,6 +32,20 @@ public function up()
$table->increments('id');
$table->geometry('geometry')->default(null)->nullable();
});
+
+ Schema::create('with_srid', function (Blueprint $table) {
+ $table->charset = 'utf8mb4';
+ $table->collation = 'utf8mb4_unicode_ci';
+ $table->increments('id');
+ $table->geometry('geo', 3857)->default(null)->nullable();
+ $table->point('location', 3857)->default(null)->nullable();
+ $table->lineString('line', 3857)->default(null)->nullable();
+ $table->polygon('shape', 3857)->default(null)->nullable();
+ $table->multiPoint('multi_locations', 3857)->default(null)->nullable();
+ $table->multiLineString('multi_lines', 3857)->default(null)->nullable();
+ $table->multiPolygon('multi_shapes', 3857)->default(null)->nullable();
+ $table->geometryCollection('multi_geometries', 3857)->default(null)->nullable();
+ });
}
/**
@@ -41,5 +57,6 @@ public function down()
{
Schema::drop('geometry');
Schema::drop('no_spatial_fields');
+ Schema::drop('with_srid');
}
}
diff --git a/tests/Integration/Migrations/UpdateTables.php b/tests/Integration/Migrations/UpdateTables.php
index 46ebaccc..83915b81 100644
--- a/tests/Integration/Migrations/UpdateTables.php
+++ b/tests/Integration/Migrations/UpdateTables.php
@@ -1,7 +1,7 @@
register(SpatialServiceProvider::class);
-
- $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
-
- $app['config']->set('database.default', 'mysql');
- $app['config']->set('database.connections.mysql.host', env('DB_HOST', '127.0.0.1'));
- $app['config']->set('database.connections.mysql.database', 'spatial_test');
- $app['config']->set('database.connections.mysql.username', 'root');
- $app['config']->set('database.connections.mysql.password', '');
- $app['config']->set('database.connections.mysql.modes', [
- 'ONLY_FULL_GROUP_BY',
- 'STRICT_TRANS_TABLES',
- 'NO_ZERO_IN_DATE',
- 'NO_ZERO_DATE',
- 'ERROR_FOR_DIVISION_BY_ZERO',
- 'NO_ENGINE_SUBSTITUTION',
- ]);
-
- return $app;
- }
-
- /**
- * Setup DB before each test.
- *
- * @return void
- */
- public function setUp()
- {
- parent::setUp();
-
- $this->after_fix = $this->isMySQL8AfterFix();
-
- $this->onMigrations(function ($migrationClass) {
- (new $migrationClass())->up();
- });
-
- //\DB::listen(function($sql) {
- // var_dump($sql);
- //});
- }
-
- public function tearDown()
- {
- $this->onMigrations(function ($migrationClass) {
- (new $migrationClass())->down();
- }, true);
-
- parent::tearDown();
- }
-
- // MySQL 8.0.4 fixed bug #26941370 and bug #88031
- private function isMySQL8AfterFix()
- {
- $results = DB::select(DB::raw('select version()'));
- $mysql_version = $results[0]->{'version()'};
-
- return version_compare($mysql_version, '8.0.4', '>=');
- }
-
- protected function assertDatabaseHas($table, array $data, $connection = null)
- {
- if (method_exists($this, 'seeInDatabase')) {
- $this->seeInDatabase($table, $data, $connection);
- } else {
- parent::assertDatabaseHas($table, $data, $connection);
- }
- }
-
- protected function assertException($exceptionName)
- {
- if (method_exists(parent::class, 'expectException')) {
- parent::expectException($exceptionName);
- } else {
- $this->setExpectedException($exceptionName);
- }
- }
-
- private function onMigrations(\Closure $closure, $reverse_sort = false)
- {
- $fileSystem = new Filesystem();
- $classFinder = new Tools\ClassFinder();
-
- $migrations = $fileSystem->files(__DIR__.'/Migrations');
- $reverse_sort ? rsort($migrations, SORT_STRING) : sort($migrations, SORT_STRING);
-
- foreach ($migrations as $file) {
- $fileSystem->requireOnce($file);
- $migrationClass = $classFinder->findClass($file);
-
- $closure($migrationClass);
- }
- }
+ protected $migrations = [
+ CreateLocationTable::class,
+ UpdateLocationTable::class,
+ ];
public function testSpatialFieldsNotDefinedException()
{
@@ -193,6 +91,21 @@ public function testInsertGeometryCollection()
$this->assertDatabaseHas('geometry', ['id' => $geo->id]);
}
+ public function testInsertEmptyGeometryCollection()
+ {
+ $geo = new GeometryModel();
+
+ $geo->location = new Point(1, 2);
+
+ $geo->multi_geometries = new GeometryCollection([]);
+ $geo->save();
+ $this->assertDatabaseHas('geometry', ['id' => $geo->id]);
+
+ $geo2 = GeometryModel::find($geo->id);
+ $this->assertInstanceOf(GeometryCollection::class, $geo2->multi_geometries);
+ $this->assertEquals(0, count($geo2->multi_geometries));
+ }
+
public function testUpdate()
{
$geo = new GeometryModel();
@@ -323,6 +236,82 @@ public function testDistanceSphereValue()
}
}
+ public function testOrderBySpatialWithUnknownFunction()
+ {
+ $loc = new GeometryModel();
+ $loc->location = new Point(1, 1);
+
+ $this->assertException(\Grimzy\LaravelMysqlSpatial\Exceptions\UnknownSpatialFunctionException::class);
+ GeometryModel::orderBySpatial('location', $loc->location, 'does-not-exist')->get();
+ }
+
+ public function testOrderByDistance()
+ {
+ $loc2 = new GeometryModel();
+ $loc2->location = new Point(2, 2); // Distance from loc1: 1.4142135623731
+ $loc2->save();
+
+ $loc1 = new GeometryModel();
+ $loc1->location = new Point(1, 1);
+ $loc1->save();
+
+ $loc3 = new GeometryModel();
+ $loc3->location = new Point(3, 3); // Distance from loc1: 2.8284271247462
+ $loc3->save();
+
+ $a = GeometryModel::orderByDistance('location', $loc1->location)->get();
+ $this->assertCount(3, $a);
+ $this->assertEquals($loc1->location, $a[0]->location);
+ $this->assertEquals($loc2->location, $a[1]->location);
+ $this->assertEquals($loc3->location, $a[2]->location);
+
+ // Excluding self
+ $b = GeometryModel::orderByDistance('location', $loc1->location, 'asc')->get();
+ $this->assertCount(3, $b);
+ $this->assertEquals($loc1->location, $b[0]->location);
+ $this->assertEquals($loc2->location, $b[1]->location);
+ $this->assertEquals($loc3->location, $b[2]->location);
+
+ $c = GeometryModel::orderByDistance('location', $loc1->location, 'desc')->get();
+ $this->assertCount(3, $c);
+ $this->assertEquals($loc3->location, $c[0]->location);
+ $this->assertEquals($loc2->location, $c[1]->location);
+ $this->assertEquals($loc1->location, $c[2]->location);
+ }
+
+ public function testOrderByDistanceSphere()
+ {
+ $loc2 = new GeometryModel();
+ $loc2->location = new Point(40.767664, -73.971271); // Distance from loc1: 44.741406484588
+ $loc2->save();
+
+ $loc1 = new GeometryModel();
+ $loc1->location = new Point(40.767864, -73.971732);
+ $loc1->save();
+
+ $loc3 = new GeometryModel();
+ $loc3->location = new Point(40.761434, -73.977619); // Distance from loc1: 870.06424066202
+ $loc3->save();
+
+ $a = GeometryModel::orderByDistanceSphere('location', $loc1->location)->get();
+ $this->assertCount(3, $a);
+ $this->assertEquals($loc1->location, $a[0]->location);
+ $this->assertEquals($loc2->location, $a[1]->location);
+ $this->assertEquals($loc3->location, $a[2]->location);
+
+ $b = GeometryModel::orderByDistanceSphere('location', $loc1->location, 'asc')->get();
+ $this->assertCount(3, $b);
+ $this->assertEquals($loc1->location, $b[0]->location);
+ $this->assertEquals($loc2->location, $b[1]->location);
+ $this->assertEquals($loc3->location, $b[2]->location);
+
+ $c = GeometryModel::orderByDistanceSphere('location', $loc1->location, 'desc')->get();
+ $this->assertCount(3, $c);
+ $this->assertEquals($loc3->location, $c[0]->location);
+ $this->assertEquals($loc2->location, $c[1]->location);
+ $this->assertEquals($loc1->location, $c[2]->location);
+ }
+
//public function testBounding() {
// $point = new Point(0, 0);
//
diff --git a/tests/Integration/SridSpatialTest.php b/tests/Integration/SridSpatialTest.php
new file mode 100644
index 00000000..f57c6cb2
--- /dev/null
+++ b/tests/Integration/SridSpatialTest.php
@@ -0,0 +1,136 @@
+location = new Point(1, 2, 3857);
+ $geo->save();
+ $this->assertDatabaseHas('with_srid', ['id' => $geo->id]);
+ }
+
+ public function testInsertLineStringWithSrid()
+ {
+ $geo = new WithSridModel();
+
+ $geo->location = new Point(1, 2, 3857);
+ $geo->line = new LineString([new Point(1, 1), new Point(2, 2)], 3857);
+ $geo->save();
+ $this->assertDatabaseHas('with_srid', ['id' => $geo->id]);
+ }
+
+ public function testInsertPolygonWithSrid()
+ {
+ $geo = new WithSridModel();
+
+ $geo->location = new Point(1, 2, 3857);
+ $geo->shape = Polygon::fromWKT('POLYGON((0 10,10 10,10 0,0 0,0 10))', 3857);
+ $geo->save();
+ $this->assertDatabaseHas('with_srid', ['id' => $geo->id]);
+ }
+
+ public function testInsertMultiPointWithSrid()
+ {
+ $geo = new WithSridModel();
+
+ $geo->location = new Point(1, 2, 3857);
+ $geo->multi_locations = new MultiPoint([new Point(1, 1), new Point(2, 2)], 3857);
+ $geo->save();
+ $this->assertDatabaseHas('with_srid', ['id' => $geo->id]);
+ }
+
+ public function testInsertMultiPolygonWithSrid()
+ {
+ $geo = new WithSridModel();
+
+ $geo->location = new Point(1, 2, 3857);
+
+ $geo->multi_shapes = new MultiPolygon([
+ Polygon::fromWKT('POLYGON((0 10,10 10,10 0,0 0,0 10))'),
+ Polygon::fromWKT('POLYGON((0 0,0 5,5 5,5 0,0 0))'),
+ ], 3857);
+ $geo->save();
+ $this->assertDatabaseHas('with_srid', ['id' => $geo->id]);
+ }
+
+ public function testInsertGeometryCollectionWithSrid()
+ {
+ $geo = new WithSridModel();
+
+ $geo->location = new Point(1, 2, 3857);
+
+ $geo->multi_geometries = new GeometryCollection([
+ Polygon::fromWKT('POLYGON((0 10,10 10,10 0,0 0,0 10))'),
+ Polygon::fromWKT('POLYGON((0 0,0 5,5 5,5 0,0 0))'),
+ new Point(0, 0),
+ ], 3857);
+ $geo->save();
+ $this->assertDatabaseHas('with_srid', ['id' => $geo->id]);
+ }
+
+ public function testUpdateWithSrid()
+ {
+ $geo = new WithSridModel();
+ $geo->location = new Point(1, 2, 3857);
+ $geo->save();
+
+ $to_update = WithSridModel::all()->first();
+ $to_update->location = new Point(2, 3, 3857);
+ $to_update->save();
+
+ $this->assertDatabaseHas('with_srid', ['id' => $to_update->id]);
+
+ $all = WithSridModel::all();
+ $this->assertCount(1, $all);
+
+ $updated = $all->first();
+ $this->assertInstanceOf(Point::class, $updated->location);
+ $this->assertEquals(2, $updated->location->getLat());
+ $this->assertEquals(3, $updated->location->getLng());
+ }
+
+ public function testInsertPointWithWrongSrid()
+ {
+ $geo = new WithSridModel();
+ $geo->location = new Point(1, 2);
+
+ $this->assertException(
+ Illuminate\Database\QueryException::class,
+ 'SQLSTATE[HY000]: General error: 3643 The SRID of the geometry '.
+ 'does not match the SRID of the column \'location\'. The SRID '.
+ 'of the geometry is 0, but the SRID of the column is 3857. '.
+ 'Consider changing the SRID of the geometry or the SRID property '.
+ 'of the column. (SQL: insert into `with_srid` (`location`) values '.
+ '(ST_GeomFromText(POINT(2 1), 0, \'axis-order=long-lat\')))'
+ );
+ $geo->save();
+ }
+
+ public function testGeometryInsertedHasRightSrid()
+ {
+ $geo = new WithSridModel();
+ $geo->location = new Point(1, 2, 3857);
+ $geo->save();
+
+ $srid = \DB::selectOne('select ST_SRID(location) as srid from with_srid');
+ $this->assertEquals(3857, $srid->srid);
+
+ $result = WithSridModel::first();
+
+ $this->assertEquals($geo->location->getSrid(), $result->location->getSrid());
+ $a = 1;
+ }
+}
diff --git a/tests/Integration/Tools/ClassFinder.php b/tests/Integration/Tools/ClassFinder.php
deleted file mode 100644
index 13a8263b..00000000
--- a/tests/Integration/Tools/ClassFinder.php
+++ /dev/null
@@ -1,154 +0,0 @@
-in($directory)->name('*.php') as $file) {
- $classes[] = $this->findClass($file->getRealPath());
- }
-
- return array_filter($classes);
- }
-
- /**
- * Extract the class name from the file at the given path.
- *
- * @param string $path
- *
- * @return string|null
- */
- public function findClass($path)
- {
- $namespace = null;
-
- $tokens = token_get_all(file_get_contents($path));
-
- foreach ($tokens as $key => $token) {
- if ($this->tokenIsNamespace($token)) {
- $namespace = $this->getNamespace($key + 2, $tokens);
- } elseif ($this->tokenIsClassOrInterface($token)) {
- return ltrim($namespace.'\\'.$this->getClass($key + 2, $tokens), '\\');
- }
- }
- }
-
- /**
- * Find the namespace in the tokens starting at a given key.
- *
- * @param int $key
- * @param array $tokens
- *
- * @return string
- */
- protected function getNamespace($key, array $tokens)
- {
- $namespace = null;
-
- $tokenCount = count($tokens);
-
- for ($i = $key; $i < $tokenCount; $i++) {
- if ($this->isPartOfNamespace($tokens[$i])) {
- $namespace .= $tokens[$i][1];
- } elseif ($tokens[$i] == ';') {
- return $namespace;
- }
- }
- }
-
- /**
- * Find the class in the tokens starting at a given key.
- *
- * @param int $key
- * @param array $tokens
- *
- * @return string
- */
- protected function getClass($key, array $tokens)
- {
- $class = null;
-
- $tokenCount = count($tokens);
-
- for ($i = $key; $i < $tokenCount; $i++) {
- if ($this->isPartOfClass($tokens[$i])) {
- $class .= $tokens[$i][1];
- } elseif ($this->isWhitespace($tokens[$i])) {
- return $class;
- }
- }
- }
-
- /**
- * Determine if the given token is a namespace keyword.
- *
- * @param array|string $token
- *
- * @return bool
- */
- protected function tokenIsNamespace($token)
- {
- return is_array($token) && $token[0] == T_NAMESPACE;
- }
-
- /**
- * Determine if the given token is a class or interface keyword.
- *
- * @param array|string $token
- *
- * @return bool
- */
- protected function tokenIsClassOrInterface($token)
- {
- return is_array($token) && ($token[0] == T_CLASS || $token[0] == T_INTERFACE);
- }
-
- /**
- * Determine if the given token is part of the namespace.
- *
- * @param array|string $token
- *
- * @return bool
- */
- protected function isPartOfNamespace($token)
- {
- return is_array($token) && ($token[0] == T_STRING || $token[0] == T_NS_SEPARATOR);
- }
-
- /**
- * Determine if the given token is part of the class.
- *
- * @param array|string $token
- *
- * @return bool
- */
- protected function isPartOfClass($token)
- {
- return is_array($token) && $token[0] == T_STRING;
- }
-
- /**
- * Determine if the given token is whitespace.
- *
- * @param array|string $token
- *
- * @return bool
- */
- protected function isWhitespace($token)
- {
- return is_array($token) && $token[0] == T_WHITESPACE;
- }
-}
diff --git a/tests/Unit/BaseTestCase.php b/tests/Unit/BaseTestCase.php
index 44f323c5..219f737d 100644
--- a/tests/Unit/BaseTestCase.php
+++ b/tests/Unit/BaseTestCase.php
@@ -1,18 +1,22 @@
setExpectedException($exceptionName);
+ $this->setExpectedException($exceptionName, $exceptionMessage, $exceptionCode);
}
}
}
diff --git a/tests/Unit/Eloquent/BuilderTest.php b/tests/Unit/Eloquent/BuilderTest.php
index b77c6c4e..d9a12a55 100644
--- a/tests/Unit/Eloquent/BuilderTest.php
+++ b/tests/Unit/Eloquent/BuilderTest.php
@@ -41,9 +41,12 @@ public function testUpdatePoint()
$this->queryBuilder
->shouldReceive('update')
->with(['point' => new SpatialExpression($point)])
- ->once();
+ ->once()
+ ->andReturn(1);
+
+ $result = $this->builder->update(['point' => $point]);
- $this->builder->update(['point' => $point]);
+ $this->assertSame(1, $result);
}
public function testUpdateLinestring()
@@ -53,9 +56,12 @@ public function testUpdateLinestring()
$this->queryBuilder
->shouldReceive('update')
->with(['linestring' => new SpatialExpression($linestring)])
- ->once();
+ ->once()
+ ->andReturn(1);
- $this->builder->update(['linestring' => $linestring]);
+ $result = $this->builder->update(['linestring' => $linestring]);
+
+ $this->assertSame(1, $result);
}
public function testUpdatePolygon()
@@ -68,9 +74,59 @@ public function testUpdatePolygon()
$this->queryBuilder
->shouldReceive('update')
->with(['polygon' => new SpatialExpression($polygon)])
- ->once();
+ ->once()
+ ->andReturn(1);
+
+ $result = $this->builder->update(['polygon' => $polygon]);
+
+ $this->assertSame(1, $result);
+ }
+
+ public function testUpdatePointWithSrid()
+ {
+ $point = new Point(1, 2, 4326);
+ $this->queryBuilder
+ ->shouldReceive('update')
+ ->with(['point' => new SpatialExpression($point)])
+ ->once()
+ ->andReturn(1);
+
+ $result = $this->builder->update(['point' => $point]);
+
+ $this->assertSame(1, $result);
+ }
+
+ public function testUpdateLinestringWithSrid()
+ {
+ $linestring = new LineString([new Point(0, 0), new Point(1, 1), new Point(2, 2)], 4326);
+
+ $this->queryBuilder
+ ->shouldReceive('update')
+ ->with(['linestring' => new SpatialExpression($linestring)])
+ ->once()
+ ->andReturn(1);
+
+ $result = $this->builder->update(['linestring' => $linestring]);
+
+ $this->assertSame(1, $result);
+ }
+
+ public function testUpdatePolygonWithSrid()
+ {
+ $linestrings[] = new LineString([new Point(0, 0), new Point(0, 1)]);
+ $linestrings[] = new LineString([new Point(0, 1), new Point(1, 1)]);
+ $linestrings[] = new LineString([new Point(1, 1), new Point(0, 0)]);
+ $polygon = new Polygon($linestrings, 4326);
+
+ $this->queryBuilder
+ ->shouldReceive('update')
+ ->with(['polygon' => new SpatialExpression($polygon)])
+ ->once()
+ ->andReturn(1);
+
+ $result = $this->builder->update(['polygon' => $polygon]);
- $this->builder->update(['polygon' => $polygon]);
+ $this->assertSame(1, $result);
}
}
diff --git a/tests/Unit/Eloquent/SpatialTraitTest.php b/tests/Unit/Eloquent/SpatialTraitTest.php
index 94482a1c..8ece7d25 100644
--- a/tests/Unit/Eloquent/SpatialTraitTest.php
+++ b/tests/Unit/Eloquent/SpatialTraitTest.php
@@ -4,10 +4,13 @@
use Grimzy\LaravelMysqlSpatial\MysqlConnection;
use Grimzy\LaravelMysqlSpatial\Types\Point;
use Illuminate\Database\Eloquent\Model;
+use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use Mockery as m;
class SpatialTraitTest extends BaseTestCase
{
+ use MockeryPHPUnitIntegration;
+
/**
* @var TestModel
*/
@@ -37,7 +40,7 @@ public function testInsertUpdatePointHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('insert', $this->queries[0]);
- $this->assertContains('insert into `test_models` (`point`) values (ST_GeomFromText(?))', $this->queries[0]);
+ $this->assertContains('insert into `test_models` (`point`) values (ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $this->queries[0]);
// TODO: assert bindings in query
$this->assertTrue($this->model->exists);
@@ -45,7 +48,7 @@ public function testInsertUpdatePointHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('update', $this->queries[1]);
- $this->assertContains('update `test_models` set `point` = ST_GeomFromText(?) where `id` = ?', $this->queries[1]);
+ $this->assertContains('update `test_models` set `point` = ST_GeomFromText(?, ?, \'axis-order=long-lat\') where `id` = ?', $this->queries[1]);
// TODO: assert bindings in query
}
@@ -60,7 +63,7 @@ public function testInsertUpdateLineStringHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('insert', $this->queries[0]);
- $this->assertContains('insert into `test_models` (`linestring`) values (ST_GeomFromText(?))', $this->queries[0]);
+ $this->assertContains('insert into `test_models` (`linestring`) values (ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $this->queries[0]);
// TODO: assert bindings in query
$this->assertTrue($this->model->exists);
@@ -68,7 +71,7 @@ public function testInsertUpdateLineStringHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('update', $this->queries[1]);
- $this->assertContains('update `test_models` set `linestring` = ST_GeomFromText(?) where `id` = ?', $this->queries[1]);
+ $this->assertContains('update `test_models` set `linestring` = ST_GeomFromText(?, ?, \'axis-order=long-lat\') where `id` = ?', $this->queries[1]);
// TODO: assert bindings in query
}
@@ -87,14 +90,14 @@ public function testInsertUpdatePolygonHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('insert', $this->queries[0]);
- $this->assertContains('insert into `test_models` (`polygon`) values (ST_GeomFromText(?))', $this->queries[0]);
+ $this->assertContains('insert into `test_models` (`polygon`) values (ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $this->queries[0]);
// TODO: assert bindings in query
$this->assertTrue($this->model->exists);
$this->model->polygon = new \Grimzy\LaravelMysqlSpatial\Types\Polygon([$linestring1, $linestring2]);
$this->model->save();
$this->assertStringStartsWith('update', $this->queries[1]);
- $this->assertContains('update `test_models` set `polygon` = ST_GeomFromText(?) where `id` = ?', $this->queries[1]);
+ $this->assertContains('update `test_models` set `polygon` = ST_GeomFromText(?, ?, \'axis-order=long-lat\') where `id` = ?', $this->queries[1]);
// TODO: assert bindings in query
}
@@ -109,7 +112,7 @@ public function testInsertUpdateMultiPointHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('insert', $this->queries[0]);
- $this->assertContains('insert into `test_models` (`multipoint`) values (ST_GeomFromText(?))', $this->queries[0]);
+ $this->assertContains('insert into `test_models` (`multipoint`) values (ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $this->queries[0]);
// TODO: assert bindings in query
$this->assertTrue($this->model->exists);
@@ -117,7 +120,7 @@ public function testInsertUpdateMultiPointHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('update', $this->queries[1]);
- $this->assertContains('update `test_models` set `multipoint` = ST_GeomFromText(?) where `id` = ?', $this->queries[1]);
+ $this->assertContains('update `test_models` set `multipoint` = ST_GeomFromText(?, ?, \'axis-order=long-lat\') where `id` = ?', $this->queries[1]);
// TODO: assert bindings in query
}
@@ -136,14 +139,14 @@ public function testInsertUpdateMultiLineStringHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('insert', $this->queries[0]);
- $this->assertContains('insert into `test_models` (`multilinestring`) values (ST_GeomFromText(?))', $this->queries[0]);
+ $this->assertContains('insert into `test_models` (`multilinestring`) values (ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $this->queries[0]);
// TODO: assert bindings in query
$this->assertTrue($this->model->exists);
$this->model->multilinestring = new \Grimzy\LaravelMysqlSpatial\Types\MultiLineString([$linestring1, $linestring2]);
$this->model->save();
$this->assertStringStartsWith('update', $this->queries[1]);
- $this->assertContains('update `test_models` set `multilinestring` = ST_GeomFromText(?) where `id` = ?', $this->queries[1]);
+ $this->assertContains('update `test_models` set `multilinestring` = ST_GeomFromText(?, ?, \'axis-order=long-lat\') where `id` = ?', $this->queries[1]);
// TODO: assert bindings in query
}
@@ -171,14 +174,14 @@ public function testInsertUpdateMultiPolygonHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('insert', $this->queries[0]);
- $this->assertContains('insert into `test_models` (`multipolygon`) values (ST_GeomFromText(?))', $this->queries[0]);
+ $this->assertContains('insert into `test_models` (`multipolygon`) values (ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $this->queries[0]);
// TODO: assert bindings in query
$this->assertTrue($this->model->exists);
$this->model->multipolygon = new \Grimzy\LaravelMysqlSpatial\Types\MultiPolygon([$polygon1, $polygon2]);
$this->model->save();
$this->assertStringStartsWith('update', $this->queries[1]);
- $this->assertContains('update `test_models` set `multipolygon` = ST_GeomFromText(?) where `id` = ?', $this->queries[1]);
+ $this->assertContains('update `test_models` set `multipolygon` = ST_GeomFromText(?, ?, \'axis-order=long-lat\') where `id` = ?', $this->queries[1]);
// TODO: assert bindings in query
}
@@ -195,20 +198,20 @@ public function testInsertUpdateGeometryCollectionHasCorrectSql()
$this->model->save();
$this->assertStringStartsWith('insert', $this->queries[0]);
- $this->assertContains('insert into `test_models` (`geometrycollection`) values (ST_GeomFromText(?))', $this->queries[0]);
+ $this->assertContains('insert into `test_models` (`geometrycollection`) values (ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $this->queries[0]);
// TODO: assert bindings in query
$this->assertTrue($this->model->exists);
$this->model->geometrycollection = new \Grimzy\LaravelMysqlSpatial\Types\GeometryCollection([$point1, $linestring1]);
$this->model->save();
$this->assertStringStartsWith('update', $this->queries[1]);
- $this->assertContains('update `test_models` set `geometrycollection` = ST_GeomFromText(?) where `id` = ?', $this->queries[1]);
+ $this->assertContains('update `test_models` set `geometrycollection` = ST_GeomFromText(?, ?, \'axis-order=long-lat\') where `id` = ?', $this->queries[1]);
// TODO: assert bindings in query
}
public function testSettingRawAttributes()
{
- $attributes['point'] = '0101000000000000000000f03f0000000000000040';
+ $attributes['point'] = "\0\0\0\0".'0101000000000000000000f03f0000000000000040';
$this->model->setRawAttributes($attributes);
$this->assertInstanceOf(Point::class, ($this->model->point));
@@ -217,7 +220,10 @@ public function testSettingRawAttributes()
public function testSpatialFieldsNotDefinedException()
{
$model = new TestNoSpatialModel();
- $this->setExpectedException(SpatialFieldsNotDefinedException::class);
+ $this->assertException(
+ SpatialFieldsNotDefinedException::class,
+ 'TestNoSpatialModel has to define $spatialFields'
+ );
$model->getSpatialFields();
}
@@ -231,9 +237,9 @@ public function testScopeDistance()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertEquals('st_distance(`point`, ST_GeomFromText(?)) <= ?', $q->wheres[0]['sql']);
+ $this->assertEquals('st_distance(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) <= ?', $q->wheres[0]['sql']);
$this->assertEquals('POINT(2 1)', $bindings[0]);
- $this->assertEquals(10, $bindings[1]);
+ $this->assertEquals(10, $bindings[2]);
}
public function testScopeDistanceExcludingSelf()
@@ -246,11 +252,11 @@ public function testScopeDistanceExcludingSelf()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertEquals('st_distance(`point`, ST_GeomFromText(?)) <= ?', $q->wheres[0]['sql']);
- $this->assertEquals('st_distance(`point`, ST_GeomFromText(?)) != 0', $q->wheres[1]['sql']);
+ $this->assertEquals('st_distance(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) <= ?', $q->wheres[0]['sql']);
+ $this->assertEquals('st_distance(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) != 0', $q->wheres[1]['sql']);
$this->assertEquals('POINT(2 1)', $bindings[0]);
- $this->assertEquals(10, $bindings[1]);
- $this->assertEquals('POINT(2 1)', $bindings[2]);
+ $this->assertEquals(10, $bindings[2]);
+ $this->assertEquals('POINT(2 1)', $bindings[3]);
}
public function testScopeDistanceSphere()
@@ -263,9 +269,9 @@ public function testScopeDistanceSphere()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertEquals('st_distance_sphere(`point`, ST_GeomFromText(?)) <= ?', $q->wheres[0]['sql']);
+ $this->assertEquals('st_distance_sphere(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) <= ?', $q->wheres[0]['sql']);
$this->assertEquals('POINT(2 1)', $bindings[0]);
- $this->assertEquals(10, $bindings[1]);
+ $this->assertEquals(10, $bindings[2]);
}
public function testScopeDistanceSphereExcludingSelf()
@@ -278,11 +284,11 @@ public function testScopeDistanceSphereExcludingSelf()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertEquals('st_distance_sphere(`point`, ST_GeomFromText(?)) <= ?', $q->wheres[0]['sql']);
- $this->assertEquals('st_distance_sphere(point, ST_GeomFromText(?)) != 0', $q->wheres[1]['sql']);
+ $this->assertEquals('st_distance_sphere(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) <= ?', $q->wheres[0]['sql']);
+ $this->assertEquals('st_distance_sphere(point, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) != 0', $q->wheres[1]['sql']);
$this->assertEquals('POINT(2 1)', $bindings[0]);
- $this->assertEquals(10, $bindings[1]);
- $this->assertEquals('POINT(2 1)', $bindings[2]);
+ $this->assertEquals(10, $bindings[2]);
+ $this->assertEquals('POINT(2 1)', $bindings[3]);
}
public function testScopeDistanceValue()
@@ -297,7 +303,7 @@ public function testScopeDistanceValue()
$this->assertNotEmpty($bindings);
$this->assertEquals('*', $q->columns[0]);
$this->assertInstanceOf(\Illuminate\Database\Query\Expression::class, $q->columns[1]);
- $this->assertEquals('st_distance(`point`, ST_GeomFromText(?)) as distance', $q->columns[1]->getValue());
+ $this->assertEquals('st_distance(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) as distance', $q->columns[1]->getValue());
$this->assertEquals('POINT(2 1)', $bindings[0]);
}
@@ -313,7 +319,7 @@ public function testScopeDistanceValueWithSelect()
$this->assertNotEmpty($bindings);
$this->assertEquals('some_column', $q->columns[0]);
$this->assertInstanceOf(\Illuminate\Database\Query\Expression::class, $q->columns[1]);
- $this->assertEquals('st_distance(`point`, ST_GeomFromText(?)) as distance', $q->columns[1]->getValue());
+ $this->assertEquals('st_distance(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) as distance', $q->columns[1]->getValue());
$this->assertEquals('POINT(2 1)', $bindings[0]);
}
@@ -329,7 +335,7 @@ public function testScopeDistanceSphereValue()
$this->assertNotEmpty($bindings);
$this->assertEquals('*', $q->columns[0]);
$this->assertInstanceOf(\Illuminate\Database\Query\Expression::class, $q->columns[1]);
- $this->assertEquals('st_distance_sphere(`point`, ST_GeomFromText(?)) as distance', $q->columns[1]->getValue());
+ $this->assertEquals('st_distance_sphere(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) as distance', $q->columns[1]->getValue());
$this->assertEquals('POINT(2 1)', $bindings[0]);
}
@@ -345,7 +351,7 @@ public function testScopeDistanceSphereValueWithSelect()
$this->assertNotEmpty($bindings);
$this->assertEquals('some_column', $q->columns[0]);
$this->assertInstanceOf(\Illuminate\Database\Query\Expression::class, $q->columns[1]);
- $this->assertEquals('st_distance_sphere(`point`, ST_GeomFromText(?)) as distance', $q->columns[1]->getValue());
+ $this->assertEquals('st_distance_sphere(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) as distance', $q->columns[1]->getValue());
$this->assertEquals('POINT(2 1)', $bindings[0]);
}
@@ -373,7 +379,7 @@ public function testScopeComparison()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_within(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_within(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
@@ -386,7 +392,7 @@ public function testScopeWithin()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_within(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_within(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
@@ -399,7 +405,7 @@ public function testScopeCrosses()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_crosses(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_crosses(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
@@ -412,7 +418,7 @@ public function testScopeContains()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_contains(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_contains(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
@@ -425,7 +431,7 @@ public function testScopeDisjoint()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_disjoint(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_disjoint(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
@@ -438,7 +444,7 @@ public function testScopeEquals()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_equals(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_equals(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
@@ -451,7 +457,7 @@ public function testScopeIntersects()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_intersects(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_intersects(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
@@ -464,7 +470,7 @@ public function testScopeOverlaps()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_overlaps(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_overlaps(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
@@ -477,9 +483,47 @@ public function testScopeDoesTouch()
$this->assertNotEmpty($q->wheres);
$bindings = $q->getRawBindings()['where'];
$this->assertNotEmpty($bindings);
- $this->assertContains('st_touches(`point`, ST_GeomFromText(?))', $q->wheres[0]['sql']);
+ $this->assertContains('st_touches(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\'))', $q->wheres[0]['sql']);
$this->assertEquals('POLYGON((1 1,2 1),(2 1,2 2),(2 2,1 1))', $bindings[0]);
}
+
+ public function testScopeOrderBySpatialThrowsExceptionWhenFunctionNotRegistered()
+ {
+ $point = new Point(1, 2);
+ $this->assertException(
+ \Grimzy\LaravelMysqlSpatial\Exceptions\UnknownSpatialFunctionException::class,
+ 'does-not-exist'
+ );
+ TestModel::orderBySpatial('point', $point, 'does-not-exist');
+ }
+
+ public function testScopeOrderByDistance()
+ {
+ $point = new Point(1, 2);
+ $query = TestModel::orderByDistance('point', $point);
+
+ $this->assertInstanceOf(\Grimzy\LaravelMysqlSpatial\Eloquent\Builder::class, $query);
+ $q = $query->getQuery();
+ $this->assertNotEmpty($q->orders);
+ $bindings = $q->getRawBindings()['order'];
+ $this->assertNotEmpty($bindings);
+ $this->assertContains('st_distance(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) asc', $q->orders[0]['sql']);
+ $this->assertEquals('POINT(2 1)', $bindings[0]);
+ }
+
+ public function testScopeOrderByDistanceSphere()
+ {
+ $point = new Point(1, 2);
+ $query = TestModel::orderByDistanceSphere('point', $point);
+
+ $this->assertInstanceOf(\Grimzy\LaravelMysqlSpatial\Eloquent\Builder::class, $query);
+ $q = $query->getQuery();
+ $this->assertNotEmpty($q->orders);
+ $bindings = $q->getRawBindings()['order'];
+ $this->assertNotEmpty($bindings);
+ $this->assertContains('st_distance_sphere(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) asc', $q->orders[0]['sql']);
+ $this->assertEquals('POINT(2 1)', $bindings[0]);
+ }
}
class TestModel extends Model
diff --git a/tests/Unit/MysqlConnectionTest.php b/tests/Unit/MysqlConnectionTest.php
index c630d990..cae970a2 100644
--- a/tests/Unit/MysqlConnectionTest.php
+++ b/tests/Unit/MysqlConnectionTest.php
@@ -2,9 +2,10 @@
use Grimzy\LaravelMysqlSpatial\MysqlConnection;
use Grimzy\LaravelMysqlSpatial\Schema\Builder;
+use PHPUnit\Framework\TestCase;
use Stubs\PDOStub;
-class MysqlConnectionTest extends PHPUnit_Framework_TestCase
+class MysqlConnectionTest extends TestCase
{
private $mysqlConnection;
diff --git a/tests/Unit/Schema/BlueprintTest.php b/tests/Unit/Schema/BlueprintTest.php
index da335520..c22c9518 100644
--- a/tests/Unit/Schema/BlueprintTest.php
+++ b/tests/Unit/Schema/BlueprintTest.php
@@ -4,10 +4,14 @@
use BaseTestCase;
use Grimzy\LaravelMysqlSpatial\Schema\Blueprint;
+use Illuminate\Database\Schema\ColumnDefinition;
use Mockery;
class BlueprintTest extends BaseTestCase
{
+ /**
+ * @var \Grimzy\LaravelMysqlSpatial\Schema\Blueprint
+ */
protected $blueprint;
public function setUp()
@@ -20,81 +24,305 @@ public function setUp()
public function testGeometry()
{
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'geometry',
+ 'name' => 'col',
+ 'srid' => null,
+ ]);
+
$this->blueprint
->shouldReceive('addColumn')
- ->with('geometry', 'col')
- ->once();
+ ->with('geometry', 'col', ['srid' => null])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->geometry('col');
- $this->blueprint->geometry('col');
+ $this->assertSame($expectedCol, $result);
}
public function testPoint()
{
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'point',
+ 'name' => 'col',
+ 'srid' => null,
+ ]);
+
$this->blueprint
->shouldReceive('addColumn')
->with('point', 'col', ['srid' => null])
- ->once();
+ ->once()
+ ->andReturn($expectedCol);
- $this->blueprint->point('col');
+ $result = $this->blueprint->point('col');
+
+ $this->assertSame($expectedCol, $result);
}
public function testLinestring()
{
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'linestring',
+ 'name' => 'col',
+ 'srid' => null,
+ ]);
+
$this->blueprint
->shouldReceive('addColumn')
- ->with('linestring', 'col')
- ->once();
+ ->with('linestring', 'col', ['srid' => null])
+ ->once()
+ ->andReturn($expectedCol);
- $this->blueprint->linestring('col');
+ $result = $this->blueprint->linestring('col');
+
+ $this->assertSame($expectedCol, $result);
}
public function testPolygon()
{
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'polygon',
+ 'name' => 'col',
+ 'srid' => null,
+ ]);
+
$this->blueprint
->shouldReceive('addColumn')
- ->with('polygon', 'col')
- ->once();
+ ->with('polygon', 'col', ['srid' => null])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->polygon('col');
- $this->blueprint->polygon('col');
+ $this->assertSame($expectedCol, $result);
}
public function testMultiPoint()
{
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'multipoint',
+ 'name' => 'col',
+ 'srid' => null,
+ ]);
+
$this->blueprint
->shouldReceive('addColumn')
- ->with('multipoint', 'col')
- ->once();
+ ->with('multipoint', 'col', ['srid' => null])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->multipoint('col');
- $this->blueprint->multipoint('col');
+ $this->assertSame($expectedCol, $result);
}
public function testMultiLineString()
{
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'multilinestring',
+ 'name' => 'col',
+ 'srid' => null,
+ ]);
+
$this->blueprint
->shouldReceive('addColumn')
- ->with('multilinestring', 'col')
- ->once();
+ ->with('multilinestring', 'col', ['srid' => null])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->multilinestring('col');
- $this->blueprint->multilinestring('col');
+ $this->assertSame($expectedCol, $result);
}
- public function testMulltiPolygon()
+ public function testMultiPolygon()
{
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'multipolygon',
+ 'name' => 'col',
+ 'srid' => null,
+ ]);
+
$this->blueprint
->shouldReceive('addColumn')
- ->with('multipolygon', 'col')
- ->once();
+ ->with('multipolygon', 'col', ['srid' => null])
+ ->once()
+ ->andReturn($expectedCol);
- $this->blueprint->multipolygon('col');
+ $result = $this->blueprint->multipolygon('col');
+
+ $this->assertSame($expectedCol, $result);
}
public function testGeometryCollection()
{
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'geometrycollection',
+ 'name' => 'col',
+ 'srid' => null,
+ ]);
+
+ $this->blueprint
+ ->shouldReceive('addColumn')
+ ->with('geometrycollection', 'col', ['srid' => null])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->geometrycollection('col');
+
+ $this->assertSame($expectedCol, $result);
+ }
+
+ public function testGeometryWithSrid()
+ {
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'geometry',
+ 'name' => 'col',
+ 'srid' => 4326,
+ ]);
+
+ $this->blueprint
+ ->shouldReceive('addColumn')
+ ->with('geometry', 'col', ['srid' => 4326])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->geometry('col', 4326);
+
+ $this->assertSame($expectedCol, $result);
+ }
+
+ public function testPointWithSrid()
+ {
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'point',
+ 'name' => 'col',
+ 'srid' => 4326,
+ ]);
+
+ $this->blueprint
+ ->shouldReceive('addColumn')
+ ->with('point', 'col', ['srid' => 4326])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->point('col', 4326);
+
+ $this->assertSame($expectedCol, $result);
+ }
+
+ public function testLinestringWithSrid()
+ {
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'linestring',
+ 'name' => 'col',
+ 'srid' => 4326,
+ ]);
+
+ $this->blueprint
+ ->shouldReceive('addColumn')
+ ->with('linestring', 'col', ['srid' => 4326])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->linestring('col', 4326);
+
+ $this->assertSame($expectedCol, $result);
+ }
+
+ public function testPolygonWithSrid()
+ {
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'polygon',
+ 'name' => 'col',
+ 'srid' => 4326,
+ ]);
+
+ $this->blueprint
+ ->shouldReceive('addColumn')
+ ->with('polygon', 'col', ['srid' => 4326])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->polygon('col', 4326);
+
+ $this->assertSame($expectedCol, $result);
+ }
+
+ public function testMultiPointWithSrid()
+ {
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'multipoint',
+ 'name' => 'col',
+ 'srid' => 4326,
+ ]);
+
+ $this->blueprint
+ ->shouldReceive('addColumn')
+ ->with('multipoint', 'col', ['srid' => 4326])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->multipoint('col', 4326);
+
+ $this->assertSame($expectedCol, $result);
+ }
+
+ public function testMultiLineStringWithSrid()
+ {
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'multilinestring',
+ 'name' => 'col',
+ 'srid' => 4326,
+ ]);
+
+ $this->blueprint
+ ->shouldReceive('addColumn')
+ ->with('multilinestring', 'col', ['srid' => 4326])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->multilinestring('col', 4326);
+
+ $this->assertSame($expectedCol, $result);
+ }
+
+ public function testMultiPolygonWithSrid()
+ {
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'multipolygon',
+ 'name' => 'col',
+ 'srid' => 4326,
+ ]);
+
+ $this->blueprint
+ ->shouldReceive('addColumn')
+ ->with('multipolygon', 'col', ['srid' => 4326])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->multipolygon('col', 4326);
+
+ $this->assertSame($expectedCol, $result);
+ }
+
+ public function testGeometryCollectionWithSrid()
+ {
+ $expectedCol = new ColumnDefinition([
+ 'type' => 'geometrycollection',
+ 'name' => 'col',
+ 'srid' => 4326,
+ ]);
+
$this->blueprint
->shouldReceive('addColumn')
- ->with('geometrycollection', 'col')
- ->once();
+ ->with('geometrycollection', 'col', ['srid' => 4326])
+ ->once()
+ ->andReturn($expectedCol);
+
+ $result = $this->blueprint->geometrycollection('col', 4326);
- $this->blueprint->geometrycollection('col');
+ $this->assertSame($expectedCol, $result);
}
}
diff --git a/tests/Unit/Schema/Grammars/MySqlGrammarTest.php b/tests/Unit/Schema/Grammars/MySqlGrammarTest.php
index 4773a2ea..66ba7641 100644
--- a/tests/Unit/Schema/Grammars/MySqlGrammarTest.php
+++ b/tests/Unit/Schema/Grammars/MySqlGrammarTest.php
@@ -13,7 +13,7 @@ public function testAddingGeometry()
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(1, count($statements));
- $this->assertContains('GEOMETRY', $statements[0]);
+ $this->assertEquals('alter table `test` add `foo` GEOMETRY not null', $statements[0]);
}
public function testAddingPoint()
@@ -23,7 +23,7 @@ public function testAddingPoint()
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(1, count($statements));
- $this->assertContains('POINT', $statements[0]);
+ $this->assertEquals('alter table `test` add `foo` POINT not null', $statements[0]);
}
public function testAddingLinestring()
@@ -33,7 +33,7 @@ public function testAddingLinestring()
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(1, count($statements));
- $this->assertContains('LINESTRING', $statements[0]);
+ $this->assertEquals('alter table `test` add `foo` LINESTRING not null', $statements[0]);
}
public function testAddingPolygon()
@@ -43,7 +43,7 @@ public function testAddingPolygon()
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(1, count($statements));
- $this->assertContains('POLYGON', $statements[0]);
+ $this->assertEquals('alter table `test` add `foo` POLYGON not null', $statements[0]);
}
public function testAddingMultipoint()
@@ -53,7 +53,7 @@ public function testAddingMultipoint()
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(1, count($statements));
- $this->assertContains('MULTIPOINT', $statements[0]);
+ $this->assertEquals('alter table `test` add `foo` MULTIPOINT not null', $statements[0]);
}
public function testAddingMultiLinestring()
@@ -63,7 +63,7 @@ public function testAddingMultiLinestring()
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(1, count($statements));
- $this->assertContains('MULTILINESTRING', $statements[0]);
+ $this->assertEquals('alter table `test` add `foo` MULTILINESTRING not null', $statements[0]);
}
public function testAddingMultiPolygon()
@@ -73,7 +73,7 @@ public function testAddingMultiPolygon()
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(1, count($statements));
- $this->assertContains('MULTIPOLYGON', $statements[0]);
+ $this->assertEquals('alter table `test` add `foo` MULTIPOLYGON not null', $statements[0]);
}
public function testAddingGeometryCollection()
@@ -83,7 +83,87 @@ public function testAddingGeometryCollection()
$statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(1, count($statements));
- $this->assertContains('GEOMETRYCOLLECTION', $statements[0]);
+ $this->assertEquals('alter table `test` add `foo` GEOMETRYCOLLECTION not null', $statements[0]);
+ }
+
+ public function testAddingGeometryWithSrid()
+ {
+ $blueprint = new Blueprint('test');
+ $blueprint->geometry('foo', 4326);
+ $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
+
+ $this->assertEquals(1, count($statements));
+ $this->assertEquals('alter table `test` add `foo` GEOMETRY not null srid 4326', $statements[0]);
+ }
+
+ public function testAddingPointWithSrid()
+ {
+ $blueprint = new Blueprint('test');
+ $blueprint->point('foo', 4326);
+ $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
+
+ $this->assertEquals(1, count($statements));
+ $this->assertEquals('alter table `test` add `foo` POINT not null srid 4326', $statements[0]);
+ }
+
+ public function testAddingLinestringWithSrid()
+ {
+ $blueprint = new Blueprint('test');
+ $blueprint->linestring('foo', 4326);
+ $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
+
+ $this->assertEquals(1, count($statements));
+ $this->assertEquals('alter table `test` add `foo` LINESTRING not null srid 4326', $statements[0]);
+ }
+
+ public function testAddingPolygonWithSrid()
+ {
+ $blueprint = new Blueprint('test');
+ $blueprint->polygon('foo', 4326);
+ $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
+
+ $this->assertEquals(1, count($statements));
+ $this->assertEquals('alter table `test` add `foo` POLYGON not null srid 4326', $statements[0]);
+ }
+
+ public function testAddingMultipointWithSrid()
+ {
+ $blueprint = new Blueprint('test');
+ $blueprint->multipoint('foo', 4326);
+ $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
+
+ $this->assertEquals(1, count($statements));
+ $this->assertEquals('alter table `test` add `foo` MULTIPOINT not null srid 4326', $statements[0]);
+ }
+
+ public function testAddingMultiLinestringWithSrid()
+ {
+ $blueprint = new Blueprint('test');
+ $blueprint->multilinestring('foo', 4326);
+ $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
+
+ $this->assertEquals(1, count($statements));
+ $this->assertEquals('alter table `test` add `foo` MULTILINESTRING not null srid 4326', $statements[0]);
+ }
+
+ public function testAddingMultiPolygonWithSrid()
+ {
+ $blueprint = new Blueprint('test');
+ $blueprint->multipolygon('foo', 4326);
+ $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
+
+ $this->assertEquals(1, count($statements));
+ $this->assertEquals('alter table `test` add `foo` MULTIPOLYGON not null srid 4326', $statements[0]);
+ }
+
+ public function testAddingGeometryCollectionWithSrid()
+ {
+ $blueprint = new Blueprint('test');
+ $blueprint->geometrycollection('foo', 4326);
+ $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
+
+ $this->assertEquals(1, count($statements));
+ $this->assertEquals('alter table `test` add `foo` GEOMETRYCOLLECTION not null srid 4326', $statements[0]);
}
public function testAddRemoveSpatialIndex()
@@ -94,7 +174,7 @@ public function testAddRemoveSpatialIndex()
$addStatements = $blueprint->toSql($this->getConnection(), $this->getGrammar());
$this->assertEquals(2, count($addStatements));
- $this->assertContains('alter table `test` add spatial `test_foo_spatial`(`foo`)', $addStatements[1]);
+ $this->assertEquals('alter table `test` add spatial `test_foo_spatial`(`foo`)', $addStatements[1]);
$blueprint->dropSpatialIndex(['foo']);
$blueprint->dropSpatialIndex('test_foo_spatial');
@@ -102,8 +182,8 @@ public function testAddRemoveSpatialIndex()
$expectedSql = 'alter table `test` drop index `test_foo_spatial`';
$this->assertEquals(5, count($dropStatements));
- $this->assertContains($expectedSql, $dropStatements[3]);
- $this->assertContains($expectedSql, $dropStatements[4]);
+ $this->assertEquals($expectedSql, $dropStatements[3]);
+ $this->assertEquals($expectedSql, $dropStatements[4]);
}
/**
diff --git a/tests/Unit/Types/GeometryCollectionTest.php b/tests/Unit/Types/GeometryCollectionTest.php
index 07759c5f..a0d6f016 100644
--- a/tests/Unit/Types/GeometryCollectionTest.php
+++ b/tests/Unit/Types/GeometryCollectionTest.php
@@ -33,9 +33,34 @@ public function testJsonSerialize()
$this->assertSame('{"type":"GeometryCollection","geometries":[{"type":"LineString","coordinates":[[0,0],[1,0],[1,1],[0,1],[0,0]]},{"type":"Point","coordinates":[200,100]}]}', json_encode($this->getGeometryCollection()->jsonSerialize()));
}
+ public function testCanCreateEmptyGeometryCollection()
+ {
+ $geometryCollection = new GeometryCollection([]);
+ $this->assertInstanceOf(GeometryCollection::class, $geometryCollection);
+ }
+
+ public function testFromWKTWithEmptyGeometryCollection()
+ {
+ /**
+ * @var GeometryCollection
+ */
+ $geometryCollection = GeometryCollection::fromWKT('GEOMETRYCOLLECTION()');
+ $this->assertInstanceOf(GeometryCollection::class, $geometryCollection);
+
+ $this->assertEquals(0, $geometryCollection->count());
+ }
+
+ public function testToWKTWithEmptyGeometryCollection()
+ {
+ $this->assertEquals('GEOMETRYCOLLECTION()', (new GeometryCollection([]))->toWKT());
+ }
+
public function testInvalidArgumentExceptionNotArrayGeometries()
{
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\GeometryCollection must be a collection of Grimzy\LaravelMysqlSpatial\Types\GeometryInterface'
+ );
$geometrycollection = new GeometryCollection([
$this->getPoint(),
1,
@@ -85,7 +110,10 @@ public function testArrayAccess()
$this->assertEquals($point100, $geometryCollection[100]);
// assert invalid
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\GeometryCollection must be a collection of Grimzy\LaravelMysqlSpatial\Types\GeometryInterface'
+ );
$geometryCollection[] = 1;
}
@@ -101,7 +129,10 @@ public function testFromJson()
public function testInvalidGeoJsonException()
{
- $this->setExpectedException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class);
+ $this->assertException(
+ \Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class,
+ sprintf('Expected %s, got %s', GeoJson\Feature\FeatureCollection::class, GeoJson\Geometry\Point::class)
+ );
GeometryCollection::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
}
diff --git a/tests/Unit/Types/GeometryTest.php b/tests/Unit/Types/GeometryTest.php
index 51b400ec..e51022d5 100644
--- a/tests/Unit/Types/GeometryTest.php
+++ b/tests/Unit/Types/GeometryTest.php
@@ -32,24 +32,28 @@ public function testGetWKTClass()
$this->assertEquals(MultiLineString::class, Geometry::getWKTClass('MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))'));
$this->assertEquals(MultiPolygon::class, Geometry::getWKTClass('MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))'));
$this->assertEquals(GeometryCollection::class, Geometry::getWKTClass('GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))'));
- $this->assertException(UnknownWKTTypeException::class);
+ $this->assertException(
+ UnknownWKTTypeException::class,
+ 'Type was TRIANGLE'
+ );
Geometry::getWKTClass('TRIANGLE((0 0, 0 9, 9 0, 0 0))');
}
public function testGetWKBClass()
{
- $this->assertInstanceOf(Point::class, Geometry::fromWKB('0101000000000000000000f03f0000000000000040'));
+ $prefix = "\0\0\0\0";
+
+ $this->assertInstanceOf(Point::class, Geometry::fromWKB($prefix.'0101000000000000000000f03f0000000000000040'));
- $this->assertInstanceOf(LineString::class, Geometry::fromWKB('010200000002000000000000000000f03f000000000000004000000000000008400000000000001040'));
- $this->assertInstanceOf(Polygon::class, Geometry::fromWKB('01030000000100000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f0000000000000040'));
- $this->assertInstanceOf(MultiPoint::class, Geometry::fromWKB('0104000000020000000101000000000000000000f03f0000000000000040010100000000000000000008400000000000001040'));
- $this->assertInstanceOf(MultiLineString::class, Geometry::fromWKB('010500000001000000010200000002000000000000000000f03f000000000000004000000000000008400000000000001040'));
- $this->assertInstanceOf(MultiLineString::class, Geometry::fromWKB('010500000002000000010200000002000000000000000000f03f000000000000004000000000000008400000000000001040010200000002000000000000000000144000000000000018400000000000001c400000000000002040'));
- $this->assertInstanceOf(MultiPolygon::class, Geometry::fromWKB('01060000000200000001030000000100000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f000000000000004001030000000300000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f000000000000004004000000000000000000264000000000000028400000000000002a400000000000002c400000000000002e4000000000000030400000000000002640000000000000284004000000000000000000354000000000000036400000000000003740000000000000384000000000000039400000000000003a4000000000000035400000000000003640'));
- $this->assertInstanceOf(GeometryCollection::class, Geometry::fromWKB('0107000000010000000101000000000000000000f03f0000000000000040'));
- $this->assertInstanceOf(GeometryCollection::class, Geometry::fromWKB('0107000000020000000101000000000000000000f03f0000000000000040010200000002000000000000000000f03f000000000000004000000000000008400000000000001040'));
+ $this->assertInstanceOf(LineString::class, Geometry::fromWKB($prefix.'010200000002000000000000000000f03f000000000000004000000000000008400000000000001040'));
+ $this->assertInstanceOf(Polygon::class, Geometry::fromWKB($prefix.'01030000000100000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f0000000000000040'));
+ $this->assertInstanceOf(MultiPoint::class, Geometry::fromWKB($prefix.'0104000000020000000101000000000000000000f03f0000000000000040010100000000000000000008400000000000001040'));
+ $this->assertInstanceOf(MultiLineString::class, Geometry::fromWKB($prefix.'010500000001000000010200000002000000000000000000f03f000000000000004000000000000008400000000000001040'));
+ $this->assertInstanceOf(MultiLineString::class, Geometry::fromWKB($prefix.'010500000002000000010200000002000000000000000000f03f000000000000004000000000000008400000000000001040010200000002000000000000000000144000000000000018400000000000001c400000000000002040'));
+ $this->assertInstanceOf(MultiPolygon::class, Geometry::fromWKB($prefix.'01060000000200000001030000000100000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f000000000000004001030000000300000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f000000000000004004000000000000000000264000000000000028400000000000002a400000000000002c400000000000002e4000000000000030400000000000002640000000000000284004000000000000000000354000000000000036400000000000003740000000000000384000000000000039400000000000003a4000000000000035400000000000003640'));
+ $this->assertInstanceOf(GeometryCollection::class, Geometry::fromWKB($prefix.'0107000000010000000101000000000000000000f03f0000000000000040'));
+ $this->assertInstanceOf(GeometryCollection::class, Geometry::fromWKB($prefix.'0107000000020000000101000000000000000000f03f0000000000000040010200000002000000000000000000f03f000000000000004000000000000008400000000000001040'));
- $prefix = "\0\0\0\0";
$this->assertInstanceOf(Point::class, Geometry::fromWKB($prefix.'0101000000000000000000f03f0000000000000040'));
}
diff --git a/tests/Unit/Types/LineStringTest.php b/tests/Unit/Types/LineStringTest.php
index 9300e3f1..ce5713d2 100644
--- a/tests/Unit/Types/LineStringTest.php
+++ b/tests/Unit/Types/LineStringTest.php
@@ -45,7 +45,10 @@ public function testFromJson()
public function testInvalidGeoJsonException()
{
- $this->setExpectedException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class);
+ $this->assertException(
+ \Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class,
+ sprintf('Expected %s, got %s', \GeoJson\Geometry\LineString::class, GeoJson\Geometry\Point::class)
+ );
LineString::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
}
diff --git a/tests/Unit/Types/MultiLineStringTest.php b/tests/Unit/Types/MultiLineStringTest.php
index df7b42e4..16477feb 100644
--- a/tests/Unit/Types/MultiLineStringTest.php
+++ b/tests/Unit/Types/MultiLineStringTest.php
@@ -45,7 +45,10 @@ public function testFromJson()
public function testInvalidGeoJsonException()
{
- $this->setExpectedException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class);
+ $this->assertException(
+ \Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class,
+ sprintf('Expected %s, got %s', GeoJson\Geometry\MultiLineString::class, GeoJson\Geometry\Point::class)
+ );
MultiLineString::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
}
@@ -59,13 +62,19 @@ public function testJsonSerialize()
public function testInvalidArgumentExceptionAtLeastOneEntry()
{
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiLineString must contain at least 1 entry'
+ );
$multilinestring = new MultiLineString([]);
}
public function testInvalidArgumentExceptionNotArrayOfLineString()
{
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiLineString must be a collection of Grimzy\LaravelMysqlSpatial\Types\LineString'
+ );
$multilinestring = new MultiLineString([
new LineString([new Point(0, 0), new Point(1, 1)]),
new Point(0, 1),
@@ -98,7 +107,10 @@ public function testArrayAccess()
$this->assertEquals($linestring2, $multilinestring[2]);
// assert invalid
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiLineString must be a collection of Grimzy\LaravelMysqlSpatial\Types\LineString'
+ );
$multilinestring[] = 1;
}
}
diff --git a/tests/Unit/Types/MultiPointTest.php b/tests/Unit/Types/MultiPointTest.php
index 1e9bf7f4..a8a94f41 100644
--- a/tests/Unit/Types/MultiPointTest.php
+++ b/tests/Unit/Types/MultiPointTest.php
@@ -42,7 +42,10 @@ public function testFromJson()
public function testInvalidGeoJsonException()
{
- $this->setExpectedException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class);
+ $this->assertException(
+ \Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class,
+ sprintf('Expected %s, got %s', GeoJson\Geometry\MultiPoint::class, GeoJson\Geometry\Point::class)
+ );
MultiPoint::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
}
@@ -58,13 +61,19 @@ public function testJsonSerialize()
public function testInvalidArgumentExceptionAtLeastOneEntry()
{
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiPoint must contain at least 1 entry'
+ );
$multipoint = new MultiPoint([]);
}
public function testInvalidArgumentExceptionNotArrayOfLineString()
{
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiPoint must be a collection of Grimzy\LaravelMysqlSpatial\Types\Point'
+ );
$multipoint = new MultiPoint([
new Point(0, 0),
1,
@@ -87,7 +96,10 @@ public function testArrayAccess()
$this->assertEquals($point2, $multipoint[2]);
// assert invalid
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiPoint must be a collection of Grimzy\LaravelMysqlSpatial\Types\Point'
+ );
$multipoint[] = 1;
}
@@ -132,7 +144,10 @@ public function testDeprecatedInsertPoint()
$this->assertEquals($point2, $multipoint[1]);
$this->assertEquals($point3, $multipoint[2]);
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ '$index is greater than the size of the array'
+ );
$multipoint->insertPoint(100, new Point(100, 100));
}
}
diff --git a/tests/Unit/Types/MultiPolygonTest.php b/tests/Unit/Types/MultiPolygonTest.php
index cf5894ff..3e49d32d 100644
--- a/tests/Unit/Types/MultiPolygonTest.php
+++ b/tests/Unit/Types/MultiPolygonTest.php
@@ -65,7 +65,10 @@ public function testFromJson()
public function testInvalidGeoJsonException()
{
- $this->setExpectedException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class);
+ $this->assertException(
+ \Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class,
+ sprintf('Expected %s, got %s', GeoJson\Geometry\MultiPolygon::class, GeoJson\Geometry\Point::class)
+ );
MultiPolygon::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
}
@@ -75,9 +78,21 @@ public function testJsonSerialize()
$this->assertSame('{"type":"MultiPolygon","coordinates":[[[[0,0],[1,0],[1,1],[0,1],[0,0]],[[10,10],[20,10],[20,20],[10,20],[10,10]]],[[[100,100],[200,100],[200,200],[100,200],[100,100]]]]}', json_encode($this->getMultiPolygon()));
}
- public function testInvalidArgumentExceptionNotArrayOfLineString()
+ public function testInvalidArgumentExceptionAtLeastOneEntry()
{
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiPolygon must contain at least 1 entry'
+ );
+ $multipolygon = new MultiPolygon([]);
+ }
+
+ public function testInvalidArgumentExceptionNotArrayOfPolygon()
+ {
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiPolygon must be a collection of Grimzy\LaravelMysqlSpatial\Types\Polygon'
+ );
$multipolygon = new MultiPolygon([
$this->getPolygon1(),
$this->getLineString1(),
@@ -101,7 +116,10 @@ public function testArrayAccess()
$this->assertEquals($polygon2, $multipolygon[2]);
// assert invalid
- $this->assertException(InvalidArgumentException::class);
+ $this->assertException(
+ InvalidArgumentException::class,
+ 'Grimzy\LaravelMysqlSpatial\Types\MultiPolygon must be a collection of Grimzy\LaravelMysqlSpatial\Types\Polygon'
+ );
$multipolygon[] = 1;
}
diff --git a/tests/Unit/Types/PointTest.php b/tests/Unit/Types/PointTest.php
index 257f6a45..518a8a56 100644
--- a/tests/Unit/Types/PointTest.php
+++ b/tests/Unit/Types/PointTest.php
@@ -6,18 +6,19 @@ class PointTest extends BaseTestCase
{
public function testFromWKT()
{
- $point = Point::fromWKT('POINT(1 2)');
+ $point = Point::fromWKT('POINT(1 2)', 4326);
$this->assertInstanceOf(Point::class, $point);
- $this->assertEquals(2, $point->getLat());
- $this->assertEquals(1, $point->getLng());
+ $this->assertSame(2.0, $point->getLat());
+ $this->assertSame(1.0, $point->getLng());
+ $this->assertSame(4326, $point->getSrid());
}
public function testToWKT()
{
- $point = new Point(1, 2);
+ $point = new Point(1, 2, 4326);
- $this->assertEquals('POINT(2 1)', $point->toWKT());
+ $this->assertSame('POINT(2 1)', $point->toWKT());
}
public function testGettersAndSetters()
@@ -25,30 +26,35 @@ public function testGettersAndSetters()
$point = new Point(1, 2);
$this->assertSame(1.0, $point->getLat());
$this->assertSame(2.0, $point->getLng());
+ $this->assertSame(0, $point->getSrid());
$point->setLat('3');
$point->setLng('4');
+ $point->setSrid(100);
$this->assertSame(3.0, $point->getLat());
$this->assertSame(4.0, $point->getLng());
+ $this->assertSame(100, $point->getSrid());
}
public function testPair()
{
- $point = Point::fromPair('1.5 2');
+ $point = Point::fromPair('1.5 2', 4326);
$this->assertSame(1.5, $point->getLng());
$this->assertSame(2.0, $point->getLat());
+ $this->assertSame(4326, $point->getSrid());
$this->assertSame('1.5 2', $point->toPair());
}
public function testToString()
{
- $point = Point::fromString('1.3 2');
+ $point = Point::fromString('1.3 2', 4326);
$this->assertSame(1.3, $point->getLng());
$this->assertSame(2.0, $point->getLat());
+ $this->assertSame(4326, $point->getSrid());
$this->assertEquals('1.3 2', (string) $point);
}
@@ -57,13 +63,16 @@ public function testFromJson()
{
$point = Point::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
$this->assertInstanceOf(Point::class, $point);
- $this->assertEquals(1.2, $point->getLat());
- $this->assertEquals(3.4, $point->getLng());
+ $this->assertSame(1.2, $point->getLat());
+ $this->assertSame(3.4, $point->getLng());
}
public function testInvalidGeoJsonException()
{
- $this->setExpectedException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class);
+ $this->assertException(
+ \Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class,
+ 'Expected GeoJson\Geometry\Point, got GeoJson\Geometry\LineString'
+ );
Point::fromJson('{"type": "LineString","coordinates":[[1,1],[2,2]]}');
}
diff --git a/tests/Unit/Types/PolygonTest.php b/tests/Unit/Types/PolygonTest.php
index de923c2f..aaab437b 100644
--- a/tests/Unit/Types/PolygonTest.php
+++ b/tests/Unit/Types/PolygonTest.php
@@ -20,12 +20,12 @@ protected function setUp()
]
);
- $this->polygon = new Polygon([$collection]);
+ $this->polygon = new Polygon([$collection], 4326);
}
public function testFromWKT()
{
- $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 = Polygon::fromWKT('POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))', 4326);
$this->assertInstanceOf(Polygon::class, $polygon);
$this->assertEquals(2, $polygon->count());
@@ -56,7 +56,10 @@ public function testFromJson()
public function testInvalidGeoJsonException()
{
- $this->setExpectedException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class);
+ $this->assertException(
+ \Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class,
+ 'Expected GeoJson\Geometry\Polygon, got GeoJson\Geometry\Point'
+ );
Polygon::fromJson('{"type":"Point","coordinates":[3.4,1.2]}');
}