From 4db0a4a212def2083e1bef733414c57c30c1e72d Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Wed, 6 Feb 2019 21:37:55 -0500 Subject: [PATCH 01/21] 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 02/21] 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 03/21] 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 04/21] 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 0f942632e4a9f2ac9dd1f0f52e48e04e292af177 Mon Sep 17 00:00:00 2001 From: Saif M Date: Sat, 7 Dec 2019 12:30:12 +0600 Subject: [PATCH 05/21] 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 06/21] 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 07/21] 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 08/21] 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 09/21] 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 10/21] 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 11/21] 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 12/21] 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 13/21] 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 14/21] 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 15/21] 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 16/21] 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 17/21] 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 b9e6f4a8d64fb080a770a98ca1bec2b82e73b188 Mon Sep 17 00:00:00 2001 From: Joseph Estefane Date: Mon, 9 Mar 2020 02:54:05 +0000 Subject: [PATCH 18/21] 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 19/21] 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 20/21] 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 21/21] 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 ```