From a1982786169502ab3f1ac56278ca180538add3c2 Mon Sep 17 00:00:00 2001 From: jl9404 Date: Sat, 27 Oct 2018 13:45:26 +0800 Subject: [PATCH 01/55] Fix Geometry::fromWKB function to allow various SRID --- src/Types/Geometry.php | 6 +----- tests/Unit/Eloquent/SpatialTraitTest.php | 2 +- tests/Unit/Types/GeometryTest.php | 21 +++++++++++---------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/Types/Geometry.php b/src/Types/Geometry.php index a46baed3..c0df8ec3 100644 --- a/src/Types/Geometry.php +++ b/src/Types/Geometry.php @@ -55,11 +55,7 @@ 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)); - } - + $wkb = substr($wkb, 4); $parser = new Parser(new Factory()); return $parser->parse($wkb); diff --git a/tests/Unit/Eloquent/SpatialTraitTest.php b/tests/Unit/Eloquent/SpatialTraitTest.php index 94482a1c..6fb9f207 100644 --- a/tests/Unit/Eloquent/SpatialTraitTest.php +++ b/tests/Unit/Eloquent/SpatialTraitTest.php @@ -208,7 +208,7 @@ public function testInsertUpdateGeometryCollectionHasCorrectSql() public function testSettingRawAttributes() { - $attributes['point'] = '0101000000000000000000f03f0000000000000040'; + $attributes['point'] = "\0\0\0\0".'0101000000000000000000f03f0000000000000040'; $this->model->setRawAttributes($attributes); $this->assertInstanceOf(Point::class, ($this->model->point)); diff --git a/tests/Unit/Types/GeometryTest.php b/tests/Unit/Types/GeometryTest.php index 51b400ec..8bd765a7 100644 --- a/tests/Unit/Types/GeometryTest.php +++ b/tests/Unit/Types/GeometryTest.php @@ -38,18 +38,19 @@ public function testGetWKTClass() 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')); } From 4db0a4a212def2083e1bef733414c57c30c1e72d Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Wed, 6 Feb 2019 21:37:55 -0500 Subject: [PATCH 02/55] Updated Blueprint to accept srid for all geometry types --- src/Schema/Blueprint.php | 49 +++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/Schema/Blueprint.php b/src/Schema/Blueprint.php index 9507e31e..80106578 100644 --- a/src/Schema/Blueprint.php +++ b/src/Schema/Blueprint.php @@ -9,13 +9,14 @@ class Blueprint extends IlluminateBlueprint /** * Add a geometry column on the table. * - * @param string $column + * @param string $column + * @param null|int $srid * * @return \Illuminate\Support\Fluent */ - public function geometry($column) + public function geometry($column, $srid = null) { - return $this->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')); } /** From ccce934f44bbba5623b10738152b0f138623ccf6 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Wed, 6 Feb 2019 22:18:16 -0500 Subject: [PATCH 03/55] Added tests for migrations. Abstracted createApplication process in integration tests. Removed utility class ClassFinder --- tests/Integration/IntegrationBaseTestCase.php | 111 +++++++++++++ tests/Integration/MigrationTest.php | 56 +++++++ tests/Integration/Migrations/CreateTables.php | 15 +- tests/Integration/Migrations/UpdateTables.php | 2 +- tests/Integration/SpatialTest.php | 112 +------------ tests/Integration/Tools/ClassFinder.php | 154 ------------------ 6 files changed, 187 insertions(+), 263 deletions(-) create mode 100644 tests/Integration/IntegrationBaseTestCase.php create mode 100644 tests/Integration/MigrationTest.php delete mode 100644 tests/Integration/Tools/ClassFinder.php diff --git a/tests/Integration/IntegrationBaseTestCase.php b/tests/Integration/IntegrationBaseTestCase.php new file mode 100644 index 00000000..54d23afa --- /dev/null +++ b/tests/Integration/IntegrationBaseTestCase.php @@ -0,0 +1,111 @@ +register(SpatialServiceProvider::class); + + $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap(); + + /** + * @param \Illuminate\Config\Repository $config + */ + $config = $app->config; + $config->set('database.default', 'mysql'); + $config->set('database.connections.mysql.host', env('DB_HOST', '127.0.0.1')); + $config->set('database.connections.mysql.database', 'spatial_test'); + $config->set('database.connections.mysql.username', 'root'); + $config->set('database.connections.mysql.password', ''); + $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) + { + $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..3f5f9960 --- /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(10) 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..1c668725 100644 --- a/tests/Integration/Migrations/CreateTables.php +++ b/tests/Integration/Migrations/CreateTables.php @@ -1,7 +1,7 @@ increments('id'); $table->geometry('geometry')->default(null)->nullable(); }); + + Schema::create('with_srid', function (Blueprint $table) { + $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 +53,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() { 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; - } -} From cb05acf58c0c8c01661271d07924a419f67f1895 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Thu, 7 Feb 2019 01:13:00 -0500 Subject: [PATCH 04/55] Added SRID to GeometryInterface and Geometry models. Updated query builder. --- src/Eloquent/BaseBuilder.php | 14 +- src/Eloquent/SpatialExpression.php | 7 +- src/Types/Factory.php | 16 +-- src/Types/Geometry.php | 20 ++- src/Types/GeometryCollection.php | 9 +- src/Types/GeometryInterface.php | 4 +- src/Types/LineString.php | 8 +- src/Types/MultiLineString.php | 9 +- src/Types/MultiPoint.php | 8 +- src/Types/MultiPolygon.php | 9 +- src/Types/Point.php | 12 +- src/Types/PointCollection.php | 5 +- tests/Integration/IntegrationBaseTestCase.php | 9 +- tests/Integration/Models/GeometryModel.php | 8 ++ .../Models/NoSpatialFieldsModel.php | 5 + tests/Integration/Models/WithSridModel.php | 23 +++ tests/Integration/SridSpatialTest.php | 134 ++++++++++++++++++ 17 files changed, 254 insertions(+), 46 deletions(-) create mode 100644 tests/Integration/Models/WithSridModel.php create mode 100644 tests/Integration/SridSpatialTest.php diff --git a/src/Eloquent/BaseBuilder.php b/src/Eloquent/BaseBuilder.php index 33c0f21c..549e3f98 100644 --- a/src/Eloquent/BaseBuilder.php +++ b/src/Eloquent/BaseBuilder.php @@ -8,10 +8,16 @@ class BaseBuilder extends QueryBuilder { protected 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..e4436885 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(?, ?)'; } public function getSpatialValue() { return $this->value->toWkt(); } + + public function getSrid() + { + return $this->value->getSrid(); + } } 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 c0df8ec3..60b93419 100644 --- a/src/Types/Geometry.php +++ b/src/Types/Geometry.php @@ -19,6 +19,22 @@ 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, '('); @@ -61,11 +77,11 @@ public static function fromWKB($wkb) return $parser->parse($wkb); } - public static function fromWKT($wkt) + public static function fromWKT($wkt, $srid = 0) { $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..43b7b84e 100755 --- a/src/Types/GeometryCollection.php +++ b/src/Types/GeometryCollection.php @@ -23,11 +23,14 @@ 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) { + parent::__construct($srid); + $validated = array_filter($geometries, function ($value) { return $value instanceof GeometryInterface; }); @@ -56,7 +59,7 @@ public function __toString() }, $this->items)); } - public static function fromString($wktArgument) + public static function fromString($wktArgument, $srid = 0) { $geometry_strings = preg_split('/,\s*(?=[A-Za-z])/', $wktArgument); @@ -64,7 +67,7 @@ public static function fromString($wktArgument) $klass = Geometry::getWKTClass($geometry_string); return call_user_func($klass.'::fromWKT', $geometry_string); - }, $geometry_strings)); + }, $geometry_strings), $srid); } public function toArray() 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..c32b3e62 100644 --- a/src/Types/LineString.php +++ b/src/Types/LineString.php @@ -13,21 +13,21 @@ 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..10b4e339 100644 --- a/src/Types/MultiLineString.php +++ b/src/Types/MultiLineString.php @@ -11,8 +11,9 @@ class MultiLineString extends GeometryCollection { /** * @param LineString[] $lineStrings + * @param int $srid */ - public function __construct(array $lineStrings) + public function __construct(array $lineStrings, $srid = 0) { if (count($lineStrings) < 1) { throw new InvalidArgumentException('$lineStrings must contain at least one entry'); @@ -26,7 +27,7 @@ public function __construct(array $lineStrings) throw new InvalidArgumentException('$lineStrings must be an array of LineString'); } - parent::__construct($lineStrings); + parent::__construct($lineStrings, $srid); } public function getLineStrings() @@ -39,14 +40,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() diff --git a/src/Types/MultiPoint.php b/src/Types/MultiPoint.php index fb55f9e8..935866f5 100644 --- a/src/Types/MultiPoint.php +++ b/src/Types/MultiPoint.php @@ -13,14 +13,14 @@ 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 +29,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..63ca02ca 100644 --- a/src/Types/MultiPolygon.php +++ b/src/Types/MultiPolygon.php @@ -11,8 +11,9 @@ class MultiPolygon extends GeometryCollection { /** * @param Polygon[] $polygons + * @param int $srid */ - public function __construct(array $polygons) + public function __construct(array $polygons, $srid = 0) { $validated = array_filter($polygons, function ($value) { return $value instanceof Polygon; @@ -21,7 +22,7 @@ public function __construct(array $polygons) if (count($polygons) !== count($validated)) { throw new InvalidArgumentException('$polygons must be an array of Polygon'); } - parent::__construct($polygons); + parent::__construct($polygons, $srid); } public function toWKT() @@ -36,14 +37,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); } /** diff --git a/src/Types/Point.php b/src/Types/Point.php index 40719af4..6f3a95f4 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..50e16577 100755 --- a/src/Types/PointCollection.php +++ b/src/Types/PointCollection.php @@ -9,8 +9,9 @@ abstract class PointCollection extends GeometryCollection { /** * @param Point[] $points + * @param int $srid */ - public function __construct(array $points) + public function __construct(array $points, $srid = 0) { if (count($points) < 2) { throw new InvalidArgumentException('$points must contain at least two entries'); @@ -24,7 +25,7 @@ public function __construct(array $points) throw new InvalidArgumentException('$points must be an array of Points'); } - parent::__construct($points); + parent::__construct($points, $srid); } public function toPairList() diff --git a/tests/Integration/IntegrationBaseTestCase.php b/tests/Integration/IntegrationBaseTestCase.php index 54d23afa..daad3ab4 100644 --- a/tests/Integration/IntegrationBaseTestCase.php +++ b/tests/Integration/IntegrationBaseTestCase.php @@ -22,7 +22,7 @@ public function createApplication() $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap(); /** - * @param \Illuminate\Config\Repository $config + * @param \Illuminate\Contracts\Config\Repository $config */ $config = $app->config; $config->set('database.default', 'mysql'); @@ -89,12 +89,15 @@ protected function assertDatabaseHas($table, array $data, $connection = null) } } - protected function assertException($exceptionName) + 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); + $this->setExpectedException($exceptionName, $exceptionMessage); } } diff --git a/tests/Integration/Models/GeometryModel.php b/tests/Integration/Models/GeometryModel.php index 0b08186a..f7f95f24 100644 --- a/tests/Integration/Models/GeometryModel.php +++ b/tests/Integration/Models/GeometryModel.php @@ -3,6 +3,14 @@ use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait; use Illuminate\Database\Eloquent\Model; +/** + * Class GeometryModel + * + * @property int id + * @property \Grimzy\LaravelMysqlSpatial\Types\Point location + * @property \Grimzy\LaravelMysqlSpatial\Types\LineString line + * @property \Grimzy\LaravelMysqlSpatial\Types\LineString shape + */ class GeometryModel extends Model { use SpatialTrait; diff --git a/tests/Integration/Models/NoSpatialFieldsModel.php b/tests/Integration/Models/NoSpatialFieldsModel.php index 88e962a6..9215521b 100644 --- a/tests/Integration/Models/NoSpatialFieldsModel.php +++ b/tests/Integration/Models/NoSpatialFieldsModel.php @@ -3,6 +3,11 @@ use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait; use Illuminate\Database\Eloquent\Model; +/** + * Class NoSpatialFieldsModel + * + * @property \Grimzy\LaravelMysqlSpatial\Types\Geometry geometry + */ class NoSpatialFieldsModel extends Model { use SpatialTrait; diff --git a/tests/Integration/Models/WithSridModel.php b/tests/Integration/Models/WithSridModel.php new file mode 100644 index 00000000..e4ce4b9e --- /dev/null +++ b/tests/Integration/Models/WithSridModel.php @@ -0,0 +1,23 @@ +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)))' + ); + $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; +// } +} From bf7888f17516a213a5813b23189d49fcd4d7f14a Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Thu, 7 Feb 2019 23:57:31 -0500 Subject: [PATCH 05/55] Fixed unit tests --- tests/Unit/Eloquent/BuilderTest.php | 38 +++++++ tests/Unit/Eloquent/SpatialTraitTest.php | 28 ++--- tests/Unit/Schema/BlueprintTest.php | 99 +++++++++++++++-- .../Unit/Schema/Grammars/MySqlGrammarTest.php | 102 ++++++++++++++++-- tests/Unit/Types/PointTest.php | 26 +++-- tests/Unit/Types/PolygonTest.php | 6 +- 6 files changed, 253 insertions(+), 46 deletions(-) diff --git a/tests/Unit/Eloquent/BuilderTest.php b/tests/Unit/Eloquent/BuilderTest.php index b77c6c4e..ed730f5a 100644 --- a/tests/Unit/Eloquent/BuilderTest.php +++ b/tests/Unit/Eloquent/BuilderTest.php @@ -72,6 +72,44 @@ public function testUpdatePolygon() $this->builder->update(['polygon' => $polygon]); } + + public function testUpdatePointWithSrid() + { + $point = new Point(1, 2, 4326); + $this->queryBuilder + ->shouldReceive('update') + ->with(['point' => new SpatialExpression($point)]) + ->once(); + + $this->builder->update(['point' => $point]); + } + + 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(); + + $this->builder->update(['linestring' => $linestring]); + } + + 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(); + + $this->builder->update(['polygon' => $polygon]); + } } class TestBuilderModel extends Model diff --git a/tests/Unit/Eloquent/SpatialTraitTest.php b/tests/Unit/Eloquent/SpatialTraitTest.php index 6fb9f207..1c3c0813 100644 --- a/tests/Unit/Eloquent/SpatialTraitTest.php +++ b/tests/Unit/Eloquent/SpatialTraitTest.php @@ -37,7 +37,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(?, ?))', $this->queries[0]); // TODO: assert bindings in query $this->assertTrue($this->model->exists); @@ -45,7 +45,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(?, ?) where `id` = ?', $this->queries[1]); // TODO: assert bindings in query } @@ -60,7 +60,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(?, ?))', $this->queries[0]); // TODO: assert bindings in query $this->assertTrue($this->model->exists); @@ -68,7 +68,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(?, ?) where `id` = ?', $this->queries[1]); // TODO: assert bindings in query } @@ -87,14 +87,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(?, ?))', $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(?, ?) where `id` = ?', $this->queries[1]); // TODO: assert bindings in query } @@ -109,7 +109,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(?, ?))', $this->queries[0]); // TODO: assert bindings in query $this->assertTrue($this->model->exists); @@ -117,7 +117,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(?, ?) where `id` = ?', $this->queries[1]); // TODO: assert bindings in query } @@ -136,14 +136,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(?, ?))', $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(?, ?) where `id` = ?', $this->queries[1]); // TODO: assert bindings in query } @@ -171,14 +171,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(?, ?))', $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(?, ?) where `id` = ?', $this->queries[1]); // TODO: assert bindings in query } @@ -195,14 +195,14 @@ 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(?, ?))', $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(?, ?) where `id` = ?', $this->queries[1]); // TODO: assert bindings in query } diff --git a/tests/Unit/Schema/BlueprintTest.php b/tests/Unit/Schema/BlueprintTest.php index da335520..f8024f96 100644 --- a/tests/Unit/Schema/BlueprintTest.php +++ b/tests/Unit/Schema/BlueprintTest.php @@ -8,6 +8,9 @@ class BlueprintTest extends BaseTestCase { + /** + * @var \Grimzy\LaravelMysqlSpatial\Schema\Blueprint $blueprint + */ protected $blueprint; public function setUp() @@ -22,7 +25,7 @@ public function testGeometry() { $this->blueprint ->shouldReceive('addColumn') - ->with('geometry', 'col') + ->with('geometry', 'col', ['srid' => null]) ->once(); $this->blueprint->geometry('col'); @@ -42,7 +45,7 @@ public function testLinestring() { $this->blueprint ->shouldReceive('addColumn') - ->with('linestring', 'col') + ->with('linestring', 'col', ['srid' => null]) ->once(); $this->blueprint->linestring('col'); @@ -52,7 +55,7 @@ public function testPolygon() { $this->blueprint ->shouldReceive('addColumn') - ->with('polygon', 'col') + ->with('polygon', 'col', ['srid' => null]) ->once(); $this->blueprint->polygon('col'); @@ -62,7 +65,7 @@ public function testMultiPoint() { $this->blueprint ->shouldReceive('addColumn') - ->with('multipoint', 'col') + ->with('multipoint', 'col', ['srid' => null]) ->once(); $this->blueprint->multipoint('col'); @@ -72,17 +75,17 @@ public function testMultiLineString() { $this->blueprint ->shouldReceive('addColumn') - ->with('multilinestring', 'col') + ->with('multilinestring', 'col', ['srid' => null]) ->once(); $this->blueprint->multilinestring('col'); } - public function testMulltiPolygon() + public function testMultiPolygon() { $this->blueprint ->shouldReceive('addColumn') - ->with('multipolygon', 'col') + ->with('multipolygon', 'col', ['srid' => null]) ->once(); $this->blueprint->multipolygon('col'); @@ -92,9 +95,89 @@ public function testGeometryCollection() { $this->blueprint ->shouldReceive('addColumn') - ->with('geometrycollection', 'col') + ->with('geometrycollection', 'col', ['srid' => null]) ->once(); $this->blueprint->geometrycollection('col'); } + + public function testGeometryWithSrid() + { + $this->blueprint + ->shouldReceive('addColumn') + ->with('geometry', 'col', ['srid' => 4326]) + ->once(); + + $this->blueprint->geometry('col', 4326); + } + + public function testPointWithSrid() + { + $this->blueprint + ->shouldReceive('addColumn') + ->with('point', 'col', ['srid' => 4326]) + ->once(); + + $this->blueprint->point('col', 4326); + } + + public function testLinestringWithSrid() + { + $this->blueprint + ->shouldReceive('addColumn') + ->with('linestring', 'col', ['srid' => 4326]) + ->once(); + + $this->blueprint->linestring('col', 4326); + } + + public function testPolygonWithSrid() + { + $this->blueprint + ->shouldReceive('addColumn') + ->with('polygon', 'col', ['srid' => 4326]) + ->once(); + + $this->blueprint->polygon('col', 4326); + } + + public function testMultiPointWithSrid() + { + $this->blueprint + ->shouldReceive('addColumn') + ->with('multipoint', 'col', ['srid' => 4326]) + ->once(); + + $this->blueprint->multipoint('col', 4326); + } + + public function testMultiLineStringWithSrid() + { + $this->blueprint + ->shouldReceive('addColumn') + ->with('multilinestring', 'col', ['srid' => 4326]) + ->once(); + + $this->blueprint->multilinestring('col', 4326); + } + + public function testMultiPolygonWithSrid() + { + $this->blueprint + ->shouldReceive('addColumn') + ->with('multipolygon', 'col', ['srid' => 4326]) + ->once(); + + $this->blueprint->multipolygon('col', 4326); + } + + public function testGeometryCollectionWithSrid() + { + $this->blueprint + ->shouldReceive('addColumn') + ->with('geometrycollection', 'col', ['srid' => 4326]) + ->once(); + + $this->blueprint->geometrycollection('col', 4326); + } } 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/PointTest.php b/tests/Unit/Types/PointTest.php index 257f6a45..77e75339 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,13 @@ 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); 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..9ba83ac8 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,7 @@ public function testFromJson() public function testInvalidGeoJsonException() { - $this->setExpectedException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class); + $this->assertException(\Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException::class); Polygon::fromJson('{"type":"Point","coordinates":[3.4,1.2]}'); } From 4ae8dc71e3a0e062a1b86a47ade6ef6c3ee88287 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 3 Mar 2019 23:11:56 -0500 Subject: [PATCH 06/55] Added order by distance and distance_sphere on spatial fields (Resolves #64): - Updated SpatialTrait - Added new exception: UnknownSpatialFunctionException - Added unit and integration tests - Updated documentation - Moved test variables to phpunit.xml.dist - Added composer dependencies --- README.md | 246 ++++++++++-------- composer.json | 7 + phpunit.xml.dist | 9 +- src/Eloquent/SpatialTrait.php | 36 ++- .../UnknownSpatialFunctionException.php | 7 + tests/Integration/SpatialTest.php | 143 +++++++++- tests/Unit/Eloquent/SpatialTraitTest.php | 35 +++ 7 files changed, 369 insertions(+), 114 deletions(-) create mode 100644 src/Exceptions/UnknownSpatialFunctionException.php diff --git a/README.md b/README.md index d1318946..e5555a48 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ [![Build Status](https://img.shields.io/travis/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://travis-ci.org/grimzy/laravel-mysql-spatial) [![Code Climate](https://img.shields.io/codeclimate/maintainability/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/maintainability) -[![Code Climate](https://img.shields.io/codeclimate/c/grimzy/laravel-mysql-spatial.svg?style=flat-square&colorB=4BCA2A)](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/test_coverage)[![Packagist](https://img.shields.io/packagist/v/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial) +[![Code Climate](https://img.shields.io/codeclimate/c/grimzy/laravel-mysql-spatial.svg?style=flat-square&colorB=4BCA2A)](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/test_coverage) [![Packagist](https://img.shields.io/packagist/v/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial) [![Packagist](https://img.shields.io/packagist/dt/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](LICENSE) -Laravel package to easily work with [MySQL Spatial Data Types](https://dev.mysql.com/doc/refman/5.7/en/spatial-datatypes.html) and [MySQL Spatial Functions](https://dev.mysql.com/doc/refman/5.7/en/spatial-function-reference.html). +Laravel package to easily work with [MySQL Spatial Data Types](https://dev.mysql.com/doc/refman/8.0/en/spatial-type-overview.html) and [MySQL Spatial Functions](https://dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html). Please check the documentation for your MySQL version. MySQL's Extension for Spatial Data was added in MySQL 5.5 but many Spatial Functions were changed in 5.6 and 5.7. @@ -52,11 +52,14 @@ From the command line: php artisan make:migration create_places_table ``` -Then edit the migration you just created by adding at least one spatial data field: +Then edit the migration you just created by adding at least one spatial data field. For Laravel versions prior to 5.5, you can use the Blueprint provided by this package (Grimzy\LaravelMysqlSpatial\Schema\Blueprint): ```php use Illuminate\Database\Migrations\Migration; -use Grimzy\LaravelMysqlSpatial\Schema\Blueprint; +use Illuminate\Database\Schema\Blueprint; + +// For Laravel < 5.5 +// use Grimzy\LaravelMysqlSpatial\Schema\Blueprint; class CreatePlacesTable extends Migration { @@ -114,7 +117,8 @@ use Illuminate\Database\Eloquent\Model; use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait; /** - * @property \Grimzy\LaravelMysqlSpatial\Types\Point $location + * @property \Grimzy\LaravelMysqlSpatial\Types\Point $location + * @property \Grimzy\LaravelMysqlSpatial\Types\Polygon $area */ class Place extends Model { @@ -166,103 +170,19 @@ $lat = $place2->location->getLat(); // 40.7484404 $lng = $place2->location->getLng(); // -73.9878441 ``` -## Migrations - -### Columns - -Available [MySQL Spatial Types](https://dev.mysql.com/doc/refman/5.7/en/spatial-datatypes.html) migration blueprints: - -- - `$table->geometry('column_name');` - -- `$table->point('column_name');` -- `$table->lineString('column_name');` -- `$table->polygon('column_name');` -- `$table->multiPoint('column_name');` -- `$table->multiLineString('column_name');` -- `$table->multiPolygon('column_name');` -- `$table->geometryCollection('column_name');` - -### Spatial indexes - -You can add or drop spatial indexes in your migrations with the `spatialIndex` and `dropSpatialIndex` blueprints. - -- `$table->spatialIndex('column_name');` -- `$table->dropSpatialIndex(['column_name']);` or `$table->dropSpatialIndex('index_name')` - -Note about spatial indexes from the [MySQL documentation](https://dev.mysql.com/doc/refman/5.7/en/creating-spatial-indexes.html): - -> For [`MyISAM`](https://dev.mysql.com/doc/refman/5.7/en/myisam-storage-engine.html) and (as of MySQL 5.7.5) `InnoDB` tables, MySQL can create spatial indexes using syntax similar to that for creating regular indexes, but using the `SPATIAL` keyword. Columns in spatial indexes must be declared `NOT NULL`. - -Also please read this [**important note**](https://laravel.com/docs/5.5/migrations#indexes) regarding Index Lengths in the Laravel 5.6 documentation. - -For example, as a follow up to the [Quickstart](#user-content-create-a-migration); from the command line, generate a new migration: - -```shell -php artisan make:migration update_places_table -``` - -Then edit the migration file that you just created: - -```php -use Illuminate\Database\Migrations\Migration; -use Illuminate\Database\Schema\Blueprint; -use Illuminate\Support\Facades\Schema; - -class UpdatePlacesTable extends Migration -{ - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - // MySQL < 5.7.5: table has to be MyISAM - // \DB::statement('ALTER TABLE places ENGINE = MyISAM'); - - Schema::table('places', function (Blueprint $table) { - // Make sure point is not nullable - $table->point('location')->change(); - - // Add a spatial index on the location field - $table->spatialIndex('location'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::table('places', function (Blueprint $table) { - $table->dropSpatialIndex(['location']); // either an array of column names or the index name - }); - - // \DB::statement('ALTER TABLE places ENGINE = InnoDB'); - - Schema::table('places', function (Blueprint $table) { - $table->point('location')->nullable()->change(); - }); - } -} -``` - ## Geometry classes ### Available Geometry classes -| Grimzy\LaravelMysqlSpatial\Types | OpenGIS Class | -| ---------------------------------------- | ---------------------------------------- | -| `Point($lat, $lng)` | [Point](https://dev.mysql.com/doc/refman/5.7/en/gis-class-point.html) | -| `MultiPoint(Point[])` | [MultiPoint](https://dev.mysql.com/doc/refman/5.7/en/gis-class-multipoint.html) | -| `LineString(Point[])` | [LineString](https://dev.mysql.com/doc/refman/5.7/en/gis-class-linestring.html) | -| `MultiLineString(LineString[])` | [MultiLineString](https://dev.mysql.com/doc/refman/5.7/en/gis-class-multilinestring.html) | -| `Polygon(LineString[])` *([exterior and interior boundaries](https://dev.mysql.com/doc/refman/5.7/en/gis-class-polygon.html))* | [Polygon](https://dev.mysql.com/doc/refman/5.7/en/gis-class-polygon.html) | -| `MultiPolygon(Polygon[])` | [MultiPolygon](https://dev.mysql.com/doc/refman/5.7/en/gis-class-multipolygon.html) | -| `GeometryCollection(Geometry[])` | [GeometryCollection](https://dev.mysql.com/doc/refman/5.7/en/gis-class-geometrycollection.html) | +| Grimzy\LaravelMysqlSpatial\Types | OpenGIS Class | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| `Point($lat, $lng)` | [Point](https://dev.mysql.com/doc/refman/8.0/en/gis-class-point.html) | +| `MultiPoint(Point[])` | [MultiPoint](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multipoint.html) | +| `LineString(Point[])` | [LineString](https://dev.mysql.com/doc/refman/8.0/en/gis-class-linestring.html) | +| `MultiLineString(LineString[])` | [MultiLineString](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multilinestring.html) | +| `Polygon(LineString[])` *([exterior and interior boundaries](https://dev.mysql.com/doc/refman/8.0/en/gis-class-polygon.html))* | [Polygon](https://dev.mysql.com/doc/refman/8.0/en/gis-class-polygon.html) | +| `MultiPolygon(Polygon[])` | [MultiPolygon](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multipolygon.html) | +| `GeometryCollection(Geometry[])` | [GeometryCollection](https://dev.mysql.com/doc/refman/8.0/en/gis-class-geometrycollection.html) | Check out the [Class diagram](https://user-images.githubusercontent.com/1837678/30788608-a5afd894-a16c-11e7-9a51-0a08b331d4c4.png). @@ -290,8 +210,10 @@ for($polygon as $i => $linestring) { ```php // fromWKT($wkt) -$polygon = Polygon::fromWKT('POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))'); +$point = Point::fromWKT('POINT(2 1)'); +$point->toWKT(); // POINT(2 1) +$polygon = Polygon::fromWKT('POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))'); $polygon->toWKT(); // POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)) ``` @@ -299,8 +221,10 @@ $polygon->toWKT(); // POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)) ```php // fromString($wkt) -$polygon = Polygon::fromString('(0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)'); +$point = new Point(1, 2); // lat, lng +(string)$point // lng, lat: 2 1 +$polygon = Polygon::fromString('(0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)'); (string)$polygon; // (0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1) ``` @@ -309,7 +233,7 @@ $polygon = Polygon::fromString('(0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)') The Geometry classes implement [`JsonSerializable`](http://php.net/manual/en/class.jsonserializable.php) and `Illuminate\Contracts\Support\Jsonable` to help serialize into GeoJSON: ```php -$point = new Point(10, 20); +$point = new Point(40.7484404, -73.9878441); json_encode($point); // or $point->toJson(); @@ -329,7 +253,7 @@ json_encode($point); // or $point->toJson(); To deserialize a GeoJSON string into a Geometry class, you can use `Geometry::fromJson($json_string)` : ```php -$locaction = Geometry::fromJson('{"type":"Point","coordinates":[3.4,1.2]}'); +$location = Geometry::fromJson('{"type":"Point","coordinates":[3.4,1.2]}'); $location instanceof Point::class; // true $location->getLat(); // 1.2 $location->getLng()); // 3.4 @@ -354,9 +278,127 @@ Available scopes: - `intersects($geometryColumn, $geometry)` - `overlaps($geometryColumn, $geometry)` - `doesTouch($geometryColumn, $geometry)` +- `orderBySpatial($geometryColumn, $geometry, $orderFunction, $direction = 'asc')` +- `orderByDistance($geometryColumn, ​$geometry, ​$direction = 'asc')` +- `orderByDistanceSphere($geometryColumn, ​$geometry, ​$direction = 'asc')` *Note that behavior and availability of MySQL spatial analysis functions differs in each MySQL version (cf. [documentation](https://dev.mysql.com/doc/refman/5.7/en/spatial-function-reference.html)).* +## Migrations + +For Laravel versions prior to 5.5, you can use the Blueprint provided with this package: `Grimzy\LaravelMysqlSpatial\Schema\Blueprint`. + +```php +use Illuminate\Database\Migrations\Migration; +use Grimzy\LaravelMysqlSpatial\Schema\Blueprint; + +class CreatePlacesTable extends Migration { + // ... +} +``` + +### Columns + +Available [MySQL Spatial Types](https://dev.mysql.com/doc/refman/5.7/en/spatial-datatypes.html) migration blueprints: + +- `$table->geometry('column_name')` +- `$table->point('column_name')` +- `$table->lineString('column_name')` +- `$table->polygon('column_name')` +- `$table->multiPoint('column_name')` +- `$table->multiLineString('column_name')` +- `$table->multiPolygon('column_name')` +- `$table->geometryCollection('column_name')` + +### Spatial indexes + +You can add or drop spatial indexes in your migrations with the `spatialIndex` and `dropSpatialIndex` blueprints. + +- `$table->spatialIndex('column_name')` +- `$table->dropSpatialIndex(['column_name'])` or `$table->dropSpatialIndex('index_name')` + +Note about spatial indexes from the [MySQL documentation](https://dev.mysql.com/doc/refman/5.7/en/creating-spatial-indexes.html): + +> For [`MyISAM`](https://dev.mysql.com/doc/refman/5.7/en/myisam-storage-engine.html) and (as of MySQL 5.7.5) `InnoDB` tables, MySQL can create spatial indexes using syntax similar to that for creating regular indexes, but using the `SPATIAL` keyword. Columns in spatial indexes must be declared `NOT NULL`. + +Also please read this [**important note**](https://laravel.com/docs/5.5/migrations#indexes) regarding Index Lengths in the Laravel 5.6 documentation. + +For example, as a follow up to the [Quickstart](#user-content-create-a-migration); from the command line, generate a new migration: + +```shell +php artisan make:migration update_places_table +``` + +Then edit the migration file that you just created: + +```php +use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; + +class UpdatePlacesTable extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + // MySQL < 5.7.5: table has to be MyISAM + // \DB::statement('ALTER TABLE places ENGINE = MyISAM'); + + Schema::table('places', function (Blueprint $table) { + // Make sure point is not nullable + $table->point('location')->change(); + + // Add a spatial index on the location field + $table->spatialIndex('location'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('places', function (Blueprint $table) { + $table->dropSpatialIndex(['location']); // either an array of column names or the index name + }); + + // \DB::statement('ALTER TABLE places ENGINE = InnoDB'); + + Schema::table('places', function (Blueprint $table) { + $table->point('location')->nullable()->change(); + }); + } +} +``` + +## Tests + +```shell +composer test +# or +composer test:unit +composer test:integration +``` + +Integration tests require a running MySQL database. If you have Docker installed, you can start easily start one: + +```shell +make start_db # starts MySQL 8.0 +# or +make start_db V=5.7 # starts a MySQL 5.7 +``` + +## Contributing + +Recommendations and pull request are most welcome! Pull requests with tests are the best! There are still a lot of MySQL spatial functions to implement or creative ways to use spatial functions. + ## Credits Originally inspired from [njbarrett's Laravel postgis package](https://github.com/njbarrett/laravel-postgis). + diff --git a/composer.json b/composer.json index 4b37e283..9a4efa85 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": [ @@ -11,6 +16,8 @@ ], "require": { "php": ">=5.5", + "ext-pdo": "*", + "ext-json": "*", "illuminate/database": "^5.2", "geo-io/wkb-parser": "^1.0", "jmikola/geojson": "^1.0" 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/SpatialTrait.php b/src/Eloquent/SpatialTrait.php index 5132a622..6c022afb 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. * @@ -106,7 +115,7 @@ public function getSpatialFields() if (property_exists($this, 'spatialFields')) { return $this->spatialFields; } else { - throw new SpatialFieldsNotDefinedException(__CLASS__.' has to define $spatialFields'); + throw new SpatialFieldsNotDefinedException(__CLASS__ . ' has to define $spatialFields'); } } @@ -252,4 +261,29 @@ 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(?)) {$direction}", [ + $geometry->toWkt() + ]); + + 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 @@ +exec(sprintf('DROP DATABASE IF EXISTS %s', $database)); + if ($recreate) { + $pdo->exec(sprintf( + 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s;', + $database, + env('DB_CHARSET', 'utf8mb4'), + env('DB_COLLATION', 'utf8mb4_unicode_ci') + )); + } + } catch (RuntimeException $exception) { + throw $exception; + } + } + /** * Boots the application. * @@ -22,16 +70,17 @@ class SpatialTest extends BaseTestCase */ public function createApplication() { - $app = require __DIR__.'/../../vendor/laravel/laravel/bootstrap/app.php'; + $app = require __DIR__ . '/../../vendor/laravel/laravel/bootstrap/app.php'; $app->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.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', @@ -59,9 +108,9 @@ public function setUp() (new $migrationClass())->up(); }); - //\DB::listen(function($sql) { - // var_dump($sql); - //}); +// \DB::listen(function($sql) { +// var_dump($sql); +// }); } public function tearDown() @@ -105,7 +154,7 @@ private function onMigrations(\Closure $closure, $reverse_sort = false) $fileSystem = new Filesystem(); $classFinder = new Tools\ClassFinder(); - $migrations = $fileSystem->files(__DIR__.'/Migrations'); + $migrations = $fileSystem->files(__DIR__ . '/Migrations'); $reverse_sort ? rsort($migrations, SORT_STRING) : sort($migrations, SORT_STRING); foreach ($migrations as $file) { @@ -323,6 +372,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/Unit/Eloquent/SpatialTraitTest.php b/tests/Unit/Eloquent/SpatialTraitTest.php index 6fb9f207..717e8897 100644 --- a/tests/Unit/Eloquent/SpatialTraitTest.php +++ b/tests/Unit/Eloquent/SpatialTraitTest.php @@ -480,6 +480,41 @@ public function testScopeDoesTouch() $this->assertContains('st_touches(`point`, ST_GeomFromText(?))', $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); + 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(?)) 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(?)) asc', $q->orders[0]['sql']); + $this->assertEquals('POINT(2 1)', $bindings[0]); + } } class TestModel extends Model From 27b89204392334f64df1adb17e467b4dc08cc0e7 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 3 Mar 2019 23:32:02 -0500 Subject: [PATCH 07/55] Updated documentation :book: --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e5555a48..58a58de2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Build Status](https://img.shields.io/travis/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://travis-ci.org/grimzy/laravel-mysql-spatial) [![Code Climate](https://img.shields.io/codeclimate/maintainability/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/maintainability) [![Code Climate](https://img.shields.io/codeclimate/c/grimzy/laravel-mysql-spatial.svg?style=flat-square&colorB=4BCA2A)](https://codeclimate.com/github/grimzy/laravel-mysql-spatial/test_coverage) [![Packagist](https://img.shields.io/packagist/v/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial) -[![Packagist](https://img.shields.io/packagist/dt/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial) +[![Packagist](https://img.shields.io/packagist/dt/grimzy/laravel-mysql-spatial.svg?style=flat-square)](https://packagist.org/packages/grimzy/laravel-mysql-spatial) [![StyleCI](https://github.styleci.io/repos/83766141/shield?branch=master)](https://github.styleci.io/repos/83766141) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](LICENSE) Laravel package to easily work with [MySQL Spatial Data Types](https://dev.mysql.com/doc/refman/8.0/en/spatial-type-overview.html) and [MySQL Spatial Functions](https://dev.mysql.com/doc/refman/8.0/en/spatial-function-reference.html). From 4523cf44c280dd84c3ee2518d8fb1142ed0893bc Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 4 Mar 2019 04:32:13 +0000 Subject: [PATCH 08/55] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Eloquent/SpatialTrait.php | 6 +++--- tests/Integration/SpatialTest.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Eloquent/SpatialTrait.php b/src/Eloquent/SpatialTrait.php index 6c022afb..c1bf101c 100755 --- a/src/Eloquent/SpatialTrait.php +++ b/src/Eloquent/SpatialTrait.php @@ -55,7 +55,7 @@ trait SpatialTrait protected $stOrderFunctions = [ 'distance', - 'distance_sphere' + 'distance_sphere', ]; /** @@ -115,7 +115,7 @@ public function getSpatialFields() if (property_exists($this, 'spatialFields')) { return $this->spatialFields; } else { - throw new SpatialFieldsNotDefinedException(__CLASS__ . ' has to define $spatialFields'); + throw new SpatialFieldsNotDefinedException(__CLASS__.' has to define $spatialFields'); } } @@ -271,7 +271,7 @@ public function scopeOrderBySpatial($query, $geometryColumn, $geometry, $orderFu } $query->orderByRaw("st_{$orderFunction}(`$geometryColumn`, ST_GeomFromText(?)) {$direction}", [ - $geometry->toWkt() + $geometry->toWkt(), ]); return $query; diff --git a/tests/Integration/SpatialTest.php b/tests/Integration/SpatialTest.php index fb482e78..70fa3771 100644 --- a/tests/Integration/SpatialTest.php +++ b/tests/Integration/SpatialTest.php @@ -70,7 +70,7 @@ private static function cleanDatabase($recreate = false) */ public function createApplication() { - $app = require __DIR__ . '/../../vendor/laravel/laravel/bootstrap/app.php'; + $app = require __DIR__.'/../../vendor/laravel/laravel/bootstrap/app.php'; $app->register(SpatialServiceProvider::class); $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap(); @@ -154,7 +154,7 @@ private function onMigrations(\Closure $closure, $reverse_sort = false) $fileSystem = new Filesystem(); $classFinder = new Tools\ClassFinder(); - $migrations = $fileSystem->files(__DIR__ . '/Migrations'); + $migrations = $fileSystem->files(__DIR__.'/Migrations'); $reverse_sort ? rsort($migrations, SORT_STRING) : sort($migrations, SORT_STRING); foreach ($migrations as $file) { From 07fcec900db2afda02a7821d1059ba14202ccb3f Mon Sep 17 00:00:00 2001 From: Chuong Date: Tue, 7 May 2019 05:02:34 +0700 Subject: [PATCH 09/55] add missing class readme.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 58a58de2..bbfe84cc 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,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'; From 235770485bab5eec8dcaf09aaf5e0f33d73c85a1 Mon Sep 17 00:00:00 2001 From: Matan Yadaev Date: Tue, 27 Aug 2019 22:41:29 +0300 Subject: [PATCH 10/55] upgrade laravel --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9a4efa85..e937bd81 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "require-dev": { "phpunit/phpunit": "~4.8||~5.7", "mockery/mockery": "^0.9.9", - "laravel/laravel": "^5.2", + "laravel/laravel": "^5.2|^6.0", "doctrine/dbal": "^2.5", "laravel/browser-kit-testing": "^2.0", "php-coveralls/php-coveralls": "^2.0" From d54ae9967572f4290751db336e86b1390a99e1d4 Mon Sep 17 00:00:00 2001 From: Matan Yadaev Date: Tue, 27 Aug 2019 22:43:49 +0300 Subject: [PATCH 11/55] upgrade illuminate database --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e937bd81..3c22d1c2 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "php": ">=5.5", "ext-pdo": "*", "ext-json": "*", - "illuminate/database": "^5.2", + "illuminate/database": "^5.2|^6.0", "geo-io/wkb-parser": "^1.0", "jmikola/geojson": "^1.0" }, From 8cab456a66a32b6cd738e6ee6fe9afb91494198c Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 2 Sep 2019 12:50:30 -0400 Subject: [PATCH 12/55] Fix Travis build memory exhaustion during composer install --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index be0bd54a..bef7702c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ services: - docker before_install: + - "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - sudo /etc/init.d/mysql stop - make start_db V=$MYSQL_VERSION From 738da3644d003a83746ce97fa72ebd42e49d063b Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 2 Sep 2019 16:50:45 +0000 Subject: [PATCH 13/55] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Schema/Blueprint.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Schema/Blueprint.php b/src/Schema/Blueprint.php index 9507e31e..d061da26 100644 --- a/src/Schema/Blueprint.php +++ b/src/Schema/Blueprint.php @@ -34,7 +34,7 @@ public function point($column, $srid = null) /** * Add a linestring column on the table. * - * @param $column + * @param $column * * @return \Illuminate\Support\Fluent */ @@ -46,7 +46,7 @@ public function lineString($column) /** * Add a polygon column on the table. * - * @param $column + * @param $column * * @return \Illuminate\Support\Fluent */ @@ -58,7 +58,7 @@ public function polygon($column) /** * Add a multipoint column on the table. * - * @param $column + * @param $column * * @return \Illuminate\Support\Fluent */ @@ -70,7 +70,7 @@ public function multiPoint($column) /** * Add a multilinestring column on the table. * - * @param $column + * @param $column * * @return \Illuminate\Support\Fluent */ @@ -82,7 +82,7 @@ public function multiLineString($column) /** * Add a multipolygon column on the table. * - * @param $column + * @param $column * * @return \Illuminate\Support\Fluent */ @@ -94,7 +94,7 @@ public function multiPolygon($column) /** * Add a geometrycollection column on the table. * - * @param $column + * @param $column * * @return \Illuminate\Support\Fluent */ From 451da77d0c80e37ee8fe221a231c9e58b39d7800 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 2 Sep 2019 12:57:08 -0400 Subject: [PATCH 14/55] Typo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bef7702c..9973c293 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ services: - docker before_install: - - "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + - echo "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - sudo /etc/init.d/mysql stop - make start_db V=$MYSQL_VERSION From 0f942632e4a9f2ac9dd1f0f52e48e04e292af177 Mon Sep 17 00:00:00 2001 From: Saif M Date: Sat, 7 Dec 2019 12:30:12 +0600 Subject: [PATCH 15/55] WKB parser now parses the SRID of the given WKB value. --- src/Types/Geometry.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Types/Geometry.php b/src/Types/Geometry.php index 60b93419..50a218ba 100644 --- a/src/Types/Geometry.php +++ b/src/Types/Geometry.php @@ -70,14 +70,23 @@ public static function getWKTClass($value) public static function fromWKB($wkb) { - // mysql adds 4 NUL bytes at the start of the binary + $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 && $srid < 4000) { + $parsed->setSrid($srid); + } + + return $parsed; } - public static function fromWKT($wkt, $srid = 0) + public static function fromWKT($wkt, $srid = null) { $wktArgument = static::getWKTArgument($wkt); From 7d0578b17c92f12e35feffb41c70aac5f055e207 Mon Sep 17 00:00:00 2001 From: Saif M Date: Sat, 7 Dec 2019 13:10:33 +0600 Subject: [PATCH 16/55] Fixes tests. --- tests/Integration/IntegrationBaseTestCase.php | 17 +- tests/Integration/SpatialTest.php | 154 +----------------- tests/Integration/SridSpatialTest.php | 2 +- 3 files changed, 9 insertions(+), 164 deletions(-) diff --git a/tests/Integration/IntegrationBaseTestCase.php b/tests/Integration/IntegrationBaseTestCase.php index daad3ab4..85c495e5 100644 --- a/tests/Integration/IntegrationBaseTestCase.php +++ b/tests/Integration/IntegrationBaseTestCase.php @@ -21,16 +21,13 @@ public function createApplication() $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap(); - /** - * @param \Illuminate\Contracts\Config\Repository $config - */ - $config = $app->config; - $config->set('database.default', 'mysql'); - $config->set('database.connections.mysql.host', env('DB_HOST', '127.0.0.1')); - $config->set('database.connections.mysql.database', 'spatial_test'); - $config->set('database.connections.mysql.username', 'root'); - $config->set('database.connections.mysql.password', ''); - $config->set('database.connections.mysql.modes', [ + $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', diff --git a/tests/Integration/SpatialTest.php b/tests/Integration/SpatialTest.php index 2966e7b3..3b09f02b 100644 --- a/tests/Integration/SpatialTest.php +++ b/tests/Integration/SpatialTest.php @@ -11,161 +11,9 @@ class SpatialTest extends IntegrationBaseTestCase { protected $migrations = [ CreateLocationTable::class, - UpdateLocationTable::class + UpdateLocationTable::class, ]; - protected $after_fix = false; - - public static function setUpBeforeClass() - { - self::cleanDatabase(true); - - parent::setUpBeforeClass(); - } - - public static function tearDownAfterClass() - { - self::cleanDatabase(); - - parent::tearDownAfterClass(); - } - - /** - * Deletes the database. - * - * @param bool $recreate If true, then creates the database after deletion - */ - private static function cleanDatabase($recreate = false) - { - $database = env('DB_DATABASE'); - - try { - $pdo = new PDO( - sprintf( - 'mysql:host=%s;port=%d;', - env('DB_HOST'), - env('DB_PORT') - ), - env('DB_USERNAME'), - env('DB_PASSWORD') - ); - - $pdo->exec(sprintf('DROP DATABASE IF EXISTS %s', $database)); - if ($recreate) { - $pdo->exec(sprintf( - 'CREATE DATABASE %s CHARACTER SET %s COLLATE %s;', - $database, - env('DB_CHARSET', 'utf8mb4'), - env('DB_COLLATION', 'utf8mb4_unicode_ci') - )); - } - } catch (RuntimeException $exception) { - throw $exception; - } - } - - /** - * Boots the application. - * - * @return \Illuminate\Foundation\Application - */ - public function createApplication() - { - $app = require __DIR__.'/../../vendor/laravel/laravel/bootstrap/app.php'; - $app->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) - { - 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); - } - } - public function testSpatialFieldsNotDefinedException() { $geo = new NoSpatialFieldsModel(); diff --git a/tests/Integration/SridSpatialTest.php b/tests/Integration/SridSpatialTest.php index 05b85983..d7778759 100644 --- a/tests/Integration/SridSpatialTest.php +++ b/tests/Integration/SridSpatialTest.php @@ -11,7 +11,7 @@ class SridSpatialTest extends IntegrationBaseTestCase { protected $migrations = [ CreateLocationTable::class, - UpdateLocationTable::class + UpdateLocationTable::class, ]; public function testInsertPointWithSrid() From 2fbd40d49b4095b6ddea5243857809fa9b9e7de2 Mon Sep 17 00:00:00 2001 From: Saif M Date: Sat, 7 Dec 2019 15:55:29 +0600 Subject: [PATCH 17/55] Updates dependency constraints. --- .travis.yml | 6 ++---- composer.json | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9973c293..ab486e9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,12 @@ 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 diff --git a/composer.json b/composer.json index 3c22d1c2..eea3a240 100644 --- a/composer.json +++ b/composer.json @@ -15,10 +15,10 @@ } ], "require": { - "php": ">=5.5", + "php": ">=7.1.3", "ext-pdo": "*", "ext-json": "*", - "illuminate/database": "^5.2|^6.0", + "illuminate/database": "^5.6|^6.0", "geo-io/wkb-parser": "^1.0", "jmikola/geojson": "^1.0" }, From aa2a28a7cfc932746085cca0c68d934f51d3c2c8 Mon Sep 17 00:00:00 2001 From: Saif M Date: Sat, 7 Dec 2019 15:59:40 +0600 Subject: [PATCH 18/55] Removes PHP 7.4 from .travis.yml --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ab486e9f..e9ef9f38 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ php: - '7.1' - '7.2' - '7.3' - - '7.4' env: - MYSQL_VERSION=8.0 From 11a69041b110e8a60b4ec48fd4bf56fb61bc7e05 Mon Sep 17 00:00:00 2001 From: Saif M Date: Sun, 8 Dec 2019 12:21:19 +0600 Subject: [PATCH 19/55] That was a weird condition. --- src/Types/Geometry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Types/Geometry.php b/src/Types/Geometry.php index 50a218ba..df6557a6 100644 --- a/src/Types/Geometry.php +++ b/src/Types/Geometry.php @@ -79,7 +79,7 @@ public static function fromWKB($wkb) /** @var Geometry $parsed */ $parsed = $parser->parse($wkb); - if ($srid >= 0 && $srid < 4000) { + if ($srid >= 0) { $parsed->setSrid($srid); } From c6462ff8b4edf808605cbd4fe718b3430f1b4cdc Mon Sep 17 00:00:00 2001 From: Saif M Date: Sun, 8 Dec 2019 12:24:07 +0600 Subject: [PATCH 20/55] Whops! --- src/Types/Geometry.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Types/Geometry.php b/src/Types/Geometry.php index df6557a6..4a82dcb5 100644 --- a/src/Types/Geometry.php +++ b/src/Types/Geometry.php @@ -79,7 +79,7 @@ public static function fromWKB($wkb) /** @var Geometry $parsed */ $parsed = $parser->parse($wkb); - if ($srid >= 0) { + if ($srid > 0) { $parsed->setSrid($srid); } From e056dc3061f80f467f30ca95d13f87523f1a6777 Mon Sep 17 00:00:00 2001 From: Saif M Date: Sun, 8 Dec 2019 15:09:46 +0600 Subject: [PATCH 21/55] Adds a new option to st_geomfromtext to make sure MySQL understands that the first axis is longitude and the second is latitude. Adds SRID to all the eloquent scopes. --- src/Eloquent/SpatialExpression.php | 2 +- src/Eloquent/SpatialTrait.php | 24 ++++--- tests/Integration/SridSpatialTest.php | 28 ++++---- tests/Unit/Eloquent/SpatialTraitTest.php | 82 ++++++++++++------------ 4 files changed, 72 insertions(+), 64 deletions(-) diff --git a/src/Eloquent/SpatialExpression.php b/src/Eloquent/SpatialExpression.php index e4436885..9224af0f 100644 --- a/src/Eloquent/SpatialExpression.php +++ b/src/Eloquent/SpatialExpression.php @@ -8,7 +8,7 @@ class SpatialExpression extends Expression { public function getValue() { - return 'ST_GeomFromText(?, ?)'; + return "ST_GeomFromText(?, ?, 'axis-order=long-lat')"; } public function getSpatialValue() diff --git a/src/Eloquent/SpatialTrait.php b/src/Eloquent/SpatialTrait.php index c1bf101c..e44788fc 100755 --- a/src/Eloquent/SpatialTrait.php +++ b/src/Eloquent/SpatialTrait.php @@ -132,8 +132,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, ]); @@ -146,8 +147,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; @@ -163,8 +165,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(), ]); } @@ -172,8 +175,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, ]); @@ -186,8 +190,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; @@ -202,8 +207,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(), ]); } @@ -215,8 +221,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; @@ -270,8 +277,9 @@ public function scopeOrderBySpatial($query, $geometryColumn, $geometry, $orderFu throw new UnknownSpatialFunctionException($orderFunction); } - $query->orderByRaw("st_{$orderFunction}(`$geometryColumn`, ST_GeomFromText(?)) {$direction}", [ + $query->orderByRaw("st_{$orderFunction}(`$geometryColumn`, ST_GeomFromText(?, ?, 'axis-order=long-lat')) {$direction}", [ $geometry->toWkt(), + $geometry->getSrid(), ]); return $query; diff --git a/tests/Integration/SridSpatialTest.php b/tests/Integration/SridSpatialTest.php index d7778759..0089c44f 100644 --- a/tests/Integration/SridSpatialTest.php +++ b/tests/Integration/SridSpatialTest.php @@ -113,22 +113,22 @@ public function testInsertPointWithWrongSrid() '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)))' + '(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; -// } + 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/Unit/Eloquent/SpatialTraitTest.php b/tests/Unit/Eloquent/SpatialTraitTest.php index ee35b230..d6aa942b 100644 --- a/tests/Unit/Eloquent/SpatialTraitTest.php +++ b/tests/Unit/Eloquent/SpatialTraitTest.php @@ -37,7 +37,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 +45,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 +60,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 +68,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 +87,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 +109,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 +117,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 +136,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 +171,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,14 +195,14 @@ 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 } @@ -231,9 +231,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 +246,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 +263,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 +278,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 +297,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 +313,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 +329,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 +345,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 +373,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 +386,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 +399,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 +412,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 +425,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 +438,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 +451,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 +464,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,7 +477,7 @@ 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]); } @@ -498,7 +498,7 @@ public function testScopeOrderByDistance() $this->assertNotEmpty($q->orders); $bindings = $q->getRawBindings()['order']; $this->assertNotEmpty($bindings); - $this->assertContains('st_distance(`point`, ST_GeomFromText(?)) asc', $q->orders[0]['sql']); + $this->assertContains('st_distance(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) asc', $q->orders[0]['sql']); $this->assertEquals('POINT(2 1)', $bindings[0]); } @@ -512,7 +512,7 @@ public function testScopeOrderByDistanceSphere() $this->assertNotEmpty($q->orders); $bindings = $q->getRawBindings()['order']; $this->assertNotEmpty($bindings); - $this->assertContains('st_distance_sphere(`point`, ST_GeomFromText(?)) asc', $q->orders[0]['sql']); + $this->assertContains('st_distance_sphere(`point`, ST_GeomFromText(?, ?, \'axis-order=long-lat\')) asc', $q->orders[0]['sql']); $this->assertEquals('POINT(2 1)', $bindings[0]); } } From e4879edc1d39f632f69614b956e09b9ae1ed60d6 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sat, 29 Feb 2020 21:51:20 +0000 Subject: [PATCH 22/55] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Schema/Blueprint.php | 2 +- src/Types/Geometry.php | 3 ++- src/Types/GeometryCollection.php | 2 +- src/Types/MultiLineString.php | 2 +- src/Types/MultiPolygon.php | 2 +- src/Types/Point.php | 2 +- src/Types/PointCollection.php | 2 +- tests/Integration/IntegrationBaseTestCase.php | 3 +-- tests/Integration/MigrationTest.php | 2 +- tests/Integration/Models/GeometryModel.php | 2 +- tests/Integration/Models/NoSpatialFieldsModel.php | 2 +- tests/Integration/Models/WithSridModel.php | 2 +- tests/Integration/SridSpatialTest.php | 13 +++++++------ tests/Unit/Schema/BlueprintTest.php | 2 +- 14 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/Schema/Blueprint.php b/src/Schema/Blueprint.php index 80106578..0a333f06 100644 --- a/src/Schema/Blueprint.php +++ b/src/Schema/Blueprint.php @@ -61,7 +61,7 @@ public function polygon($column, $srid = null) /** * Add a multipoint column on the table. * - * @param string $column + * @param string $column * @param null|int $srid * * @return \Illuminate\Support\Fluent diff --git a/src/Types/Geometry.php b/src/Types/Geometry.php index 4a82dcb5..f840874c 100644 --- a/src/Types/Geometry.php +++ b/src/Types/Geometry.php @@ -26,7 +26,8 @@ public function __construct($srid = 0) $this->srid = (int) $srid; } - public function getSrid() { + public function getSrid() + { return $this->srid; } diff --git a/src/Types/GeometryCollection.php b/src/Types/GeometryCollection.php index 43b7b84e..a1209cce 100755 --- a/src/Types/GeometryCollection.php +++ b/src/Types/GeometryCollection.php @@ -23,7 +23,7 @@ class GeometryCollection extends Geometry implements IteratorAggregate, ArrayAcc /** * @param GeometryInterface[] $geometries - * @param int $srid + * @param int $srid * * @throws InvalidArgumentException */ diff --git a/src/Types/MultiLineString.php b/src/Types/MultiLineString.php index 10b4e339..589bdf07 100644 --- a/src/Types/MultiLineString.php +++ b/src/Types/MultiLineString.php @@ -11,7 +11,7 @@ class MultiLineString extends GeometryCollection { /** * @param LineString[] $lineStrings - * @param int $srid + * @param int $srid */ public function __construct(array $lineStrings, $srid = 0) { diff --git a/src/Types/MultiPolygon.php b/src/Types/MultiPolygon.php index 63ca02ca..a715222c 100644 --- a/src/Types/MultiPolygon.php +++ b/src/Types/MultiPolygon.php @@ -11,7 +11,7 @@ class MultiPolygon extends GeometryCollection { /** * @param Polygon[] $polygons - * @param int $srid + * @param int $srid */ public function __construct(array $polygons, $srid = 0) { diff --git a/src/Types/Point.php b/src/Types/Point.php index 6f3a95f4..d424ec5e 100644 --- a/src/Types/Point.php +++ b/src/Types/Point.php @@ -49,7 +49,7 @@ public static function fromPair($pair, $srid = 0) { list($lng, $lat) = explode(' ', trim($pair, "\t\n\r \x0B()")); - return new static((float) $lat, (float) $lng, (int)$srid); + return new static((float) $lat, (float) $lng, (int) $srid); } public function toWKT() diff --git a/src/Types/PointCollection.php b/src/Types/PointCollection.php index 50e16577..591001c3 100755 --- a/src/Types/PointCollection.php +++ b/src/Types/PointCollection.php @@ -9,7 +9,7 @@ abstract class PointCollection extends GeometryCollection { /** * @param Point[] $points - * @param int $srid + * @param int $srid */ public function __construct(array $points, $srid = 0) { diff --git a/tests/Integration/IntegrationBaseTestCase.php b/tests/Integration/IntegrationBaseTestCase.php index 85c495e5..04634734 100644 --- a/tests/Integration/IntegrationBaseTestCase.php +++ b/tests/Integration/IntegrationBaseTestCase.php @@ -16,7 +16,7 @@ abstract class IntegrationBaseTestCase extends BaseTestCase */ public function createApplication() { - $app = require __DIR__ . '/../../vendor/laravel/laravel/bootstrap/app.php'; + $app = require __DIR__.'/../../vendor/laravel/laravel/bootstrap/app.php'; $app->register(SpatialServiceProvider::class); $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap(); @@ -106,6 +106,5 @@ private function onMigrations(\Closure $closure, $reverse_sort = false) foreach ($migrations as $migrationClass) { $closure($migrationClass); } - } } diff --git a/tests/Integration/MigrationTest.php b/tests/Integration/MigrationTest.php index 3f5f9960..2737e8c3 100644 --- a/tests/Integration/MigrationTest.php +++ b/tests/Integration/MigrationTest.php @@ -6,7 +6,7 @@ class MigrationTest extends IntegrationBaseTestCase { protected $migrations = [ CreateLocationTable::class, - UpdateLocationTable::class + UpdateLocationTable::class, ]; public function testTableWasCreatedWithRightTypes() diff --git a/tests/Integration/Models/GeometryModel.php b/tests/Integration/Models/GeometryModel.php index f7f95f24..1a280ebc 100644 --- a/tests/Integration/Models/GeometryModel.php +++ b/tests/Integration/Models/GeometryModel.php @@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Model; /** - * Class GeometryModel + * Class GeometryModel. * * @property int id * @property \Grimzy\LaravelMysqlSpatial\Types\Point location diff --git a/tests/Integration/Models/NoSpatialFieldsModel.php b/tests/Integration/Models/NoSpatialFieldsModel.php index 9215521b..24b4ca17 100644 --- a/tests/Integration/Models/NoSpatialFieldsModel.php +++ b/tests/Integration/Models/NoSpatialFieldsModel.php @@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Model; /** - * Class NoSpatialFieldsModel + * Class NoSpatialFieldsModel. * * @property \Grimzy\LaravelMysqlSpatial\Types\Geometry geometry */ diff --git a/tests/Integration/Models/WithSridModel.php b/tests/Integration/Models/WithSridModel.php index e4ce4b9e..5a4d83f4 100644 --- a/tests/Integration/Models/WithSridModel.php +++ b/tests/Integration/Models/WithSridModel.php @@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Model; /** - * Class WithSridModel + * Class WithSridModel. * * @property int id * @property \Grimzy\LaravelMysqlSpatial\Types\Point location diff --git a/tests/Integration/SridSpatialTest.php b/tests/Integration/SridSpatialTest.php index 0089c44f..a85e92b0 100644 --- a/tests/Integration/SridSpatialTest.php +++ b/tests/Integration/SridSpatialTest.php @@ -108,17 +108,18 @@ public function testInsertPointWithWrongSrid() $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 ' . + '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 () { + public function testGeometryInsertedHasRightSrid() + { $geo = new WithSridModel(); $geo->location = new Point(1, 2, 3857); $geo->save(); diff --git a/tests/Unit/Schema/BlueprintTest.php b/tests/Unit/Schema/BlueprintTest.php index f8024f96..8ceda39b 100644 --- a/tests/Unit/Schema/BlueprintTest.php +++ b/tests/Unit/Schema/BlueprintTest.php @@ -9,7 +9,7 @@ class BlueprintTest extends BaseTestCase { /** - * @var \Grimzy\LaravelMysqlSpatial\Schema\Blueprint $blueprint + * @var \Grimzy\LaravelMysqlSpatial\Schema\Blueprint */ protected $blueprint; From 3578a932b5bccf3ce8c904e26aadd66d2165f779 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sat, 29 Feb 2020 17:22:14 -0500 Subject: [PATCH 23/55] Fix versions after merging PR --- .travis.yml | 5 ++++- composer.json | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e9ef9f38..b5a50f0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,9 @@ language: php php: + - '5.5' + - '5.6' + - '7.0' - '7.1' - '7.2' - '7.3' @@ -16,7 +19,7 @@ services: - docker before_install: - - echo "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + - 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 diff --git a/composer.json b/composer.json index eea3a240..255a4817 100644 --- a/composer.json +++ b/composer.json @@ -15,17 +15,17 @@ } ], "require": { - "php": ">=7.1.3", + "php": ">=5.5.9", "ext-pdo": "*", "ext-json": "*", - "illuminate/database": "^5.6|^6.0", + "illuminate/database": "^5.2||^6.0", "geo-io/wkb-parser": "^1.0", "jmikola/geojson": "^1.0" }, "require-dev": { "phpunit/phpunit": "~4.8||~5.7", "mockery/mockery": "^0.9.9", - "laravel/laravel": "^5.2|^6.0", + "laravel/laravel": "^5.2||^6.0", "doctrine/dbal": "^2.5", "laravel/browser-kit-testing": "^2.0", "php-coveralls/php-coveralls": "^2.0" From aad71bf2ba4f5db22d8475200dbb696ae7ba5e0c Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sat, 29 Feb 2020 17:38:21 -0500 Subject: [PATCH 24/55] Fixes for Laravel 5.2+/MySQL 8: - Added Srid to MySqlGrammar - Added explicit charset and collation to migrations in tests - Fixed show create command in tests for MySQL 8 - Changed branch alias to 3.0 --- composer.json | 2 +- src/Schema/Grammars/MySqlGrammar.php | 50 +++++++++++++++---- tests/Integration/MigrationTest.php | 4 +- tests/Integration/Migrations/CreateTables.php | 4 ++ 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index 255a4817..2704b83e 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ }, "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0.x-dev" }, "laravel": { "providers": [ diff --git a/src/Schema/Grammars/MySqlGrammar.php b/src/Schema/Grammars/MySqlGrammar.php index 61f015d1..f32004a6 100644 --- a/src/Schema/Grammars/MySqlGrammar.php +++ b/src/Schema/Grammars/MySqlGrammar.php @@ -8,10 +8,25 @@ class MySqlGrammar extends IlluminateMySqlGrammar { + /** + * The possible column modifiers. + * + * @var array + */ +// protected $modifiers = [ +// 'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable', +// 'Default', 'Increment', 'Comment', 'After', 'First', 'Srid', +// ]; + + public function __construct() + { + $this->modifiers[] = 'Srid'; + } + /** * Adds a statement to add a geometry column. * - * @param \Illuminate\Support\Fluent $column + * @param Fluent $column * * @return string */ @@ -23,7 +38,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 +50,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 +62,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 +74,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 +86,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 +98,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 +110,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 +122,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 +131,19 @@ public function compileSpatial(Blueprint $blueprint, Fluent $command) { return $this->compileKey($blueprint, $command, 'spatial'); } + + /** + * Get the SQL for a SRID column modifier. + * + * @param Blueprint $blueprint + * @param Fluent $column + * + * @return string|null + */ + protected function modifySrid(Blueprint $blueprint, Fluent $column) + { + if (!is_null($column->srid) && is_int($column->srid) && $column->srid > 0) { + return ' srid '.$column->srid; + } + } } diff --git a/tests/Integration/MigrationTest.php b/tests/Integration/MigrationTest.php index 2737e8c3..6b740d0f 100644 --- a/tests/Integration/MigrationTest.php +++ b/tests/Integration/MigrationTest.php @@ -14,7 +14,7 @@ public function testTableWasCreatedWithRightTypes() $result = DB::selectOne('SHOW CREATE TABLE geometry'); $expected = 'CREATE TABLE `geometry` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `id` int unsigned NOT NULL AUTO_INCREMENT, `geo` geometry DEFAULT NULL, `location` point NOT NULL, `line` linestring DEFAULT NULL, @@ -38,7 +38,7 @@ public function testTableWasCreatedWithSrid() $result = DB::selectOne('SHOW CREATE TABLE with_srid'); $expected = 'CREATE TABLE `with_srid` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `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, diff --git a/tests/Integration/Migrations/CreateTables.php b/tests/Integration/Migrations/CreateTables.php index 1c668725..fdff4f58 100644 --- a/tests/Integration/Migrations/CreateTables.php +++ b/tests/Integration/Migrations/CreateTables.php @@ -14,6 +14,8 @@ class CreateLocationTable extends Migration public function up() { Schema::create('geometry', function (Blueprint $table) { + $table->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 @@ -32,6 +34,8 @@ public function up() }); 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(); From 8fc001974712efca48597b62df6f40a72c532be0 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sat, 29 Feb 2020 22:38:34 +0000 Subject: [PATCH 25/55] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Schema/Grammars/MySqlGrammar.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Schema/Grammars/MySqlGrammar.php b/src/Schema/Grammars/MySqlGrammar.php index f32004a6..f5b1cac7 100644 --- a/src/Schema/Grammars/MySqlGrammar.php +++ b/src/Schema/Grammars/MySqlGrammar.php @@ -135,8 +135,8 @@ public function compileSpatial(Blueprint $blueprint, Fluent $command) /** * Get the SQL for a SRID column modifier. * - * @param Blueprint $blueprint - * @param Fluent $column + * @param Blueprint $blueprint + * @param Fluent $column * * @return string|null */ From b636f3cd0ae2a9641778512fe67e05f0d598c809 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sat, 29 Feb 2020 18:09:13 -0500 Subject: [PATCH 26/55] Fixed MySqlGrammar::modifySrid() --- src/Schema/Grammars/MySqlGrammar.php | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Schema/Grammars/MySqlGrammar.php b/src/Schema/Grammars/MySqlGrammar.php index f5b1cac7..8bf18984 100644 --- a/src/Schema/Grammars/MySqlGrammar.php +++ b/src/Schema/Grammars/MySqlGrammar.php @@ -8,18 +8,9 @@ class MySqlGrammar extends IlluminateMySqlGrammar { - /** - * The possible column modifiers. - * - * @var array - */ -// protected $modifiers = [ -// 'Unsigned', 'Charset', 'Collate', 'VirtualAs', 'StoredAs', 'Nullable', -// 'Default', 'Increment', 'Comment', 'After', 'First', 'Srid', -// ]; - public function __construct() { + // Enable SRID as a column modifier $this->modifiers[] = 'Srid'; } @@ -135,12 +126,12 @@ public function compileSpatial(Blueprint $blueprint, Fluent $command) /** * Get the SQL for a SRID column modifier. * - * @param Blueprint $blueprint - * @param Fluent $column + * @param \Illuminate\Database\Schema\Blueprint $blueprint + * @param Fluent $column * * @return string|null */ - protected function modifySrid(Blueprint $blueprint, Fluent $column) + 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; From db42f205a78e025e9252882a72f1ef00b9d402ec Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sat, 29 Feb 2020 18:41:50 -0500 Subject: [PATCH 27/55] Fixed MySqlGrammar::__construct() --- src/Schema/Grammars/MySqlGrammar.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Schema/Grammars/MySqlGrammar.php b/src/Schema/Grammars/MySqlGrammar.php index 8bf18984..9afe4513 100644 --- a/src/Schema/Grammars/MySqlGrammar.php +++ b/src/Schema/Grammars/MySqlGrammar.php @@ -8,10 +8,14 @@ class MySqlGrammar extends IlluminateMySqlGrammar { + const COLUMN_MODIFIER_SRID = 'Srid'; + public function __construct() { // Enable SRID as a column modifier - $this->modifiers[] = 'Srid'; + if (!in_array(self::COLUMN_MODIFIER_SRID, $this->modifiers)) { + $this->modifiers[] = self::COLUMN_MODIFIER_SRID; + } } /** From 6cb91540652bff34b00cf1f560e94110d5039ee9 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 1 Mar 2020 19:43:19 -0500 Subject: [PATCH 28/55] Fixed validation when creating GeometryCollections --- src/Types/GeometryCollection.php | 55 +++++++++++++++++---- src/Types/LineString.php | 7 +++ src/Types/MultiLineString.php | 30 +++++------ src/Types/MultiPolygon.php | 25 +++++----- src/Types/PointCollection.php | 25 ++-------- tests/Unit/BaseTestCase.php | 6 ++- tests/Unit/Eloquent/SpatialTraitTest.php | 5 +- tests/Unit/Types/GeometryCollectionTest.php | 10 +++- tests/Unit/Types/GeometryTest.php | 5 +- tests/Unit/Types/MultiLineStringTest.php | 15 ++++-- tests/Unit/Types/MultiPointTest.php | 20 ++++++-- tests/Unit/Types/MultiPolygonTest.php | 10 +++- 12 files changed, 135 insertions(+), 78 deletions(-) diff --git a/src/Types/GeometryCollection.php b/src/Types/GeometryCollection.php index 2e1f0321..04216df3 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 = 1; + + /** + * The class of the items in the collection. + * + * @var string + */ + protected $collectionItemType = GeometryInterface::class; + /** * The items contained in the spatial collection. * @@ -28,13 +42,7 @@ class GeometryCollection extends Geometry implements IteratorAggregate, ArrayAcc */ public function __construct(array $geometries) { - $validated = array_filter($geometries, function ($value) { - return $value instanceof GeometryInterface; - }); - - if (count($geometries) !== count($validated)) { - throw new InvalidArgumentException('$geometries must be an array of Geometry objects'); - } + $this->validateItems($geometries); $this->items = $geometries; } @@ -89,9 +97,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 +148,33 @@ public function jsonSerialize() return new \GeoJson\Geometry\GeometryCollection($geometries); } + + /** + * Checks + * @param array $items + */ + protected function validateItems(array $items) { + $this->validateItemCount($items); + + foreach ($items as $item) { + $this->validateItemType($item); + } + } + + 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 + )); + } + } + + 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/LineString.php b/src/Types/LineString.php index 02097edd..8c226444 100644 --- a/src/Types/LineString.php +++ b/src/Types/LineString.php @@ -8,6 +8,13 @@ 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()); diff --git a/src/Types/MultiLineString.php b/src/Types/MultiLineString.php index dd3342fd..a4199a5b 100644 --- a/src/Types/MultiLineString.php +++ b/src/Types/MultiLineString.php @@ -10,24 +10,18 @@ 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() { @@ -58,9 +52,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/MultiPolygon.php b/src/Types/MultiPolygon.php index aba2b6d1..9cc48a19 100644 --- a/src/Types/MultiPolygon.php +++ b/src/Types/MultiPolygon.php @@ -10,19 +10,18 @@ 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 = 0; - 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() { @@ -93,9 +92,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'); - } + self::validateItemType($value); parent::offsetSet($offset, $value); } diff --git a/src/Types/PointCollection.php b/src/Types/PointCollection.php index af586b28..83aea0c9 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'); - } + self::validateItemType($value); parent::offsetSet($offset, $value); } diff --git a/tests/Unit/BaseTestCase.php b/tests/Unit/BaseTestCase.php index 44f323c5..ed589673 100644 --- a/tests/Unit/BaseTestCase.php +++ b/tests/Unit/BaseTestCase.php @@ -7,12 +7,14 @@ public function tearDown() Mockery::close(); } - protected function assertException($exceptionName) + protected function assertException($exceptionName, $exceptionMessage = 'uoioi', $exceptionCode = 0) { if (method_exists(parent::class, 'expectException')) { parent::expectException($exceptionName); + parent::expectExceptionMessage($exceptionMessage); + parent::expectExceptionCode($exceptionCode); } else { - $this->setExpectedException($exceptionName); + $this->setExpectedException($exceptionName, $exceptionMessage, $exceptionCode); } } } diff --git a/tests/Unit/Eloquent/SpatialTraitTest.php b/tests/Unit/Eloquent/SpatialTraitTest.php index 717e8897..f59913f3 100644 --- a/tests/Unit/Eloquent/SpatialTraitTest.php +++ b/tests/Unit/Eloquent/SpatialTraitTest.php @@ -484,7 +484,10 @@ public function testScopeDoesTouch() public function testScopeOrderBySpatialThrowsExceptionWhenFunctionNotRegistered() { $point = new Point(1, 2); - $this->assertException(\Grimzy\LaravelMysqlSpatial\Exceptions\UnknownSpatialFunctionException::class); + $this->assertException( + \Grimzy\LaravelMysqlSpatial\Exceptions\UnknownSpatialFunctionException::class, + 'does-not-exist' + ); TestModel::orderBySpatial('point', $point, 'does-not-exist'); } diff --git a/tests/Unit/Types/GeometryCollectionTest.php b/tests/Unit/Types/GeometryCollectionTest.php index 07759c5f..8f5b9081 100644 --- a/tests/Unit/Types/GeometryCollectionTest.php +++ b/tests/Unit/Types/GeometryCollectionTest.php @@ -35,7 +35,10 @@ public function testJsonSerialize() 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 +88,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; } diff --git a/tests/Unit/Types/GeometryTest.php b/tests/Unit/Types/GeometryTest.php index 8bd765a7..e51022d5 100644 --- a/tests/Unit/Types/GeometryTest.php +++ b/tests/Unit/Types/GeometryTest.php @@ -32,7 +32,10 @@ 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))'); } diff --git a/tests/Unit/Types/MultiLineStringTest.php b/tests/Unit/Types/MultiLineStringTest.php index df7b42e4..563ecbd1 100644 --- a/tests/Unit/Types/MultiLineStringTest.php +++ b/tests/Unit/Types/MultiLineStringTest.php @@ -59,13 +59,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 +104,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..6e94af87 100644 --- a/tests/Unit/Types/MultiPointTest.php +++ b/tests/Unit/Types/MultiPointTest.php @@ -58,13 +58,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 +93,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 +141,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..42f6d607 100644 --- a/tests/Unit/Types/MultiPolygonTest.php +++ b/tests/Unit/Types/MultiPolygonTest.php @@ -77,7 +77,10 @@ public function testJsonSerialize() public function testInvalidArgumentExceptionNotArrayOfLineString() { - $this->assertException(InvalidArgumentException::class); + $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 +104,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; } From 5f72bd1e02c9b5aebc266d68c929e7b9e2f0f834 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 2 Mar 2020 00:43:46 +0000 Subject: [PATCH 29/55] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Types/GeometryCollection.php | 13 +++++++++---- src/Types/MultiLineString.php | 1 - src/Types/MultiPolygon.php | 1 - 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Types/GeometryCollection.php b/src/Types/GeometryCollection.php index 04216df3..f2ff8839 100755 --- a/src/Types/GeometryCollection.php +++ b/src/Types/GeometryCollection.php @@ -150,10 +150,12 @@ public function jsonSerialize() } /** - * Checks + * Checks. + * * @param array $items */ - protected function validateItems(array $items) { + protected function validateItems(array $items) + { $this->validateItemCount($items); foreach ($items as $item) { @@ -161,16 +163,19 @@ protected function validateItems(array $items) { } } - protected function validateItemCount(array $items) { + 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 )); } } - protected function validateItemType($item) { + 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/MultiLineString.php b/src/Types/MultiLineString.php index a4199a5b..c219ebd9 100644 --- a/src/Types/MultiLineString.php +++ b/src/Types/MultiLineString.php @@ -5,7 +5,6 @@ use GeoJson\GeoJson; use GeoJson\Geometry\MultiLineString as GeoJsonMultiLineString; use Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException; -use InvalidArgumentException; class MultiLineString extends GeometryCollection { diff --git a/src/Types/MultiPolygon.php b/src/Types/MultiPolygon.php index 9cc48a19..915e8c06 100644 --- a/src/Types/MultiPolygon.php +++ b/src/Types/MultiPolygon.php @@ -5,7 +5,6 @@ use GeoJson\GeoJson; use GeoJson\Geometry\MultiPolygon as GeoJsonMultiPolygon; use Grimzy\LaravelMysqlSpatial\Exceptions\InvalidGeoJsonException; -use InvalidArgumentException; class MultiPolygon extends GeometryCollection { From 7d0e7f29d43f03da82f11164196d2cda0db3338f Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sat, 29 Feb 2020 17:22:14 -0500 Subject: [PATCH 30/55] Fix versions after merging PR --- .travis.yml | 2 +- composer.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9973c293..22ee6ce7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ services: - docker before_install: - - echo "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + - 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 diff --git a/composer.json b/composer.json index 3c22d1c2..255a4817 100644 --- a/composer.json +++ b/composer.json @@ -15,17 +15,17 @@ } ], "require": { - "php": ">=5.5", + "php": ">=5.5.9", "ext-pdo": "*", "ext-json": "*", - "illuminate/database": "^5.2|^6.0", + "illuminate/database": "^5.2||^6.0", "geo-io/wkb-parser": "^1.0", "jmikola/geojson": "^1.0" }, "require-dev": { "phpunit/phpunit": "~4.8||~5.7", "mockery/mockery": "^0.9.9", - "laravel/laravel": "^5.2|^6.0", + "laravel/laravel": "^5.2||^6.0", "doctrine/dbal": "^2.5", "laravel/browser-kit-testing": "^2.0", "php-coveralls/php-coveralls": "^2.0" From 472f5c105fe9c83f0e03f21c751735a82224b868 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Tue, 3 Mar 2020 00:29:28 -0500 Subject: [PATCH 31/55] Remove unneeded $minimumCollectionItems in MultiLineString type --- src/Types/MultiLineString.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Types/MultiLineString.php b/src/Types/MultiLineString.php index c219ebd9..e2ee4a9b 100644 --- a/src/Types/MultiLineString.php +++ b/src/Types/MultiLineString.php @@ -8,13 +8,6 @@ class MultiLineString extends GeometryCollection { - /** - * The minimum number of items required to create this collection. - * - * @var int - */ - protected $minimumCollectionItems = 1; - /** * The class of the items in the collection. * From 7c431e6577e5cacece324cf129c839e9123b307a Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Tue, 3 Mar 2020 00:40:34 -0500 Subject: [PATCH 32/55] Doc :book: --- src/Types/GeometryCollection.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Types/GeometryCollection.php b/src/Types/GeometryCollection.php index f2ff8839..28251a38 100755 --- a/src/Types/GeometryCollection.php +++ b/src/Types/GeometryCollection.php @@ -150,7 +150,7 @@ public function jsonSerialize() } /** - * Checks. + * Checks whether the items are valid to create this collection. * * @param array $items */ @@ -163,6 +163,13 @@ protected function validateItems(array $items) } } + /** + * 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) { @@ -174,6 +181,13 @@ protected function validateItemCount(array $items) } } + /** + * Checks the type of the items in the array. + * + * @param $item + * + * @see $collectionItemType + */ protected function validateItemType($item) { if (!$item instanceof $this->collectionItemType) { From f1ca3e6cb64d1edf588cc4512a04ba4c709aad27 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Tue, 3 Mar 2020 00:41:52 -0500 Subject: [PATCH 33/55] Oops :laughing: --- src/Types/MultiLineString.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Types/MultiLineString.php b/src/Types/MultiLineString.php index e2ee4a9b..64707d6a 100644 --- a/src/Types/MultiLineString.php +++ b/src/Types/MultiLineString.php @@ -44,7 +44,7 @@ public function __toString() public function offsetSet($offset, $value) { - $this::validateItemType($value); + $this->validateItemType($value); parent::offsetSet($offset, $value); } From 2eb1c72089cd5c1b098606af5a2b4dd43afd7ed8 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Tue, 3 Mar 2020 00:44:07 -0500 Subject: [PATCH 34/55] More Oops :laughing: :laughing: :laughing: --- src/Types/MultiPolygon.php | 2 +- src/Types/PointCollection.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Types/MultiPolygon.php b/src/Types/MultiPolygon.php index 915e8c06..cb63824f 100644 --- a/src/Types/MultiPolygon.php +++ b/src/Types/MultiPolygon.php @@ -91,7 +91,7 @@ protected static function assembleParts(array $parts) public function offsetSet($offset, $value) { - self::validateItemType($value); + $this->validateItemType($value); parent::offsetSet($offset, $value); } diff --git a/src/Types/PointCollection.php b/src/Types/PointCollection.php index 83aea0c9..30d1b8de 100755 --- a/src/Types/PointCollection.php +++ b/src/Types/PointCollection.php @@ -23,7 +23,7 @@ public function toPairList() public function offsetSet($offset, $value) { - self::validateItemType($value); + $this->validateItemType($value); parent::offsetSet($offset, $value); } From 35f8031af220b79306e5e09744956a322f3c7877 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Tue, 3 Mar 2020 00:46:01 -0500 Subject: [PATCH 35/55] Last Oops --- tests/Unit/BaseTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Unit/BaseTestCase.php b/tests/Unit/BaseTestCase.php index ed589673..0b53a414 100644 --- a/tests/Unit/BaseTestCase.php +++ b/tests/Unit/BaseTestCase.php @@ -7,7 +7,7 @@ public function tearDown() Mockery::close(); } - protected function assertException($exceptionName, $exceptionMessage = 'uoioi', $exceptionCode = 0) + protected function assertException($exceptionName, $exceptionMessage = '', $exceptionCode = 0) { if (method_exists(parent::class, 'expectException')) { parent::expectException($exceptionName); From 662d169195e4c9d84120a30f1b93c8b48cd4ca31 Mon Sep 17 00:00:00 2001 From: John Ryan Camatog Date: Wed, 4 Mar 2020 23:58:50 +0800 Subject: [PATCH 36/55] Support Laravel 7 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3c22d1c2..326c78d6 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "require-dev": { "phpunit/phpunit": "~4.8||~5.7", "mockery/mockery": "^0.9.9", - "laravel/laravel": "^5.2|^6.0", + "laravel/laravel": "^5.2|^6.0|^7.0", "doctrine/dbal": "^2.5", "laravel/browser-kit-testing": "^2.0", "php-coveralls/php-coveralls": "^2.0" From 09a03532a54d5284982021cb2b08692b26704465 Mon Sep 17 00:00:00 2001 From: John Ryan Camatog Date: Thu, 5 Mar 2020 00:03:26 +0800 Subject: [PATCH 37/55] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 326c78d6..2420fa26 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "php": ">=5.5", "ext-pdo": "*", "ext-json": "*", - "illuminate/database": "^5.2|^6.0", + "illuminate/database": "^5.2|^6.0|^7.0", "geo-io/wkb-parser": "^1.0", "jmikola/geojson": "^1.0" }, From 2c1b058cd2b4aa0c2138746fccb85d142253879c Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Tue, 3 Mar 2020 02:31:43 -0500 Subject: [PATCH 38/55] Fix build --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9973c293..22ee6ce7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ services: - docker before_install: - - echo "memory_limit=2G" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + - 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 From c1c162e832d97b3e1672794c03fed69c95eb51c3 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Fri, 6 Mar 2020 18:33:13 +0000 Subject: [PATCH 39/55] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Eloquent/SpatialTrait.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Eloquent/SpatialTrait.php b/src/Eloquent/SpatialTrait.php index c1bf101c..e08a476d 100755 --- a/src/Eloquent/SpatialTrait.php +++ b/src/Eloquent/SpatialTrait.php @@ -75,7 +75,9 @@ protected function newBaseQueryBuilder() $connection = $this->getConnection(); return new BaseBuilder( - $connection, $connection->getQueryGrammar(), $connection->getPostProcessor() + $connection, + $connection->getQueryGrammar(), + $connection->getPostProcessor() ); } From 881955c2e3e97e9e5d540458a5ad9a87c367cda1 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 8 Mar 2020 20:21:29 +0000 Subject: [PATCH 40/55] Apply fixes from StyleCI [ci skip] [skip ci] --- src/Types/GeometryCollection.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Types/GeometryCollection.php b/src/Types/GeometryCollection.php index 28251a38..b199feff 100755 --- a/src/Types/GeometryCollection.php +++ b/src/Types/GeometryCollection.php @@ -176,7 +176,10 @@ protected function validateItemCount(array $items) $entries = $this->minimumCollectionItems === 1 ? 'entry' : 'entries'; throw new InvalidArgumentException(sprintf( - '%s must contain at least %d %s', get_class($this), $this->minimumCollectionItems, $entries + '%s must contain at least %d %s', + get_class($this), + $this->minimumCollectionItems, + $entries )); } } @@ -192,7 +195,9 @@ 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 + '%s must be a collection of %s', + get_class($this), + $this->collectionItemType )); } } From 534dddc9d2f43550618196c4bfa4f4751acbb983 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 8 Mar 2020 17:31:46 -0400 Subject: [PATCH 41/55] Set $minimumCollectionItems to 0 for GeometryCollection and MultiPolygon. Adjusted child classes. Added/update tests. --- src/Types/GeometryCollection.php | 6 +++++- src/Types/MultiLineString.php | 7 +++++++ src/Types/MultiPoint.php | 7 +++++++ src/Types/MultiPolygon.php | 2 +- tests/Integration/SpatialTest.php | 11 +++++++++++ tests/Unit/Types/GeometryCollectionTest.php | 22 +++++++++++++++++++++ tests/Unit/Types/MultiPolygonTest.php | 11 ++++++++++- 7 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/Types/GeometryCollection.php b/src/Types/GeometryCollection.php index 28251a38..8410f160 100755 --- a/src/Types/GeometryCollection.php +++ b/src/Types/GeometryCollection.php @@ -19,7 +19,7 @@ class GeometryCollection extends Geometry implements IteratorAggregate, ArrayAcc * * @var int */ - protected $minimumCollectionItems = 1; + protected $minimumCollectionItems = 0; /** * The class of the items in the collection. @@ -66,6 +66,10 @@ public function __toString() public static function fromString($wktArgument) { + if (empty($wktArgument)) { + return new static([]); + } + $geometry_strings = preg_split('/,\s*(?=[A-Za-z])/', $wktArgument); return new static(array_map(function ($geometry_string) { diff --git a/src/Types/MultiLineString.php b/src/Types/MultiLineString.php index 64707d6a..dd815ebf 100644 --- a/src/Types/MultiLineString.php +++ b/src/Types/MultiLineString.php @@ -8,6 +8,13 @@ class MultiLineString extends GeometryCollection { + /** + * The minimum number of items required to create this collection. + * + * @var int + */ + protected $minimumCollectionItems = 1; + /** * The class of the items in the collection. * diff --git a/src/Types/MultiPoint.php b/src/Types/MultiPoint.php index fb55f9e8..eafa7c0e 100644 --- a/src/Types/MultiPoint.php +++ b/src/Types/MultiPoint.php @@ -8,6 +8,13 @@ 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); diff --git a/src/Types/MultiPolygon.php b/src/Types/MultiPolygon.php index cb63824f..0a5b6784 100644 --- a/src/Types/MultiPolygon.php +++ b/src/Types/MultiPolygon.php @@ -13,7 +13,7 @@ class MultiPolygon extends GeometryCollection * * @var int */ - protected $minimumCollectionItems = 0; + protected $minimumCollectionItems = 1; /** * The class of the items in the collection. diff --git a/tests/Integration/SpatialTest.php b/tests/Integration/SpatialTest.php index 70fa3771..415d8557 100644 --- a/tests/Integration/SpatialTest.php +++ b/tests/Integration/SpatialTest.php @@ -242,6 +242,17 @@ 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]); + } + public function testUpdate() { $geo = new GeometryModel(); diff --git a/tests/Unit/Types/GeometryCollectionTest.php b/tests/Unit/Types/GeometryCollectionTest.php index 8f5b9081..4576a77b 100644 --- a/tests/Unit/Types/GeometryCollectionTest.php +++ b/tests/Unit/Types/GeometryCollectionTest.php @@ -33,6 +33,28 @@ 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( diff --git a/tests/Unit/Types/MultiPolygonTest.php b/tests/Unit/Types/MultiPolygonTest.php index 42f6d607..a37df382 100644 --- a/tests/Unit/Types/MultiPolygonTest.php +++ b/tests/Unit/Types/MultiPolygonTest.php @@ -75,7 +75,16 @@ 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, + 'Grimzy\LaravelMysqlSpatial\Types\MultiPolygon must contain at least 1 entry' + ); + $multipolygon = new MultiPolygon([]); + } + + public function testInvalidArgumentExceptionNotArrayOfPolygon() { $this->assertException( InvalidArgumentException::class, From acd15ea7f30ce1d7d269417a9879be29e2c25843 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 8 Mar 2020 18:08:25 -0400 Subject: [PATCH 42/55] Set same OR --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 32675ce0..f9ac9e4f 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "jmikola/geojson": "^1.0" }, "require-dev": { - "phpunit/phpunit": "~4.8||~5.7", + "phpunit/phpunit": "~4.8|~5.7", "mockery/mockery": "^0.9.9", "laravel/laravel": "^5.2|^6.0|^7.0", "doctrine/dbal": "^2.5", From ac69ee9d2b7c87914b4155ab97e0d6eb0d53c205 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 8 Mar 2020 20:58:58 -0400 Subject: [PATCH 43/55] Fix issue where the WKB of empty GeometryCollections was not getting parsed --- src/Eloquent/SpatialTrait.php | 2 +- tests/Integration/Models/GeometryModel.php | 2 +- tests/Integration/SpatialTest.php | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Eloquent/SpatialTrait.php b/src/Eloquent/SpatialTrait.php index e08a476d..da6c2a95 100755 --- a/src/Eloquent/SpatialTrait.php +++ b/src/Eloquent/SpatialTrait.php @@ -104,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); } } diff --git a/tests/Integration/Models/GeometryModel.php b/tests/Integration/Models/GeometryModel.php index 0b08186a..0565fd35 100644 --- a/tests/Integration/Models/GeometryModel.php +++ b/tests/Integration/Models/GeometryModel.php @@ -9,5 +9,5 @@ class GeometryModel extends Model protected $table = 'geometry'; - protected $spatialFields = ['location', 'line']; + protected $spatialFields = ['location', 'line', 'multi_geometries']; } diff --git a/tests/Integration/SpatialTest.php b/tests/Integration/SpatialTest.php index 415d8557..9fbb6a3b 100644 --- a/tests/Integration/SpatialTest.php +++ b/tests/Integration/SpatialTest.php @@ -251,6 +251,9 @@ public function testInsertEmptyGeometryCollection() $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); } public function testUpdate() From 8818d7a0eb3140354678f2f6b8f36ad1f816eafb Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 8 Mar 2020 21:35:01 -0400 Subject: [PATCH 44/55] Asserting empty multi geometry count --- tests/Integration/SpatialTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Integration/SpatialTest.php b/tests/Integration/SpatialTest.php index 9fbb6a3b..87f92a2b 100644 --- a/tests/Integration/SpatialTest.php +++ b/tests/Integration/SpatialTest.php @@ -254,6 +254,7 @@ public function testInsertEmptyGeometryCollection() $geo2 = GeometryModel::find($geo->id); $this->assertInstanceOf(GeometryCollection::class, $geo2->multi_geometries); + $this->assertEquals(0, count($geo2->multi_geometries)); } public function testUpdate() From b9e6f4a8d64fb080a770a98ca1bec2b82e73b188 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 9 Mar 2020 02:54:05 +0000 Subject: [PATCH 45/55] Apply fixes from StyleCI [ci skip] [skip ci] --- tests/Integration/SridSpatialTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Integration/SridSpatialTest.php b/tests/Integration/SridSpatialTest.php index a85e92b0..f57c6cb2 100644 --- a/tests/Integration/SridSpatialTest.php +++ b/tests/Integration/SridSpatialTest.php @@ -107,7 +107,8 @@ public function testInsertPointWithWrongSrid() $geo = new WithSridModel(); $geo->location = new Point(1, 2); - $this->assertException(Illuminate\Database\QueryException::class, + $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. '. From eb01c85c29b36c9d0ce95557ecb08d33211b07ed Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 9 Mar 2020 00:10:20 -0400 Subject: [PATCH 46/55] Updated unit tests --- Makefile | 2 +- tests/Unit/Types/PointTest.php | 5 ++++- tests/Unit/Types/PolygonTest.php | 5 ++++- 3 files changed, 9 insertions(+), 3 deletions(-) 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/tests/Unit/Types/PointTest.php b/tests/Unit/Types/PointTest.php index 77e75339..518a8a56 100644 --- a/tests/Unit/Types/PointTest.php +++ b/tests/Unit/Types/PointTest.php @@ -69,7 +69,10 @@ public function testFromJson() public function testInvalidGeoJsonException() { - $this->assertException(\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 9ba83ac8..aaab437b 100644 --- a/tests/Unit/Types/PolygonTest.php +++ b/tests/Unit/Types/PolygonTest.php @@ -56,7 +56,10 @@ public function testFromJson() public function testInvalidGeoJsonException() { - $this->assertException(\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]}'); } From 9bbadd716b5cc35718cc3dfecf81a93d9f07416d Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 13 Apr 2020 22:18:28 -0400 Subject: [PATCH 47/55] Updated doc :book: --- README.md | 106 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index bbfe84cc..d5e61519 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,8 @@ Please check the documentation for your MySQL version. MySQL's Extension for Spa **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 +- **`3.x.x`: MySQL 8.0 with SRID support (Current branch)** 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 +22,20 @@ 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 +``` + +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`: @@ -80,6 +87,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(); + // }); } /** @@ -158,11 +178,37 @@ $place1->area = new Polygon([new LineString([ new Point(40.74894149554006, -73.98615270853043) ])]); $place1->save(); +``` + +Or if your database fields were created with a specific SRID: + +```php +use Grimzy\LaravelMysqlSpatial\Types\Point; +use Grimzy\LaravelMysqlSpatial\Types\Polygon; +use Grimzy\LaravelMysqlSpatial\Types\LineString; + +$place1 = new Place(); +$place1->name = 'Empire State Building'; -$place1->area = new Polygon(); +// saving a point with SRID 4326 (WGS84 spheroid) +$place1->location = new Point(40.7484404, -73.9878441, 4326); // (lat, lng, srid) +$place1->save(); +// saving a polygon with SRID 4326 (WGS84 spheroid) +$place1->area = new Polygon([new LineString([ + new Point(40.74894149554006, -73.98615270853043), + new Point(40.74848633046773, -73.98648262023926), + new Point(40.747925497790725, -73.9851602911949), + new Point(40.74837050671544, -73.98482501506805), + new Point(40.74894149554006, -73.98615270853043) +])], 4326); +$place1->save(); ``` +> **Note**: When saving collection Geometries (`LineString`, `Polygon`, `MultiPoint`, `MultiLineString`, and `GeometryCollection`), only the top-most geometry should have an SRID set in the constructor. +> +> In the example above, when creating a `new Polygon()`, we only set the SRID on the `Polygon` and use the default for the `LineString` and the `Point` objects. + ### Retrieving a model ```php @@ -177,13 +223,13 @@ $lng = $place2->location->getLng(); // -73.9878441 | Grimzy\LaravelMysqlSpatial\Types | OpenGIS Class | | ------------------------------------------------------------ | ------------------------------------------------------------ | -| `Point($lat, $lng)` | [Point](https://dev.mysql.com/doc/refman/8.0/en/gis-class-point.html) | -| `MultiPoint(Point[])` | [MultiPoint](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multipoint.html) | -| `LineString(Point[])` | [LineString](https://dev.mysql.com/doc/refman/8.0/en/gis-class-linestring.html) | -| `MultiLineString(LineString[])` | [MultiLineString](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multilinestring.html) | -| `Polygon(LineString[])` *([exterior and interior boundaries](https://dev.mysql.com/doc/refman/8.0/en/gis-class-polygon.html))* | [Polygon](https://dev.mysql.com/doc/refman/8.0/en/gis-class-polygon.html) | -| `MultiPolygon(Polygon[])` | [MultiPolygon](https://dev.mysql.com/doc/refman/8.0/en/gis-class-multipolygon.html) | -| `GeometryCollection(Geometry[])` | [GeometryCollection](https://dev.mysql.com/doc/refman/8.0/en/gis-class-geometrycollection.html) | +| `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). @@ -193,7 +239,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 @@ -210,7 +256,7 @@ for($polygon as $i => $linestring) { ##### From/To Well Known Text ([WKT](https://dev.mysql.com/doc/refman/5.7/en/gis-data-formats.html#gis-wkt-format)) ```php -// fromWKT($wkt) +// fromWKT($wkt, $srid = 0) $point = Point::fromWKT('POINT(2 1)'); $point->toWKT(); // POINT(2 1) @@ -221,9 +267,9 @@ $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) +// fromString($wkt, $srid = 0) $point = new Point(1, 2); // lat, lng -(string)$point // lng, lat: 2 1 +(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) @@ -280,8 +326,8 @@ Available scopes: - `overlaps($geometryColumn, $geometry)` - `doesTouch($geometryColumn, $geometry)` - `orderBySpatial($geometryColumn, $geometry, $orderFunction, $direction = 'asc')` -- `orderByDistance($geometryColumn, ​$geometry, ​$direction = 'asc')` -- `orderByDistanceSphere($geometryColumn, ​$geometry, ​$direction = 'asc')` +- `orderByDistance($geometryColumn, $geometry, $direction = 'asc')` +- `orderByDistanceSphere($geometryColumn, $geometry, $direction = 'asc')` *Note that behavior and availability of MySQL spatial analysis functions differs in each MySQL version (cf. [documentation](https://dev.mysql.com/doc/refman/5.7/en/spatial-function-reference.html)).* @@ -302,14 +348,14 @@ class CreatePlacesTable extends Migration { 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')` +- `$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 @@ -381,18 +427,18 @@ class UpdatePlacesTable extends Migration ## Tests ```shell -composer test +$ composer test # or -composer test:unit -composer test:integration +$ 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 +$ make start_db # starts MySQL 8.0 # or -make start_db V=5.7 # starts a MySQL 5.7 +$ make start_db V=5.7 # starts MySQL 5.7 ``` ## Contributing From e3bcd3728b9d18edecaa6b311fc379d9e3bc8256 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 13 Apr 2020 22:29:57 -0400 Subject: [PATCH 48/55] Updated links in doc :book: --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d5e61519..88c2a5ac 100644 --- a/README.md +++ b/README.md @@ -253,7 +253,7 @@ 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, $srid = 0) @@ -269,7 +269,7 @@ $polygon->toWKT(); // POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)) ```php // fromString($wkt, $srid = 0) $point = new Point(1, 2); // lat, lng -(string)$point // lng, lat: 2 1 +(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) @@ -301,9 +301,9 @@ To deserialize a GeoJSON string into a Geometry class, you can use `Geometry::fr ```php $location = Geometry::fromJson('{"type":"Point","coordinates":[3.4,1.2]}'); -$location instanceof Point::class; // true -$location->getLat(); // 1.2 -$location->getLng()); // 3.4 +$location instanceof Point::class; // true +$location->getLat(); // 1.2 +$location->getLng()); // 3.4 ``` ## Scopes: Spatial analysis functions @@ -329,7 +329,7 @@ Available scopes: - `orderByDistance($geometryColumn, $geometry, $direction = 'asc')` - `orderByDistanceSphere($geometryColumn, $geometry, $direction = 'asc')` -*Note that behavior and availability of MySQL spatial analysis functions differs in each MySQL version (cf. [documentation](https://dev.mysql.com/doc/refman/5.7/en/spatial-function-reference.html)).* +*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 @@ -346,7 +346,7 @@ class CreatePlacesTable extends Migration { ### Columns -Available [MySQL Spatial Types](https://dev.mysql.com/doc/refman/5.7/en/spatial-datatypes.html) migration blueprints: +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)` @@ -364,9 +364,9 @@ You can add or drop spatial indexes in your migrations with the `spatialIndex` a - `$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): +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/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`. +> 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. @@ -436,7 +436,7 @@ $ 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 +$ make start_db # starts MySQL 8.0 # or $ make start_db V=5.7 # starts MySQL 5.7 ``` From e8cf208f8c5c4cf4cf42df10a68f8a2e5f25aae5 Mon Sep 17 00:00:00 2001 From: George Boot Date: Fri, 4 Sep 2020 12:49:16 +0200 Subject: [PATCH 49/55] Laravel 8 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 8dfecb78..7acd9fe0 100644 --- a/composer.json +++ b/composer.json @@ -18,14 +18,14 @@ "php": ">=5.5.9", "ext-pdo": "*", "ext-json": "*", - "illuminate/database": "^5.2|^6.0|^7.0", + "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|^6.0|^7.0", + "laravel/laravel": "^8.0", "doctrine/dbal": "^2.5", "laravel/browser-kit-testing": "^2.0", "php-coveralls/php-coveralls": "^2.0" From 1e47ab8a78963e719f0d78ea73a60eeeda35caf7 Mon Sep 17 00:00:00 2001 From: George Boot Date: Fri, 4 Sep 2020 12:49:22 +0200 Subject: [PATCH 50/55] Make public --- src/Eloquent/BaseBuilder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Eloquent/BaseBuilder.php b/src/Eloquent/BaseBuilder.php index 549e3f98..a2130840 100644 --- a/src/Eloquent/BaseBuilder.php +++ b/src/Eloquent/BaseBuilder.php @@ -6,7 +6,7 @@ class BaseBuilder extends QueryBuilder { - protected function cleanBindings(array $bindings) + public function cleanBindings(array $bindings) { $spatialBindings = []; foreach ($bindings as &$binding) { From 04e061526870a2d046eac9e31edee1ab0808f27e Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 20 Sep 2020 20:40:01 -0400 Subject: [PATCH 51/55] Prep for Laravel 8 - Removed PHP versions prior to 7.3 - Upgraded mockery to ^1.3 and phpunit to ~6.5 - Using php-coveralls.phar instead of installing as dev dependency (fixes issue with Guzzle 6 vs 7) - Updated tests :lab_coat: :test_tube: - Updated README.md :book: --- .travis.yml | 10 +- README.md | 3 +- composer.json | 9 +- tests/Unit/BaseTestCase.php | 4 +- tests/Unit/Eloquent/BuilderTest.php | 42 ++-- tests/Unit/Eloquent/SpatialTraitTest.php | 8 +- tests/Unit/MysqlConnectionTest.php | 3 +- tests/Unit/Schema/BlueprintTest.php | 209 +++++++++++++++++--- tests/Unit/Types/GeometryCollectionTest.php | 5 +- tests/Unit/Types/LineStringTest.php | 5 +- tests/Unit/Types/MultiLineStringTest.php | 5 +- tests/Unit/Types/MultiPointTest.php | 5 +- tests/Unit/Types/MultiPolygonTest.php | 5 +- 13 files changed, 249 insertions(+), 64 deletions(-) diff --git a/.travis.yml b/.travis.yml index b5a50f0e..14c9d7f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,8 @@ language: php php: - - '5.5' - - '5.6' - - '7.0' - - '7.1' - - '7.2' - '7.3' + - '7.4' env: - MYSQL_VERSION=8.0 @@ -30,10 +26,12 @@ before_script: - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - ./cc-test-reporter before-build + - curl -L https://github.com/php-coveralls/php-coveralls/releases/download/v2.2.0/php-coveralls.phar > ./php-coveralls.phar + - chmod +x php-coveralls.phar script: vendor/bin/phpunit --coverage-clover build/logs/clover.xml after_script: - - php vendor/bin/coveralls -v + - ./php-coveralls.phar -v - ./cc-test-reporter after-build --coverage-input-type clover --exit-code $TRAVIS_TEST_RESULT diff --git a/README.md b/README.md index 88c2a5ac..764b164a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ Please check the documentation for your MySQL version. MySQL's Extension for Spa - `1.x.x`: MySQL 5.6 (also supports MySQL 5.5 but not all spatial analysis functions) - `2.x.x`: MySQL 5.7 -- **`3.x.x`: MySQL 8.0 with SRID support (Current branch)** +- `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]** 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. diff --git a/composer.json b/composer.json index 8dfecb78..53862a63 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": ">=5.5.9", + "php": ">=7.3", "ext-pdo": "*", "ext-json": "*", "illuminate/database": "^5.2|^6.0|^7.0", @@ -23,12 +23,11 @@ "jmikola/geojson": "^1.0" }, "require-dev": { - "phpunit/phpunit": "~4.8|~5.7", - "mockery/mockery": "^0.9.9", + "phpunit/phpunit": "~6.5", "laravel/laravel": "^5.2|^6.0|^7.0", "doctrine/dbal": "^2.5", "laravel/browser-kit-testing": "^2.0", - "php-coveralls/php-coveralls": "^2.0" + "mockery/mockery": "^1.3" }, "autoload": { "psr-4": { @@ -43,7 +42,7 @@ }, "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0.x-dev" }, "laravel": { "providers": [ diff --git a/tests/Unit/BaseTestCase.php b/tests/Unit/BaseTestCase.php index 0b53a414..219f737d 100644 --- a/tests/Unit/BaseTestCase.php +++ b/tests/Unit/BaseTestCase.php @@ -1,6 +1,8 @@ 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,12 @@ public function testUpdatePolygon() $this->queryBuilder ->shouldReceive('update') ->with(['polygon' => new SpatialExpression($polygon)]) - ->once(); + ->once() + ->andReturn(1); + + $result = $this->builder->update(['polygon' => $polygon]); - $this->builder->update(['polygon' => $polygon]); + $this->assertSame(1, $result); } public function testUpdatePointWithSrid() @@ -79,9 +88,12 @@ public function testUpdatePointWithSrid() $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 testUpdateLinestringWithSrid() @@ -91,9 +103,12 @@ public function testUpdateLinestringWithSrid() $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 testUpdatePolygonWithSrid() @@ -106,9 +121,12 @@ public function testUpdatePolygonWithSrid() $this->queryBuilder ->shouldReceive('update') ->with(['polygon' => new SpatialExpression($polygon)]) - ->once(); + ->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 785c78a7..dd7358fc 100644 --- a/tests/Unit/Eloquent/SpatialTraitTest.php +++ b/tests/Unit/Eloquent/SpatialTraitTest.php @@ -5,9 +5,12 @@ use Grimzy\LaravelMysqlSpatial\Types\Point; use Illuminate\Database\Eloquent\Model; use Mockery as m; +use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; class SpatialTraitTest extends BaseTestCase { + use MockeryPHPUnitIntegration; + /** * @var TestModel */ @@ -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(); } 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 8ceda39b..03e41733 100644 --- a/tests/Unit/Schema/BlueprintTest.php +++ b/tests/Unit/Schema/BlueprintTest.php @@ -4,6 +4,7 @@ use BaseTestCase; use Grimzy\LaravelMysqlSpatial\Schema\Blueprint; +use Illuminate\Database\Schema\ColumnDefinition; use Mockery; class BlueprintTest extends BaseTestCase @@ -23,161 +24,305 @@ public function setUp() public function testGeometry() { + $expectedCol = new ColumnDefinition([ + 'type' => 'geometry', + 'name' => 'col', + 'srid' => null + ]); + $this->blueprint ->shouldReceive('addColumn') ->with('geometry', 'col', ['srid' => null]) - ->once(); + ->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); + + $result = $this->blueprint->point('col'); - $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', ['srid' => null]) - ->once(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->linestring('col'); - $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', ['srid' => null]) - ->once(); + ->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', ['srid' => null]) - ->once(); + ->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', ['srid' => null]) - ->once(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->multilinestring('col'); - $this->blueprint->multilinestring('col'); + $this->assertSame($expectedCol, $result); } public function testMultiPolygon() { + $expectedCol = new ColumnDefinition([ + 'type' => 'multipolygon', + 'name' => 'col', + 'srid' => null + ]); + $this->blueprint ->shouldReceive('addColumn') ->with('multipolygon', 'col', ['srid' => null]) - ->once(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->multipolygon('col'); - $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(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->geometrycollection('col'); - $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(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->geometry('col', 4326); - $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(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->point('col', 4326); - $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(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->linestring('col', 4326); - $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(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->polygon('col', 4326); - $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(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->multipoint('col', 4326); - $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(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->multilinestring('col', 4326); - $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(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->multipolygon('col', 4326); - $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', ['srid' => 4326]) - ->once(); + ->once() + ->andReturn($expectedCol); + + $result = $this->blueprint->geometrycollection('col', 4326); - $this->blueprint->geometrycollection('col', 4326); + $this->assertSame($expectedCol, $result); } } diff --git a/tests/Unit/Types/GeometryCollectionTest.php b/tests/Unit/Types/GeometryCollectionTest.php index 4576a77b..a0d6f016 100644 --- a/tests/Unit/Types/GeometryCollectionTest.php +++ b/tests/Unit/Types/GeometryCollectionTest.php @@ -129,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/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 563ecbd1..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]}'); } diff --git a/tests/Unit/Types/MultiPointTest.php b/tests/Unit/Types/MultiPointTest.php index 6e94af87..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]}'); } diff --git a/tests/Unit/Types/MultiPolygonTest.php b/tests/Unit/Types/MultiPolygonTest.php index a37df382..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]}'); } From 6cc29470bbcc0fc7cea494923fb766e4ce2d5956 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 21 Sep 2020 00:43:12 +0000 Subject: [PATCH 52/55] Apply fixes from StyleCI [ci skip] [skip ci] --- tests/Unit/Eloquent/SpatialTraitTest.php | 2 +- tests/Unit/Schema/BlueprintTest.php | 32 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/Unit/Eloquent/SpatialTraitTest.php b/tests/Unit/Eloquent/SpatialTraitTest.php index dd7358fc..8ece7d25 100644 --- a/tests/Unit/Eloquent/SpatialTraitTest.php +++ b/tests/Unit/Eloquent/SpatialTraitTest.php @@ -4,8 +4,8 @@ use Grimzy\LaravelMysqlSpatial\MysqlConnection; use Grimzy\LaravelMysqlSpatial\Types\Point; use Illuminate\Database\Eloquent\Model; -use Mockery as m; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; +use Mockery as m; class SpatialTraitTest extends BaseTestCase { diff --git a/tests/Unit/Schema/BlueprintTest.php b/tests/Unit/Schema/BlueprintTest.php index 03e41733..c22c9518 100644 --- a/tests/Unit/Schema/BlueprintTest.php +++ b/tests/Unit/Schema/BlueprintTest.php @@ -27,7 +27,7 @@ public function testGeometry() $expectedCol = new ColumnDefinition([ 'type' => 'geometry', 'name' => 'col', - 'srid' => null + 'srid' => null, ]); $this->blueprint @@ -46,7 +46,7 @@ public function testPoint() $expectedCol = new ColumnDefinition([ 'type' => 'point', 'name' => 'col', - 'srid' => null + 'srid' => null, ]); $this->blueprint @@ -65,7 +65,7 @@ public function testLinestring() $expectedCol = new ColumnDefinition([ 'type' => 'linestring', 'name' => 'col', - 'srid' => null + 'srid' => null, ]); $this->blueprint @@ -84,7 +84,7 @@ public function testPolygon() $expectedCol = new ColumnDefinition([ 'type' => 'polygon', 'name' => 'col', - 'srid' => null + 'srid' => null, ]); $this->blueprint @@ -103,7 +103,7 @@ public function testMultiPoint() $expectedCol = new ColumnDefinition([ 'type' => 'multipoint', 'name' => 'col', - 'srid' => null + 'srid' => null, ]); $this->blueprint @@ -122,7 +122,7 @@ public function testMultiLineString() $expectedCol = new ColumnDefinition([ 'type' => 'multilinestring', 'name' => 'col', - 'srid' => null + 'srid' => null, ]); $this->blueprint @@ -141,7 +141,7 @@ public function testMultiPolygon() $expectedCol = new ColumnDefinition([ 'type' => 'multipolygon', 'name' => 'col', - 'srid' => null + 'srid' => null, ]); $this->blueprint @@ -160,7 +160,7 @@ public function testGeometryCollection() $expectedCol = new ColumnDefinition([ 'type' => 'geometrycollection', 'name' => 'col', - 'srid' => null + 'srid' => null, ]); $this->blueprint @@ -179,7 +179,7 @@ public function testGeometryWithSrid() $expectedCol = new ColumnDefinition([ 'type' => 'geometry', 'name' => 'col', - 'srid' => 4326 + 'srid' => 4326, ]); $this->blueprint @@ -198,7 +198,7 @@ public function testPointWithSrid() $expectedCol = new ColumnDefinition([ 'type' => 'point', 'name' => 'col', - 'srid' => 4326 + 'srid' => 4326, ]); $this->blueprint @@ -217,7 +217,7 @@ public function testLinestringWithSrid() $expectedCol = new ColumnDefinition([ 'type' => 'linestring', 'name' => 'col', - 'srid' => 4326 + 'srid' => 4326, ]); $this->blueprint @@ -236,7 +236,7 @@ public function testPolygonWithSrid() $expectedCol = new ColumnDefinition([ 'type' => 'polygon', 'name' => 'col', - 'srid' => 4326 + 'srid' => 4326, ]); $this->blueprint @@ -255,7 +255,7 @@ public function testMultiPointWithSrid() $expectedCol = new ColumnDefinition([ 'type' => 'multipoint', 'name' => 'col', - 'srid' => 4326 + 'srid' => 4326, ]); $this->blueprint @@ -274,7 +274,7 @@ public function testMultiLineStringWithSrid() $expectedCol = new ColumnDefinition([ 'type' => 'multilinestring', 'name' => 'col', - 'srid' => 4326 + 'srid' => 4326, ]); $this->blueprint @@ -293,7 +293,7 @@ public function testMultiPolygonWithSrid() $expectedCol = new ColumnDefinition([ 'type' => 'multipolygon', 'name' => 'col', - 'srid' => 4326 + 'srid' => 4326, ]); $this->blueprint @@ -312,7 +312,7 @@ public function testGeometryCollectionWithSrid() $expectedCol = new ColumnDefinition([ 'type' => 'geometrycollection', 'name' => 'col', - 'srid' => 4326 + 'srid' => 4326, ]); $this->blueprint From efb637e454332195c6c571ad915c29cc1dbc6256 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 20 Sep 2020 22:01:58 -0400 Subject: [PATCH 53/55] Remove coveralls --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 14c9d7f6..f6a2a31f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,12 +26,8 @@ before_script: - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - ./cc-test-reporter before-build - - curl -L https://github.com/php-coveralls/php-coveralls/releases/download/v2.2.0/php-coveralls.phar > ./php-coveralls.phar - - chmod +x php-coveralls.phar script: vendor/bin/phpunit --coverage-clover build/logs/clover.xml -after_script: - - ./php-coveralls.phar -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 From 2c4c67133925c0f33f6818b2b1eb66cabbc63ccb Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sun, 20 Sep 2020 22:19:55 -0400 Subject: [PATCH 54/55] Updated README.md :book: --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 764b164a..cab18d80 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,10 @@ 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 +$ 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: From 2ca9f2f25cf10e3b4771881108ecc9c69317bf57 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Sat, 17 Oct 2020 03:47:27 -0400 Subject: [PATCH 55/55] Update README.md :book: --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cab18d80..39d5303c 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,10 @@ Please check the documentation for your MySQL version. MySQL's Extension for Spa **Versions** - `1.x.x`: MySQL 5.6 (also supports MySQL 5.5 but not all spatial analysis functions) -- `2.x.x`: MySQL 5.7 +- `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.