diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..f78dd13 --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,41 @@ +name: Test Suite + +on: + push: + pull_request: + +jobs: + tests: + runs-on: ubuntu-latest + + strategy: + matrix: + php: [8.1 8.0 7.4] + release: [stable, lowest] + + services: + postgres: + image: kartoza/postgis:12.1 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DBNAME: postgres + ports: + - 5432/tcp + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 + + steps: + - uses: actions/checkout@v1 + - uses: actions/cache@v1 + with: + path: ~/.composer/cache/files + key: php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: pecl + extensions: mbstring, dom, fileinfo, pgsql, intl + coverage: ${{ matrix.coverage }} + - run: composer update --no-interaction --no-progress --no-suggest --prefer-dist --prefer-${{ matrix.release }} + - run: | + vendor/bin/phpunit diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1a42468..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: php -dist: trusty -php: - - 5.5 - - 5.6 - - 7.0 - - hhvm - - nightly -matrix: - allow_failures: - - nightly - -install: - - travis_retry composer install - -before_script: - - mkdir -p build/logs - -script: - - vendor/bin/phpunit --coverage-clover build/logs/clover.xml - -after_script: - - php vendor/bin/coveralls -v - - ./vendor/bin/test-reporter diff --git a/README.md b/README.md index 6783bf4..4f9a8d3 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,86 @@ -Laravel postgis extension -========================= +Laravel Wrapper for PostgreSQL's Geo-Extension Postgis +====================================================== -[![Build Status](https://travis-ci.org/njbarrett/laravel-postgis.svg?branch=master)](https://travis-ci.org/njbarrett/laravel-postgis.svg?branch=master) -[![Code Climate](https://codeclimate.com/github/njbarrett/laravel-postgis/badges/gpa.svg)](https://codeclimate.com/github/njbarrett/laravel-postgis) -[![Coverage Status](https://coveralls.io/repos/github/njbarrett/laravel-postgis/badge.svg?branch=master)](https://coveralls.io/github/njbarrett/laravel-postgis?branch=master) +![Build Status](https://github.com/mstaack/laravel-postgis/workflows/Test%20Suite/badge.svg) + + +# DEPRECATED +Consider using: https://github.com/clickbar/laravel-magellan ## Features - * Work with geometry classes instead of arrays. (`$myModel->myPoint = new Point(1,2)`) - * Adds helpers in migrations. (`$table->polygon('myColumn')`) + * Work with geometry classes instead of arrays. +```php +$model->myPoint = new Point(1,2); //lat, long +``` + +* Adds helpers in migrations. +```php +$table->polygon('myColumn'); +``` + +## Warning +This Package has been moved to a new owner and aims for Laravel 6/7/8/9 and PHP 7 support only soon! -### Future plans +Replace all your references to the new namespace: +``` +MStaack\LaravelPostgis +``` - * Geometry functions on the geometry classes (contains(), equals(), distance(), etc… (HELP!)) +Thanks to : +- https://github.com/njbarrett +- https://github.com/phaza +- https://github.com/mirzap -## Versions -- Use 2.* for Laravel 5.1.* -- Use 3.* for Laravel 5.2.* -- Use 3.* for Laravel 5.3.* -- Use 3.* for Laravel 5.4.* -- Use 3.* for Laravel 5.5.* +Fluent in Laravel Packages and Postgres/Postgis? Consider contributing! We are looking for anyone that wants to help out! ## Installation +- Use 3.* for Laravel 5 - composer require phaza/laravel-postgis +```bash +composer require "mstaack/laravel-postgis:3.*" +``` + +- Use 5.* for Laravel 6/7/8/9 +```bash +composer require mstaack/laravel-postgis +``` For laravel >=5.5 that's all. This package supports Laravel new [Package Discovery](https://laravel.com/docs/5.5/packages#package-discovery). If you are using Laravel < 5.5, you also need to add the DatabaseServiceProvider to your `config/app.php` file. +```php +'MStaack\LaravelPostgis\DatabaseServiceProvider', +``` +## Usage - 'Phaza\LaravelPostgis\DatabaseServiceProvider', +To start, ensure you have PostGIS enabled in your database - you can do this in a Laravel migration or manually via SQL. +### Enable PostGIS via a Laravel migration -## Usage +You need to publish the migration to easily enable PostGIS: -First of all, make sure to enable postgis. +```sh +php artisan vendor:publish --provider="MStaack\LaravelPostgis\DatabaseServiceProvider" --tag="migrations" +``` + +And then you run the migrations: + +```sh +php artisan migrate +``` + +These methods are safe to use and will only enable / disable the PostGIS extension if relevant - they won't cause an error if PostGIS is / isn't already enabled. + +If you prefer, you can use the `enablePostgis()` method which will throw an error if PostGIS is already enabled, and the `disablePostgis()` method twhich will throw an error if PostGIS isn't enabled. + +### Enable PostGIS manually + +Use an SQL client to connect to your database and run the following command: CREATE EXTENSION postgis; -To verify that postgis is enabled +To verify that PostGIS is enabled you can run: SELECT postgis_full_version(); @@ -56,7 +98,7 @@ Open the created migrations with your editor. ```PHP use Illuminate\Database\Migrations\Migration; -use Phaza\LaravelPostgis\Schema\Blueprint; +use MStaack\LaravelPostgis\Schema\Blueprint; class CreateLocationsTable extends Migration { @@ -118,8 +160,8 @@ what attributes/columns on your model are to be considered geometry objects. By ```PHP use Illuminate\Database\Eloquent\Model; -use Phaza\LaravelPostgis\Eloquent\PostgisTrait; -use Phaza\LaravelPostgis\Geometries\Point; +use MStaack\LaravelPostgis\Eloquent\PostgisTrait; +use MStaack\LaravelPostgis\Geometries\Point; class Location extends Model { @@ -137,7 +179,7 @@ class Location extends Model 'polygon', 'polygon2' ]; - + protected $postgisTypes = [ 'location' => [ 'geomtype' => 'geography', @@ -195,3 +237,22 @@ Available geometry classes: * Polygon * MultiPolygon * GeometryCollection + +## Publishing config +A configuration file exists for overriding default values. To add to your project, run: + +```sh +php artisan vendor:publish --provider="MStaack\LaravelPostgis\DatabaseServiceProvider" --tag="postgis" +``` +### Coordinate precision +The precision of stored/displayed coordinated can be customised in the config. + + +```php +# config/postgis.php +return [ + ... + 'precision' => 6, +]; +``` +See http://wiki.gis.com/wiki/index.php/Decimal_degrees#Accuracy for more information diff --git a/composer.json b/composer.json index b4cfd8d..b88bf2d 100644 --- a/composer.json +++ b/composer.json @@ -1,29 +1,27 @@ { - "name": "phaza/laravel-postgis", + "name": "mstaack/laravel-postgis", "description": "Postgis extensions for laravel. Aims to make it easy to work with geometries from laravel models", "require": { - "php": ">=5.5", - "illuminate/database": "^5.2", + "php": ">=7.1", + "illuminate/database": "^6.0|^7.0|^8.0|^9.0|^10.0", "geo-io/wkb-parser": "^1.0", "jmikola/geojson": "^1.0", - "bosnadev/database": "~0.16" + "bosnadev/database": "^0.21|dev-master" }, "require-dev": { - "phpunit/phpunit": "~4.5", - "mockery/mockery": "0.9.*", - "codeclimate/php-test-reporter": "~0.3", - "illuminate/pagination": "~5.0" + "illuminate/pagination": "^6.0|^7.0|^8.0|^9.0|^10.0", + "phpunit/phpunit": ">=8.5.23", + "mockery/mockery": "^1.3" }, "autoload": { "psr-4": { - "Phaza\\LaravelPostgis\\": "src/" + "MStaack\\LaravelPostgis\\": "src/" } }, "autoload-dev": { - "classmap": [ - "tests/BaseTestCase.php", - "tests/Stubs/" - ] + "psr-4": { + "MStaack\\LaravelPostgis\\Tests\\": "tests/" + } }, "license": "MIT", "authors": [ @@ -34,13 +32,20 @@ { "name": "Nicholas Barrett", "email": "njbarrett7@gmail.com" + }, + { + "name": "Max Matteo Staack", + "email": "maxmatteostaack@gmail.com" } ], "extra": { "laravel": { "providers": [ - "Phaza\\LaravelPostgis\\DatabaseServiceProvider" + "MStaack\\LaravelPostgis\\DatabaseServiceProvider" ] } + }, + "scripts": { + "test": "./vendor/bin/phpunit" } } diff --git a/config/postgis.php b/config/postgis.php new file mode 100644 index 0000000..3186cd7 --- /dev/null +++ b/config/postgis.php @@ -0,0 +1,6 @@ + 'public', // Schema for the Postgis extension, + 'precision' => 6, // Control precision of floats in stringifyFloat +]; diff --git a/database/migrations/enable_postgis.php.stub b/database/migrations/enable_postgis.php.stub new file mode 100644 index 0000000..b5e1ab7 --- /dev/null +++ b/database/migrations/enable_postgis.php.stub @@ -0,0 +1,27 @@ + diff --git a/src/Connectors/ConnectionFactory.php b/src/Connectors/ConnectionFactory.php index 715c2cc..7585b27 100644 --- a/src/Connectors/ConnectionFactory.php +++ b/src/Connectors/ConnectionFactory.php @@ -1,7 +1,8 @@ -container->bound($key = "db.connection.{$driver}")) { - return $this->container->make($key, [$connection, $database, $prefix, $config]); + if ($resolver = Connection::getResolver($driver)) { + return $resolver($connection, $database, $prefix, $config); } if ($driver === 'pgsql') { diff --git a/src/DatabaseServiceProvider.php b/src/DatabaseServiceProvider.php index 5e7e2af..83a5bf8 100644 --- a/src/DatabaseServiceProvider.php +++ b/src/DatabaseServiceProvider.php @@ -1,15 +1,28 @@ -publishes([$config_path => config_path('postgis.php')], 'postgis'); + + if (!class_exists('EnablePostgis')) { + $this->publishes([ + __DIR__ . '/../database/migrations/enable_postgis.php.stub' => database_path('migrations/'.date('Y_m_d_His', time()).'_enable_postgis.php'), + ], 'migrations'); + } + + $this->mergeConfigFrom($config_path, 'postgis'); + } + /** * Register the service provider. * diff --git a/src/Eloquent/Builder.php b/src/Eloquent/Builder.php index d58c7f9..3f74ffe 100644 --- a/src/Eloquent/Builder.php +++ b/src/Eloquent/Builder.php @@ -1,7 +1,7 @@ - &$value) { if ($value instanceof GeometryInterface) { - $value = $this->asWKT($value); + if (is_null($this->model)) { + $value = $this->asWKT($value); + } else { + $attrs = $this->model->getPostgisType($key); + $value = $this->model->asWKT($value, $attrs); + } } } return parent::update($values); } - protected function getPostgisFields() + public function upsert(array $values, $uniqueBy, $update = null) { - return $this->getModel()->getPostgisFields(); - } + foreach ($values as &$row) { + foreach ($row as $column => &$value) { + if ($value instanceof GeometryInterface) { + if (is_null($this->model)) { + $value = $this->asWKT($value); + } else { + $attrs = $this->model->getPostgisType($column); + $value = $this->model->asWKT($value, $attrs); + } + } + } + } + return parent::upsert($values, $uniqueBy, $update); + } protected function asWKT(GeometryInterface $geometry) { - return $this->getQuery()->raw(sprintf("public.ST_GeogFromText('%s')", $geometry->toWKT())); + return $this->getQuery()->raw(sprintf("%s.ST_GeogFromText('%s')", + function_exists('config') ? config('postgis.schema') : 'public', $geometry->toWKT())); } } diff --git a/src/Eloquent/PostgisTrait.php b/src/Eloquent/PostgisTrait.php index 6a7fc0b..b5363ff 100644 --- a/src/Eloquent/PostgisTrait.php +++ b/src/Eloquent/PostgisTrait.php @@ -1,13 +1,14 @@ -getConnection()->raw(sprintf("%s.ST_GeogFromText('%s')", + function_exists('config') ? config('postgis.schema') : 'public', $geometry->toWKT())); + } + + protected function geomFromText(GeometryInterface $geometry, $srid = 4326) + { + return $this->getConnection()->raw(sprintf("%s.ST_GeomFromText('%s', '%d')", + function_exists('config') ? config('postgis.schema') : 'public', $geometry->toWKT(), $srid)); + } + + public function asWKT(GeometryInterface $geometry, $attrs) + { + switch (strtoupper($attrs['geomtype'])) { + case 'GEOMETRY': + return $this->geomFromText($geometry, $attrs['srid']); + break; + case 'GEOGRAPHY': + default: + return $this->geogFromText($geometry); + break; + } + } + protected function performInsert(EloquentBuilder $query, array $options = []) { foreach ($this->attributes as $key => $value) { @@ -31,17 +57,9 @@ protected function performInsert(EloquentBuilder $query, array $options = []) $this->geometries[$key] = $value; //Preserve the geometry objects prior to the insert if (! $value instanceof GeometryCollection) { $attrs = $this->getPostgisType($key); - switch (strtoupper($attrs['geomtype'])) { - case 'GEOMETRY': - $this->attributes[$key] = $this->getConnection()->raw(sprintf("public.ST_GeomFromText('%s', '%d')", $value->toWKT(), $attrs['srid'])); - break; - case 'GEOGRAPHY': - default: - $this->attributes[$key] = $this->getConnection()->raw(sprintf("public.ST_GeogFromText('%s')", $value->toWKT())); - break; - } + $this->attributes[$key] = $this->asWKT($value, $attrs); } else { - $this->attributes[$key] = $this->getConnection()->raw(sprintf("public.ST_GeomFromText('%s', 4326)", $value->toWKT())); + $this->attributes[$key] = $this->geomFromText($value); } } } diff --git a/src/Exceptions/PostgisFieldsNotDefinedException.php b/src/Exceptions/PostgisFieldsNotDefinedException.php index 235eef0..9248caa 100644 --- a/src/Exceptions/PostgisFieldsNotDefinedException.php +++ b/src/Exceptions/PostgisFieldsNotDefinedException.php @@ -1,4 +1,4 @@ -geometries); } @@ -78,7 +79,7 @@ public function count() * * @return \GeoJson\Geometry\GeometryCollection */ - public function jsonSerialize() + public function jsonSerialize(): \GeoJson\Geometry\GeometryCollection { $geometries = []; foreach ($this->geometries as $geometry) { diff --git a/src/Geometries/GeometryInterface.php b/src/Geometries/GeometryInterface.php index 22f27c7..8009533 100644 --- a/src/Geometries/GeometryInterface.php +++ b/src/Geometries/GeometryInterface.php @@ -1,4 +1,6 @@ -points) === 0) return false; + return $this->points[0]->is3d(); + } + public function toWKT() { - return sprintf('LINESTRING(%s)', $this->toPairList()); + $wktType = 'LINESTRING'; + if ($this->is3d()) $wktType .= ' Z'; + return sprintf('%s(%s)', $wktType, $this->toPairList()); } public static function fromWKT($wkt) @@ -34,7 +44,7 @@ public function __toString() * * @return \GeoJson\Geometry\LineString */ - public function jsonSerialize() + public function jsonSerialize(): \GeoJson\Geometry\LineString { $points = []; foreach ($this->points as $point) { diff --git a/src/Geometries/LineStringCollection.php b/src/Geometries/LineStringCollection.php new file mode 100644 index 0000000..ff056c2 --- /dev/null +++ b/src/Geometries/LineStringCollection.php @@ -0,0 +1,68 @@ +linestrings = $linestrings; + } + + public function getLineStrings() + { + return $this->linestrings; + } + + public function is3d() + { + if (count($this->linestrings) === 0) return false; + return $this->linestrings[0]->is3d(); + } + + public static function fromString($wktArgument) + { + $str = preg_split('/\)\s*,\s*\(/', substr(trim($wktArgument), 1, -1)); + $linestrings = array_map(function ($data) { + return LineString::fromString($data); + }, $str); + + + return new static($linestrings); + } + + public function __toString() + { + return implode(',', array_map(function (LineString $linestring) { + return sprintf('(%s)', (string)$linestring); + }, $this->getLineStrings())); + } + + public function count(): int + { + return count($this->linestrings); + } +} diff --git a/src/Geometries/MultiLineString.php b/src/Geometries/MultiLineString.php index 75ee891..090f695 100644 --- a/src/Geometries/MultiLineString.php +++ b/src/Geometries/MultiLineString.php @@ -1,66 +1,14 @@ -linestrings = $linestrings; - } - - public function getLineStrings() - { - return $this->linestrings; - } - public function toWKT() { - return sprintf('MULTILINESTRING(%s)', (string)$this); - } - - public static function fromString($wktArgument) - { - $str = preg_split('/\)\s*,\s*\(/', substr(trim($wktArgument), 1, -1)); - $linestrings = array_map(function ($data) { - return LineString::fromString($data); - }, $str); - - - return new static($linestrings); - } - - public function __toString() - { - return implode(',', array_map(function (LineString $linestring) { - return sprintf('(%s)', (string)$linestring); - }, $this->getLineStrings())); - } - - public function count() - { - return count($this->linestrings); + $wktType = 'MULTILINESTRING'; + if ($this->is3d()) $wktType .= ' Z'; + return sprintf('%s(%s)', $wktType, (string)$this); } /** @@ -68,7 +16,7 @@ public function count() * * @return \GeoJson\Geometry\MultiLineString */ - public function jsonSerialize() + public function jsonSerialize(): \GeoJson\Geometry\MultiLineString { $linestrings = []; diff --git a/src/Geometries/MultiPoint.php b/src/Geometries/MultiPoint.php old mode 100644 new mode 100755 index 17f423e..465047c --- a/src/Geometries/MultiPoint.php +++ b/src/Geometries/MultiPoint.php @@ -1,10 +1,38 @@ -points = $points; + } + + public function is3d() + { + if (count($this->points) === 0) return false; + return $this->points[0]->is3d(); + } + public function toWKT() { - return sprintf('MULTIPOINT(%s)', (string)$this); + $wktType = 'MULTIPOINT'; + if ($this->is3d()) $wktType .= ' Z'; + return sprintf('%s(%s)', $wktType, (string)$this); } public static function fromWKT($wkt) @@ -16,8 +44,15 @@ public static function fromWKT($wkt) public static function fromString($wktArgument) { + if (!strpos(trim($wktArgument), '(')) { + $points = explode(',', $wktArgument); + $wktArgument = implode(',', array_map(function ($pair) { + return '(' . trim($pair) . ')'; + }, $points)); + }; + $matches = []; - preg_match_all('/\(\s*(\d+\s+\d+)\s*\)/', trim($wktArgument), $matches); + preg_match_all('/\(\s*([+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)+\s+[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)+(\s+[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)+)?)\s*\)/', trim($wktArgument), $matches); if (count($matches) < 2) { return new static([]); @@ -42,7 +77,7 @@ public function __toString() * * @return \GeoJson\Geometry\MultiPoint */ - public function jsonSerialize() + public function jsonSerialize(): \GeoJson\Geometry\MultiPoint { $points = []; foreach ($this->points as $point) { diff --git a/src/Geometries/MultiPolygon.php b/src/Geometries/MultiPolygon.php index 62c331a..56c205d 100644 --- a/src/Geometries/MultiPolygon.php +++ b/src/Geometries/MultiPolygon.php @@ -1,4 +1,6 @@ -polygons = $polygons; } + public function is3d() + { + if (count($this->polygons) === 0) return false; + return $this->polygons[0]->is3d(); + } + public function toWKT() { - return sprintf('MULTIPOLYGON(%s)', (string) $this); + $wktType = 'MULTIPOLYGON'; + if ($this->is3d()) $wktType .= ' Z'; + return sprintf('%s(%s)', $wktType, (string)$this); } public function __toString() { return implode(',', array_map(function (Polygon $polygon) { - return sprintf('(%s)', (string) $polygon); + return sprintf('(%s)', (string)$polygon); }, $this->polygons)); } public static function fromString($wktArgument) { - $parts = preg_split('/(\)\s*\)\s*,\s*\(\s*\()/', $wktArgument, -1, PREG_SPLIT_DELIM_CAPTURE); + $parts = preg_split('/(\)\s*\)\s*,\s*\(\s*\()/', $wktArgument, -1, PREG_SPLIT_DELIM_CAPTURE); $polygons = static::assembleParts($parts); return new static(array_map(function ($polygonString) { @@ -57,7 +67,7 @@ public static function fromString($wktArgument) *

* The return value is cast to an integer. */ - public function count() + public function count(): int { return count($this->polygons); } @@ -91,7 +101,7 @@ public function getPolygons() protected static function assembleParts(array $parts) { $polygons = []; - $count = count($parts); + $count = count($parts); for ($i = 0; $i < $count; $i++) { if ($i % 2 !== 0) { @@ -111,7 +121,7 @@ protected static function assembleParts(array $parts) * * @return \GeoJson\Geometry\MultiPolygon */ - public function jsonSerialize() + public function jsonSerialize(): \GeoJson\Geometry\MultiPolygon { $polygons = []; foreach ($this->polygons as $polygon) { diff --git a/src/Geometries/Point.php b/src/Geometries/Point.php index 559e3c0..4176d34 100644 --- a/src/Geometries/Point.php +++ b/src/Geometries/Point.php @@ -1,16 +1,32 @@ -lat = (float)$lat; $this->lng = (float)$lng; + $this->alt = isset($alt) ? (float)$alt : null; + $this->setPrecision( + function_exists('config') ? config('postgis.precision', 6) : 6 + ); + } + + public function setPrecision($precision) + { + $precision = filter_var($precision, FILTER_VALIDATE_INT); + if (!is_int($precision)) { + throw new \UnexpectedValueException('Precision must be an integer'); + } + + $this->precision = $precision; } public function getLat() @@ -33,28 +49,55 @@ public function setLng($lng) $this->lng = (float)$lng; } + public function getAlt() + { + return $this->alt; + } + + public function setAlt($alt) + { + $this->alt = (float)$alt; + } + + public function is3d() + { + return isset($this->alt); + } + public function toPair() { - return self::stringifyFloat($this->getLng()) . ' ' . self::stringifyFloat($this->getLat()); + $pair = $this->stringifyFloat($this->getLng()) . ' ' . $this->stringifyFloat($this->getLat()); + if ($this->is3d()) { + $pair .= ' ' . $this->stringifyFloat($this->getAlt()); + } + return $pair; } - - private static function stringifyFloat($float) + + private function stringifyFloat($float) { // normalized output among locales - return rtrim(rtrim(sprintf('%F', $float), '0'), '.'); + + return rtrim(rtrim(sprintf("%.{$this->precision}F", $float), '0'), '.'); } - + public static function fromPair($pair) { $pair = preg_replace('/^[a-zA-Z\(\)]+/', '', trim($pair)); - list($lng, $lat) = explode(' ', trim($pair)); + $splits = explode(' ', trim($pair)); + $lng = $splits[0]; + $lat = $splits[1]; + if (count($splits) > 2) { + $alt = $splits[2]; + } - return new static((float)$lat, (float)$lng); + return new static((float)$lat, (float)$lng, isset($alt) ? (float)$alt : null); } public function toWKT() { - return sprintf('POINT(%s)', (string)$this); + $wktType = 'POINT'; + if ($this->is3d()) $wktType .= ' Z'; + return sprintf('%s(%s)', $wktType, (string)$this); } public static function fromString($wktArgument) @@ -72,8 +115,10 @@ public function __toString() * * @return \GeoJson\Geometry\Point */ - public function jsonSerialize() + public function jsonSerialize(): \GeoJson\Geometry\Point { - return new \GeoJson\Geometry\Point([$this->getLng(), $this->getLat()]); + $position = [$this->getLng(), $this->getLat()]; + if ($this->is3d()) $position[] = $this->getAlt(); + return new \GeoJson\Geometry\Point($position); } } diff --git a/src/Geometries/PointCollection.php b/src/Geometries/PointCollection.php index b0aed6f..1e6e3ca 100644 --- a/src/Geometries/PointCollection.php +++ b/src/Geometries/PointCollection.php @@ -1,4 +1,6 @@ -points; } - public function getIterator() + public function getIterator(): Traversable { return new ArrayIterator($this->points); } @@ -68,7 +71,7 @@ public function insertPoint($index, Point $point) array_splice($this->points, $offset, 0, [$point]); } - public function offsetExists($offset) + public function offsetExists($offset): bool { return isset($this->points[$offset]); } @@ -77,12 +80,12 @@ public function offsetExists($offset) * @param mixed $offset * @return null|Point */ - public function offsetGet($offset) + public function offsetGet($offset): ?Point { return $this->offsetExists($offset) ? $this->points[$offset] : null; } - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { if (!($value instanceof Point)) { throw new InvalidArgumentException('$value must be an instance of Point'); @@ -95,12 +98,12 @@ public function offsetSet($offset, $value) } } - public function offsetUnset($offset) + public function offsetUnset($offset): void { unset($this->points[$offset]); } - public function count() + public function count(): int { return count($this->points); } diff --git a/src/Geometries/Polygon.php b/src/Geometries/Polygon.php index 2169d3d..89ba6ff 100644 --- a/src/Geometries/Polygon.php +++ b/src/Geometries/Polygon.php @@ -1,13 +1,16 @@ -is3d()) $wktType .= ' Z'; + return sprintf('%s(%s)', $wktType, (string)$this); } /** @@ -15,11 +18,11 @@ public function toWKT() * * @return \GeoJson\Geometry\Polygon */ - public function jsonSerialize() + public function jsonSerialize(): \GeoJson\Geometry\Polygon { $linearrings = []; foreach ($this->linestrings as $linestring) { - $linearrings[] = new \GeoJson\Geometry\LinearRing($linestring->jsonSerialize()->getCoordinates()); + $linearrings[] = new LinearRing($linestring->jsonSerialize()->getCoordinates()); } return new \GeoJson\Geometry\Polygon($linearrings); diff --git a/src/PostgisConnection.php b/src/PostgisConnection.php index 921dd78..6696bb1 100644 --- a/src/PostgisConnection.php +++ b/src/PostgisConnection.php @@ -1,16 +1,12 @@ -getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('geography', 'string'); - $this->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('geometry', 'string'); - } +use Bosnadev\Database\PostgresConnection; +use MStaack\LaravelPostgis\Schema\Grammars\PostgisGrammar; +class PostgisConnection extends PostgresConnection +{ /** * Get the default schema grammar instance. * @@ -18,13 +14,13 @@ public function __construct($pdo, $database = '', $tablePrefix = '', array $conf */ protected function getDefaultSchemaGrammar() { - return $this->withTablePrefix(new Schema\Grammars\PostgisGrammar); + return $this->withTablePrefix(new PostgisGrammar()); } public function getSchemaBuilder() { - if (is_null($this->schemaGrammar)) { + if ($this->schemaGrammar === null) { $this->useDefaultSchemaGrammar(); } diff --git a/src/Schema/Blueprint.php b/src/Schema/Blueprint.php index a321284..3adfd44 100644 --- a/src/Schema/Blueprint.php +++ b/src/Schema/Blueprint.php @@ -1,4 +1,4 @@ -addColumn('point', $column, compact('geomtype', 'srid')); } + /** + * Add a point column on the table + * + * @param $column + * @return \Illuminate\Support\Fluent + */ + public function pointz($column, $geomtype = 'GEOGRAPHY', $srid = '4326') + { + return $this->addColumn('pointz', $column, compact('geomtype', 'srid')); + } + /** * Add a multipoint column on the table * @@ -46,6 +57,17 @@ public function multipolygon($column, $geomtype = 'GEOGRAPHY', $srid = '4326') return $this->addColumn('multipolygon', $column, compact('geomtype', 'srid')); } + /** + * Add a multipolygonz column on the table + * + * @param $column + * @return \Illuminate\Support\Fluent + */ + public function multipolygonz($column, $geomtype = 'GEOGRAPHY', $srid = '4326') + { + return $this->addColumn('multipolygonz', $column, compact('geomtype', 'srid')); + } + /** * Add a linestring column on the table * @@ -57,6 +79,17 @@ public function linestring($column, $geomtype = 'GEOGRAPHY', $srid = '4326') return $this->addColumn('linestring', $column, compact('geomtype', 'srid')); } + /** + * Add a linestringz column on the table + * + * @param $column + * @return \Illuminate\Support\Fluent + */ + public function linestringz($column, $geomtype = 'GEOGRAPHY', $srid = '4326') + { + return $this->addColumn('linestringz', $column, compact('geomtype', 'srid')); + } + /** * Add a multilinestring column on the table * @@ -115,9 +148,21 @@ public function enablePostgis() return $this->addCommand('enablePostgis'); } + /** + * Enable postgis on this database. + * Will create the extension in the database if it doesn't already exist. + * + * @return \Illuminate\Support\Fluent + */ + public function enablePostgisIfNotExists() + { + return $this->addCommand('enablePostgisIfNotExists'); + } + /** * Disable postgis on this database. * WIll drop the extension in the database. + * * @return \Illuminate\Support\Fluent */ public function disablePostgis() @@ -125,4 +170,15 @@ public function disablePostgis() return $this->addCommand('disablePostgis'); } + /** + * Disable postgis on this database. + * WIll drop the extension in the database if it exists. + * + * @return \Illuminate\Support\Fluent + */ + public function disablePostgisIfExists() + { + return $this->addCommand('disablePostgisIfExists'); + } + } diff --git a/src/Schema/Builder.php b/src/Schema/Builder.php index a9519e9..52b78ed 100644 --- a/src/Schema/Builder.php +++ b/src/Schema/Builder.php @@ -1,4 +1,4 @@ -connection->statement( + $this->grammar->compileEnablePostgisIfNotExists() + ); + } + + /** + * Disable postgis on this database. + * WIll drop the extension in the database. * * @return bool */ @@ -39,4 +54,17 @@ public function disablePostgis() $this->grammar->compileDisablePostgis() ); } + + /** + * Disable postgis on this database. + * WIll drop the extension in the database if it exists. + * + * @return bool + */ + public function disablePostgisIfExists() + { + return $this->connection->statement( + $this->grammar->compileDisablePostgisIfExists() + ); + } } diff --git a/src/Schema/Grammars/PostgisGrammar.php b/src/Schema/Grammars/PostgisGrammar.php index f6b403d..9a67309 100644 --- a/src/Schema/Grammars/PostgisGrammar.php +++ b/src/Schema/Grammars/PostgisGrammar.php @@ -1,8 +1,8 @@ -geomtype); - if ($this->isValid($column)) { - if ($type == 'GEOGRAPHY' && $column->srid != 4326) { - throw new UnsupportedGeomtypeException('Error with validation of srid! SRID of GEOGRAPHY must be 4326)'); - } - return $type . '(POINT, ' . $column->srid . ')'; - } else { - throw new UnsupportedGeomtypeException('Error with validation of geom type or srid!'); - } + return $this->createTypeDefinition($column, 'POINT'); + } + + /** + * Adds a statement to add a pointz geometry column + * + * @param \Illuminate\Support\Fluent $column + * @return string + */ + public function typePointZ(Fluent $column) + { + return $this->createTypeDefinition($column, 'POINTZ'); } /** @@ -37,15 +40,7 @@ public function typePoint(Fluent $column) */ public function typeMultipoint(Fluent $column) { - $type = strtoupper($column->geomtype); - if ($this->isValid($column)) { - if ($type == 'GEOGRAPHY' && $column->srid != 4326) { - throw new UnsupportedGeomtypeException('Error with validation of srid! SRID of GEOGRAPHY must be 4326)'); - } - return strtoupper($column->geomtype) . '(MULTIPOINT, ' . $column->srid . ')'; - } else { - throw new UnsupportedGeomtypeException('Error with validation of geom type or srid!'); - } + return $this->createTypeDefinition($column, 'MULTIPOINT'); } /** @@ -56,15 +51,7 @@ public function typeMultipoint(Fluent $column) */ public function typePolygon(Fluent $column) { - $type = strtoupper($column->geomtype); - if ($this->isValid($column)) { - if ($type == 'GEOGRAPHY' && $column->srid != 4326) { - throw new UnsupportedGeomtypeException('Error with validation of srid! SRID of GEOGRAPHY must be 4326)'); - } - return strtoupper($column->geomtype) . '(POLYGON, ' . $column->srid . ')'; - } else { - throw new UnsupportedGeomtypeException('Error with validation of geom type or srid!'); - } + return $this->createTypeDefinition($column, 'POLYGON'); } /** @@ -75,15 +62,18 @@ public function typePolygon(Fluent $column) */ public function typeMultipolygon(Fluent $column) { - $type = strtoupper($column->geomtype); - if ($this->isValid($column)) { - if ($type == 'GEOGRAPHY' && $column->srid != 4326) { - throw new UnsupportedGeomtypeException('Error with validation of srid! SRID of GEOGRAPHY must be 4326)'); - } - return strtoupper($column->geomtype) . '(MULTIPOLYGON, ' . $column->srid . ')'; - } else { - throw new UnsupportedGeomtypeException('Error with validation of geom type or srid!'); - } + return $this->createTypeDefinition($column, 'MULTIPOLYGON'); + } + + /** + * Adds a statement to add a multipolygonz geometry column + * + * @param \Illuminate\Support\Fluent $column + * @return string + */ + public function typeMultiPolygonZ(Fluent $column) + { + return $this->createTypeDefinition($column, 'MULTIPOLYGONZ'); } /** @@ -94,15 +84,18 @@ public function typeMultipolygon(Fluent $column) */ public function typeLinestring(Fluent $column) { - $type = strtoupper($column->geomtype); - if ($this->isValid($column)) { - if ($type == 'GEOGRAPHY' && $column->srid != 4326) { - throw new UnsupportedGeomtypeException('Error with validation of srid! SRID of GEOGRAPHY must be 4326)'); - } - return strtoupper($column->geomtype) . '(LINESTRING, ' . $column->srid . ')'; - } else { - throw new UnsupportedGeomtypeException('Error with validation of geom type or srid!'); - } + return $this->createTypeDefinition($column, 'LINESTRING'); + } + + /** + * Adds a statement to add a linestringz geometry column + * + * @param \Illuminate\Support\Fluent $column + * @return string + */ + public function typeLinestringZ(Fluent $column) + { + return $this->createTypeDefinition($column, 'LINESTRINGZ'); } /** @@ -113,15 +106,7 @@ public function typeLinestring(Fluent $column) */ public function typeMultilinestring(Fluent $column) { - $type = strtoupper($column->geomtype); - if ($this->isValid($column)) { - if ($type == 'GEOGRAPHY' && $column->srid != 4326) { - throw new UnsupportedGeomtypeException('Error with validation of srid! SRID of GEOGRAPHY must be 4326)'); - } - return strtoupper($column->geomtype) . '(MULTILINESTRING, ' . $column->srid . ')'; - } else { - throw new UnsupportedGeomtypeException('Error with validation of geom type or srid!'); - } + return $this->createTypeDefinition($column, 'MULTILINESTRING'); } /** @@ -170,6 +155,16 @@ public function compileEnablePostgis() return 'CREATE EXTENSION postgis'; } + /** + * Adds a statement to create the postgis extension, if it doesn't already exist + * + * @return string + */ + public function compileEnablePostgisIfNotExists() + { + return 'CREATE EXTENSION IF NOT EXISTS postgis'; + } + /** * Adds a statement to drop the postgis extension * @@ -180,6 +175,16 @@ public function compileDisablePostgis() return 'DROP EXTENSION postgis'; } + /** + * Adds a statement to drop the postgis extension, if it exists + * + * @return string + */ + public function compileDisablePostgisIfExists() + { + return 'DROP EXTENSION IF EXISTS postgis'; + } + /** * Adds a statement to add a geometry column * @@ -193,15 +198,18 @@ protected function compileGeometry(Blueprint $blueprint, Fluent $command) $dimensions = $command->dimensions ?: 2; $typmod = $command->typmod ? 'true' : 'false'; $srid = $command->srid ?: 4326; + $schema = function_exists('config') ? config('postgis.schema') : 'public'; return sprintf( - "SELECT AddGeometryColumn('%s', '%s', %d, '%s', %d, %s)", - $blueprint->getTable(), - $command->column, - $srid, - strtoupper($command->type), - $dimensions, - $typmod + "SELECT %s.AddGeometryColumn('%s', '%s', %d, '%s.%s', %d, %s)", + $schema, + $blueprint->getTable(), + $command->column, + $srid, + $schema, + strtoupper($command->type), + $dimensions, + $typmod ); } @@ -211,7 +219,30 @@ protected function compileGeometry(Blueprint $blueprint, Fluent $command) * @param \Illuminate\Support\Fluent $column * @return boolean */ - protected function isValid($column) { + protected function isValid($column) + { return in_array(strtoupper($column->geomtype), PostgisGrammar::$allowed_geom_types) && is_int((int) $column->srid); } + + /** + * Create definition for geometry types. + * @param Fluent $column + * @param string $geometryType + * @return string + * @throws UnsupportedGeomtypeException + */ + private function createTypeDefinition(Fluent $column, $geometryType) + { + $schema = function_exists('config') ? config('postgis.schema') : 'public'; + $type = strtoupper($column->geomtype); + if ($this->isValid($column)) { + if ($type == 'GEOGRAPHY' && $column->srid != 4326) { + throw new UnsupportedGeomtypeException('Error with validation of srid! SRID of GEOGRAPHY must be 4326)'); + } + return $schema . '.' . $type . '(' . $geometryType . ', ' . $column->srid . ')'; + } else { + throw new UnsupportedGeomtypeException('Error with validation of geom type or srid!'); + } + } + } diff --git a/tests/BaseTestCase.php b/tests/BaseTestCase.php index 48c9acc..7cd87ac 100644 --- a/tests/BaseTestCase.php +++ b/tests/BaseTestCase.php @@ -1,8 +1,13 @@ queryBuilder = m::mock(QueryBuilder::class); $this->queryBuilder->makePartial(); $this->queryBuilder - ->shouldReceive('from') - ->andReturn($this->queryBuilder); + ->shouldReceive('from') + ->andReturn($this->queryBuilder); $this->queryBuilder - ->shouldReceive('take') - ->with(1) - ->andReturn($this->queryBuilder); + ->shouldReceive('take') + ->with(1) + ->andReturn($this->queryBuilder); $this->queryBuilder - ->shouldReceive('get') - ->andReturn([]); + ->shouldReceive('get') + ->andReturn([]); $this->builder = new Builder($this->queryBuilder); - $this->builder->setModel(new TestBuilderModel()); + $this->builder->setModel(new class extends Model { + use PostgisTrait; + protected $postgisFields = [ + 'point' => Point::class, + 'linestring' => LineString::class, + 'polygon' => Polygon::class + ]; + }); } public function testUpdate() { $this->queryBuilder - ->shouldReceive('raw') - ->with("public.ST_GeogFromText('POINT(2 1)')") - ->andReturn(new Expression("public.ST_GeogFromText('POINT(2 1)')")); + ->shouldReceive('raw') + ->with("public.ST_GeogFromText('POINT(2 1)')") + ->andReturn(new Expression("public.ST_GeogFromText('POINT(2 1)')")); $this->queryBuilder - ->shouldReceive('update') - ->andReturn(1); + ->shouldReceive('update') + ->andReturn(1); $builder = m::mock(Builder::class, [$this->queryBuilder])->makePartial(); $builder->shouldAllowMockingProtectedMethods(); $builder - ->shouldReceive('addUpdatedAtColumn') - ->andReturn(['point' => new Point(1, 2)]); + ->shouldReceive('addUpdatedAtColumn') + ->andReturn(['point' => new Point(1, 2)]); $builder->update(['point' => new Point(1, 2)]); } @@ -65,36 +74,70 @@ public function testUpdate() public function testUpdateLinestring() { $this->queryBuilder - ->shouldReceive('raw') - ->with("public.ST_GeogFromText('LINESTRING(0 0, 1 1, 2 2)')") - ->andReturn(new Expression("public.ST_GeogFromText('LINESTRING(0 0, 1 1, 2 2)')")); + ->shouldReceive('raw') + ->with("public.ST_GeogFromText('LINESTRING(0 0, 1 1, 2 2)')") + ->andReturn(new Expression("public.ST_GeogFromText('LINESTRING(0 0, 1 1, 2 2)')")); $this->queryBuilder - ->shouldReceive('update') - ->andReturn(1); + ->shouldReceive('update') + ->andReturn(1); $linestring = new LineString([new Point(0, 0), new Point(1, 1), new Point(2, 2)]); $builder = m::mock(Builder::class, [$this->queryBuilder])->makePartial(); $builder->shouldAllowMockingProtectedMethods(); $builder - ->shouldReceive('addUpdatedAtColumn') - ->andReturn(['linestring' => $linestring]); + ->shouldReceive('addUpdatedAtColumn') + ->andReturn(['linestring' => $linestring]); $builder - ->shouldReceive('asWKT')->with($linestring)->once(); + ->shouldReceive('asWKT')->with($linestring)->once(); $builder->update(['linestring' => $linestring]); } -} -class TestBuilderModel extends Model -{ - use PostgisTrait; + public function testUpdate3d() + { + $this->queryBuilder + ->shouldReceive('raw') + ->with("public.ST_GeogFromText('POINT Z(2 1 0)')") + ->andReturn(new Expression("public.ST_GeogFromText('POINT Z(2 1 0)')")); + + $this->queryBuilder + ->shouldReceive('update') + ->andReturn(1); - protected $postgisFields = [ - 'point' => Point::class, - 'linestring' => LineString::class, - 'polygon' => Polygon::class - ]; + $builder = m::mock(Builder::class, [$this->queryBuilder])->makePartial(); + $builder->shouldAllowMockingProtectedMethods(); + $builder + ->shouldReceive('addUpdatedAtColumn') + ->andReturn(['point' => new Point(1, 2, 0)]); + + $builder->update(['point' => new Point(1, 2, 0)]); + } + + public function testUpdateLinestring3d() + { + $this->queryBuilder + ->shouldReceive('raw') + ->with("public.ST_GeogFromText('LINESTRING Z(0 0 0, 1 1 1, 2 2 2)')") + ->andReturn(new Expression("public.ST_GeogFromText('LINESTRING Z(0 0 0, 1 1 1, 2 2 2)')")); + + $this->queryBuilder + ->shouldReceive('update') + ->andReturn(1); + + $linestring = new LineString([new Point(0, 0, 0), new Point(1, 1, 1), new Point(2, 2, 2)]); + + $builder = m::mock(Builder::class, [$this->queryBuilder])->makePartial(); + $builder->shouldAllowMockingProtectedMethods(); + $builder + ->shouldReceive('addUpdatedAtColumn') + ->andReturn(['linestring' => $linestring]); + + $builder + ->shouldReceive('asWKT')->with($linestring)->once(); + + $builder->update(['linestring' => $linestring]); + } } diff --git a/tests/Eloquent/PostgisTraitTest.php b/tests/Eloquent/PostgisTraitTest.php deleted file mode 100644 index 2cd2487..0000000 --- a/tests/Eloquent/PostgisTraitTest.php +++ /dev/null @@ -1,139 +0,0 @@ -model = new TestModel(); - $this->queries = &$this->model->getConnection()->getPdo()->queries; - } - - public function tearDown() - { - $this->model->getConnection()->getPdo()->resetQueries(); - } - - public function testInsertPointHasCorrectSql() - { - $this->model->point = new Point(1, 2); - $this->model->save(); - - $this->assertContains("public.ST_GeogFromText('POINT(2 1)')", $this->queries[0]); - } - - public function testInsertPointGeometryHasCorrectSql() - { - $this->model->point2 = new Point(1, 2); - $this->model->save(); - - $this->assertContains("public.ST_GeomFromText('POINT(2 1)', '27700')", $this->queries[0]); - } - - public function testUpdatePointHasCorrectSql() - { - $this->model->exists = true; - $this->model->point = new Point(2, 4); - $this->model->save(); - - $this->assertContains("public.ST_GeogFromText('POINT(4 2)')", $this->queries[0]); - } -} - -class TestModel extends Model -{ - use PostgisTrait; - - protected $postgisFields = [ - 'point' => Point::class, - 'point2' => Polygon::class, - ]; - - protected $postgisTypes = [ - 'point2' => [ - 'geomtype' => 'geometry', - 'srid' => 27700 - ] - ]; - - - public static $pdo; - - public static function resolveConnection($connection = null) - { - if (is_null(static::$pdo)) { - static::$pdo = m::mock('TestPDO')->makePartial(); - } - - return new PostgisConnection(static::$pdo); - } - - public function testrelatedmodels() - { - return $this->hasMany(TestRelatedModel::class); - } - - public function testrelatedmodels2() - { - return $this->belongsToMany(TestRelatedModel::class); - } - -} - -class TestRelatedModel extends TestModel -{ - public function testmodel() - { - return $this->belongsTo(TestModel::class); - } - - public function testmodels() - { - return $this->belongsToMany(TestModel::class); - } -} - -class TestPDO extends PDO -{ - public $queries = []; - public $counter = 1; - - public function prepare($statement, $driver_options = null) - { - $this->queries[] = $statement; - - $stmt = m::mock('PDOStatement'); - $stmt->shouldReceive('setFetchMode'); - $stmt->shouldReceive('bindValue')->zeroOrMoreTimes(); - $stmt->shouldReceive('execute'); - $stmt->shouldReceive('fetchAll')->andReturn([['id' => 1, 'point' => 'POINT(1 2)']]); - $stmt->shouldReceive('rowCount')->andReturn(1); - - return $stmt; - } - - public function lastInsertId($name = null) - { - return $this->counter++; - } - - public function resetQueries() - { - $this->queries = []; - } -} diff --git a/tests/Geometries/GeometryCollectionTest.php b/tests/Geometries/GeometryCollectionTest.php index f98b0c6..7bf86e4 100644 --- a/tests/Geometries/GeometryCollectionTest.php +++ b/tests/Geometries/GeometryCollectionTest.php @@ -1,8 +1,11 @@ collection = new GeometryCollection([$collection, $point]); + + $collection = new LineString( + [ + new Point(1, 1, 1), + new Point(1, 2, 3), + new Point(2, 2, 2), + new Point(2, 1, 0), + new Point(1, 1, 1) + ] + ); + + $point = new Point(100, 200, 300); + + $this->collection3d = new GeometryCollection([$collection, $point]); } @@ -42,6 +60,19 @@ public function testFromWKT() $this->assertInstanceOf(LineString::class, $geometryCollection->getGeometries()[1]); } + public function testFromWKT3d() + { + /** + * @var GeometryCollection $geometryCollection + */ + $geometryCollection = GeometryCollection::fromWKT('GEOMETRYCOLLECTION(POINT Z(2 3 4),LINESTRING Z(2 3 4,3 4 5))'); + $this->assertInstanceOf(GeometryCollection::class, $geometryCollection); + + $this->assertEquals(2, $geometryCollection->count()); + $this->assertInstanceOf(Point::class, $geometryCollection->getGeometries()[0]); + $this->assertInstanceOf(LineString::class, $geometryCollection->getGeometries()[1]); + } + public function testToWKT() { $this->assertEquals( @@ -50,6 +81,14 @@ public function testToWKT() ); } + public function testToWKT3d() + { + $this->assertEquals( + 'GEOMETRYCOLLECTION(LINESTRING Z(1 1 1,2 1 3,2 2 2,1 2 0,1 1 1),POINT Z(200 100 300))', + $this->collection3d->toWKT() + ); + } + public function testJsonSerialize() { $this->assertInstanceOf( @@ -63,4 +102,18 @@ public function testJsonSerialize() ); } + + public function testJsonSerialize3d() + { + $this->assertInstanceOf( + \GeoJson\Geometry\GeometryCollection::class, + $this->collection3d->jsonSerialize() + ); + + $this->assertSame( + '{"type":"GeometryCollection","geometries":[{"type":"LineString","coordinates":[[1,1,1],[2,1,3],[2,2,2],[1,2,0],[1,1,1]]},{"type":"Point","coordinates":[200,100,300]}]}', + json_encode($this->collection3d->jsonSerialize()) + ); + + } } diff --git a/tests/Geometries/GeometryTest.php b/tests/Geometries/GeometryTest.php index 3c0bd7e..5d0a134 100644 --- a/tests/Geometries/GeometryTest.php +++ b/tests/Geometries/GeometryTest.php @@ -1,13 +1,16 @@ assertEquals( + '1 1 1', + Geometry::getWKTArgument('POINT Z(1 1 1)') + ); + $this->assertEquals( + '1 1 1,1 2 2,2 2 3', + Geometry::getWKTArgument('LINESTRING Z(1 1 1,1 2 2,2 2 3)') + ); + $this->assertEquals( + '(1 1 1,4 1 1,4 4 1,1 4 1,1 1 1),(1 1 2, 2 1 2, 2 2 2, 1 2 2,1 1 2)', + Geometry::getWKTArgument('POLYGON Z((1 1 1,4 1 1,4 4 1,1 4 1,1 1 1),(1 1 2, 2 1 2, 2 2 2, 1 2 2,1 1 2))') + ); + $this->assertEquals( + '(1 1 1),(1 2 2)', + Geometry::getWKTArgument('MULTIPOINT Z((1 1 1),(1 2 2))') + ); + $this->assertEquals( + '(1 1 1,1 2 1,2 2 1),(2 3 2,3 2 2,5 4 2)', + Geometry::getWKTArgument('MULTILINESTRING Z((1 1 1,1 2 1,2 2 1),(2 3 2,3 2 2,5 4 2))') + ); + $this->assertEquals( + '((1 1 1,4 1 1,4 4 1,1 4 1,1 1 1),(1 1 2,2 1 2,2 2 2,1 2 2,1 1 2)), ((-1 -1 -1,-1 -2 -1,-2 -2 -1,-2 -1 -1,-1 -1 -1))', + Geometry::getWKTArgument('MULTIPOLYGON Z(((1 1 1,4 1 1,4 4 1,1 4 1,1 1 1),(1 1 2,2 1 2,2 2 2,1 2 2,1 1 2)), ((-1 -1 -1,-1 -2 -1,-2 -2 -1,-2 -1 -1,-1 -1 -1)))') + ); + $this->assertEquals( + 'POINT Z(2 3 4),LINESTRING Z(2 3 4,3 4 5)', + Geometry::getWKTArgument('GEOMETRYCOLLECTION(POINT Z(2 3 4),LINESTRING Z(2 3 4,3 4 5))') + ); + } + public function testGetWKTClass() { $this->assertEquals( @@ -75,6 +110,38 @@ public function testGetWKTClass() ); } + public function testGetWKTClass3d() + { + $this->assertEquals( + Point::class, + Geometry::getWKTClass('POINT Z(0 0 0)') + ); + $this->assertEquals( + LineString::class, + Geometry::getWKTClass('LINESTRING Z(0 0 0,1 1 1,1 2 3)') + ); + $this->assertEquals( + Polygon::class, + Geometry::getWKTClass('POLYGON Z((0 0 0 ,4 0 3,4 4 4,0 4 0,0 0 0),(1 1 1, 2 1 2, 2 2 2, 1 2 2,1 1 1))') + ); + $this->assertEquals( + MultiPoint::class, + Geometry::getWKTClass('MULTIPOINT Z((0 00),(1 2 3))') + ); + $this->assertEquals( + MultiLineString::class, + Geometry::getWKTClass('MULTILINESTRING Z((0 0 0 ,1 1 1,1 2 3),(2 3 4,3 2 1,5 4 3))') + ); + $this->assertEquals( + MultiPolygon::class, + Geometry::getWKTClass('MULTIPOLYGON Z(((0 0 0,4 0 4,4 4 4,0 4 0,0 0 0),(1 1 1,2 1 2,2 2 2,1 2 2,1 1 1)), ((-1 -1 -1,-1 -2 -1,-2 -2 -1,-2 -1 -1,-1 -1 -1)))') + ); + $this->assertEquals( + GeometryCollection::class, + Geometry::getWKTClass('GEOMETRYCOLLECTION(POINT Z(2 3 4),LINESTRING Z(2 3 4,3 4 5))') + ); + } + public function testGetWKBClass() { $this->assertInstanceOf( diff --git a/tests/Geometries/LineStringTest.php b/tests/Geometries/LineStringTest.php index de69ed1..ba49d62 100644 --- a/tests/Geometries/LineStringTest.php +++ b/tests/Geometries/LineStringTest.php @@ -1,15 +1,20 @@ points = [new Point(1, 1), new Point(2, 2), new Point(3, 3)]; + $this->points3d = [new Point(1, 1, 1), new Point(2, 2, 2), new Point(3, 3, 3)]; } public function testToWKT() @@ -19,6 +24,13 @@ public function testToWKT() $this->assertEquals('LINESTRING(1 1,2 2,3 3)', $linestring->toWKT()); } + public function testToWKT3d() + { + $linestring = new LineString($this->points3d); + + $this->assertEquals('LINESTRING Z(1 1 1,2 2 2,3 3 3)', $linestring->toWKT()); + } + public function testFromWKT() { $linestring = LineString::fromWKT('LINESTRING(1 1, 2 2,3 3)'); @@ -27,6 +39,14 @@ public function testFromWKT() $this->assertEquals(3, $linestring->count()); } + public function testFromWKT3d() + { + $linestring = LineString::fromWKT('LINESTRING Z(1 1 1, 2 2 2,3 3 3)'); + $this->assertInstanceOf(LineString::class, $linestring); + + $this->assertEquals(3, $linestring->count()); + } + public function testToString() { $linestring = new LineString($this->points); @@ -34,6 +54,13 @@ public function testToString() $this->assertEquals('1 1,2 2,3 3', (string)$linestring); } + public function testToString3d() + { + $linestring = new LineString($this->points3d); + + $this->assertEquals('1 1 1,2 2 2,3 3 3', (string)$linestring); + } + public function testJsonSerialize() { $lineString = new LineString($this->points); @@ -41,4 +68,12 @@ public function testJsonSerialize() $this->assertInstanceOf(\GeoJson\Geometry\LineString::class, $lineString->jsonSerialize()); $this->assertSame('{"type":"LineString","coordinates":[[1,1],[2,2],[3,3]]}', json_encode($lineString)); } + + public function testJsonSerialize3d() + { + $lineString = new LineString($this->points3d); + + $this->assertInstanceOf(\GeoJson\Geometry\LineString::class, $lineString->jsonSerialize()); + $this->assertSame('{"type":"LineString","coordinates":[[1,1,1],[2,2,2],[3,3,3]]}', json_encode($lineString)); + } } diff --git a/tests/Geometries/MultiLineStringTest.php b/tests/Geometries/MultiLineStringTest.php index cdaa757..d8cdac7 100644 --- a/tests/Geometries/MultiLineStringTest.php +++ b/tests/Geometries/MultiLineStringTest.php @@ -1,8 +1,11 @@ assertSame(2, $multilinestring->count()); } + public function testFromWKT3d() + { + $multilinestring = MultiLineString::fromWKT('MULTILINESTRING Z((1 1 1,2 2 2,2 3 4),(3 4 5,4 3 2,6 5 4))'); + $this->assertInstanceOf(MultiLineString::class, $multilinestring); + + $this->assertSame(2, $multilinestring->count()); + } + public function testToWKT() { $collection = new LineString( @@ -31,13 +42,30 @@ public function testToWKT() $this->assertSame('MULTILINESTRING((1 1,2 1,2 2,1 2,1 1))', $multilinestring->toWKT()); } + public function testToWKT3d() + { + $collection = new LineString( + [ + new Point(1, 1, 1), + new Point(1, 2, 3), + new Point(2, 2, 2), + new Point(2, 1, 3), + new Point(1, 1, 1) + ] + ); + + $multilinestring = new MultiLineString([$collection]); + + $this->assertSame('MULTILINESTRING Z((1 1 1,2 1 3,2 2 2,1 2 3,1 1 1))', $multilinestring->toWKT()); + } + public function testJsonSerialize() { - $multilinestring = MultiLineString::fromWKT('MULTILINESTRING((1 1,2 2,2 3),(3 4,4 3,6 5))'); + $multilinestring = MultiLineString::fromWKT('MULTILINESTRING Z((1 1 1,2 2 2,2 3 4),(3 4 5,4 3 2,6 5 4))'); $this->assertInstanceOf(\GeoJson\Geometry\MultiLineString::class, $multilinestring->jsonSerialize()); $this->assertSame( - '{"type":"MultiLineString","coordinates":[[[1,1],[2,2],[2,3]],[[3,4],[4,3],[6,5]]]}', + '{"type":"MultiLineString","coordinates":[[[1,1,1],[2,2,2],[2,3,4]],[[3,4,5],[4,3,2],[6,5,4]]]}', json_encode($multilinestring) ); } diff --git a/tests/Geometries/MultiPointTest.php b/tests/Geometries/MultiPointTest.php index 49c246a..6f24f85 100644 --- a/tests/Geometries/MultiPointTest.php +++ b/tests/Geometries/MultiPointTest.php @@ -1,7 +1,10 @@ assertEquals(3, $multipoint->count()); } + public function testFromWKTWithFloatingPoint() + { + $multipoint = MultiPoint::fromWKT('MULTIPOINT((1.0 1.0),(2.0 1.0),(2.0 2.0))'); + $this->assertInstanceOf(MultiPoint::class, $multipoint); + + $this->assertEquals(3, $multipoint->count()); + } + + public function testFromWKTWithoutNestedParentesis() + { + $multipoint = MultiPoint::fromWKT('MULTIPOINT(1 1, 2 1, 2 2)'); + $this->assertInstanceOf(MultiPoint::class, $multipoint); + + $this->assertEquals(3, $multipoint->count()); + } + + public function testFromWKT3d() + { + $multipoint = MultiPoint::fromWKT('MULTIPOINT Z((1 1 1),(2 1 3),(2 2 2))'); + $this->assertInstanceOf(MultiPoint::class, $multipoint); + + $this->assertEquals(3, $multipoint->count()); + } + + public function testFromWKT3dWithoutNestedParentesis() + { + $multipoint = MultiPoint::fromWKT('MULTIPOINT Z(1 1 1, 2 1 3, 2 2 2)'); + $this->assertInstanceOf(MultiPoint::class, $multipoint); + + $this->assertEquals(3, $multipoint->count()); + } + public function testToWKT() { $collection = [new Point(1, 1), new Point(1, 2), new Point(2, 2)]; @@ -22,6 +57,15 @@ public function testToWKT() $this->assertEquals('MULTIPOINT((1 1),(2 1),(2 2))', $multipoint->toWKT()); } + public function testToWKT3d() + { + $collection = [new Point(1, 1, 1), new Point(1, 2, 3), new Point(2, 2, 2)]; + + $multipoint = new MultiPoint($collection); + + $this->assertEquals('MULTIPOINT Z((1 1 1),(2 1 3),(2 2 2))', $multipoint->toWKT()); + } + public function testJsonSerialize() { $collection = [new Point(1, 1), new Point(1, 2), new Point(2, 2)]; @@ -31,4 +75,14 @@ public function testJsonSerialize() $this->assertInstanceOf(\GeoJson\Geometry\MultiPoint::class, $multipoint->jsonSerialize()); $this->assertSame('{"type":"MultiPoint","coordinates":[[1,1],[2,1],[2,2]]}', json_encode($multipoint)); } + + public function testJsonSerialize3d() + { + $collection = [new Point(1, 1, 1), new Point(1, 2, 3), new Point(2, 2, 2)]; + + $multipoint = new MultiPoint($collection); + + $this->assertInstanceOf(\GeoJson\Geometry\MultiPoint::class, $multipoint->jsonSerialize()); + $this->assertSame('{"type":"MultiPoint","coordinates":[[1,1,1],[2,1,3],[2,2,2]]}', json_encode($multipoint)); + } } diff --git a/tests/Geometries/MultiPolygonTest.php b/tests/Geometries/MultiPolygonTest.php index 001d7e7..6f82117 100644 --- a/tests/Geometries/MultiPolygonTest.php +++ b/tests/Geometries/MultiPolygonTest.php @@ -1,9 +1,12 @@ multiPolygon = new MultiPolygon([$polygon1, $polygon2]); + + $collection1 = new LineString( + [ + new Point(1, 1, 1), + new Point(1, 2, 3), + new Point(2, 2, 2), + new Point(2, 1, 0), + new Point(1, 1, 1) + ] + ); + + $collection2 = new LineString( + [ + new Point(10, 10, 10), + new Point(10, 20, 30), + new Point(20, 20, 20), + new Point(20, 10, 0), + new Point(10, 10, 10) + ] + ); + + $polygon1 = new Polygon([$collection1, $collection2]); + + $collection3 = new LineString( + [ + new Point(100, 100, 100), + new Point(100, 200, 300), + new Point(200, 200, 200), + new Point(200, 100, 0), + new Point(100, 100, 100) + ] + ); + + + $polygon2 = new Polygon([$collection3]); + + $this->multiPolygon3d = new MultiPolygon([$polygon1, $polygon2]); } public function testFromWKT() { $wkt = 'MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1),(1 1,2 1,2 2,1 2,1 1)),((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))'; $polygon = MultiPolygon::fromWKT($wkt); - + $this->assertInstanceOf(MultiPolygon::class, $polygon); $this->assertEquals(2, $polygon->count()); $this->assertEquals($wkt, $polygon->toWKT()); } + public function testFromWKT3d() + { + $wkt = 'MULTIPOLYGON Z(((1 1 1,2 1 3,2 2 2,1 2 0,1 1 1),(1 1 1,2 1 3,2 2 2,1 2 0,1 1)),((-1 -1 -1,-1 -2 -3,-2 -2 -2,-2 -1 0,-1 -1 -1)))'; + $polygon = MultiPolygon::fromWKT($wkt); + + $this->assertInstanceOf(MultiPolygon::class, $polygon); + $this->assertEquals(2, $polygon->count()); + $this->assertEquals($wkt, $polygon->toWKT()); + } public function testToWKT() { @@ -71,10 +121,27 @@ public function testToWKT() ); } + public function testToWKT3d() + { + $this->assertEquals( + 'MULTIPOLYGON Z(((1 1 1,2 1 3,2 2 2,1 2 0,1 1 1),(10 10 10,20 10 30,20 20 20,10 20 0,10 10 10)),((100 100 100,200 100 300,200 200 200,100 200 0,100 100 100)))', + $this->multiPolygon3d->toWKT() + ); + } + public function testGetPolygons() { $polygon = MultiPolygon::fromWKT( - 'MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))' + 'MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))' + ); + + $this->assertInstanceOf(Polygon::class, $polygon->getPolygons()[0]); + } + + public function testGetPolygons3d() + { + $polygon = MultiPolygon::fromWKT( + 'MULTIPOLYGON Z(((0 0 0,4 0 0,4 4 4,0 4 0,0 0 0),(1 1 1,2 1 3,2 2 2,1 2 0,1 1 1)), ((-1 -1 -1,-1 -2 0,-2 -2 -2,-2 -1 -3,-1 -1 -1)))' ); $this->assertInstanceOf(Polygon::class, $polygon->getPolygons()[0]); @@ -83,7 +150,16 @@ public function testGetPolygons() public function testIssue12() { $polygon = MultiPolygon::fromWKT( - 'MULTIPOLYGON(((-80.214554 25.769598 0 0,-80.2147 25.774514 0 0,-80.212983 25.77456 0 0,-80.212977 25.773597 0 0,-80.211448 25.773655 0 0,-80.211498 25.774579 0 0,-80.209432 25.774665 0 0,-80.209392 25.773667 0 0,-80.204387 25.773834 0 0,-80.199383 25.774324 0 0,-80.197718 25.774031 0 0,-80.197757 25.774975 0 0,-80.193655 25.775108 0 0,-80.193623 25.774134 0 0,-80.191855 25.772551 0 0,-80.193442 25.76969 0 0,-80.192231 25.768345 0 0,-80.192879 25.758009 0 0,-80.196301 25.759985 0 0,-80.195608 25.76152 0 0,-80.198856 25.761454 0 0,-80.200646 25.763287 0 0,-80.20401 25.763164 0 0,-80.204023 25.76367 0 0,-80.205673 25.763141 0 0,-80.214326 25.762935 0 0,-80.214451 25.765883 0 0,-80.214539 25.768649 0 0,-80.216203 25.76858 0 0,-80.214554 25.769598 0 0)))' + 'MULTIPOLYGON(((-80.214554 25.769598 0 0,-80.2147 25.774514 0 0,-80.212983 25.77456 0 0,-80.212977 25.773597 0 0,-80.211448 25.773655 0 0,-80.211498 25.774579 0 0,-80.209432 25.774665 0 0,-80.209392 25.773667 0 0,-80.204387 25.773834 0 0,-80.199383 25.774324 0 0,-80.197718 25.774031 0 0,-80.197757 25.774975 0 0,-80.193655 25.775108 0 0,-80.193623 25.774134 0 0,-80.191855 25.772551 0 0,-80.193442 25.76969 0 0,-80.192231 25.768345 0 0,-80.192879 25.758009 0 0,-80.196301 25.759985 0 0,-80.195608 25.76152 0 0,-80.198856 25.761454 0 0,-80.200646 25.763287 0 0,-80.20401 25.763164 0 0,-80.204023 25.76367 0 0,-80.205673 25.763141 0 0,-80.214326 25.762935 0 0,-80.214451 25.765883 0 0,-80.214539 25.768649 0 0,-80.216203 25.76858 0 0,-80.214554 25.769598 0 0)))' + ); + + $this->assertInstanceOf(MultiPolygon::class, $polygon); + } + + public function testIssue123d() + { + $polygon = MultiPolygon::fromWKT( + 'MULTIPOLYGON Z(((-80.214554 25.769598 0 0,-80.2147 25.774514 0 0,-80.212983 25.77456 0 0,-80.212977 25.773597 0 0,-80.211448 25.773655 0 0,-80.211498 25.774579 0 0,-80.209432 25.774665 0 0,-80.209392 25.773667 0 0,-80.204387 25.773834 0 0,-80.199383 25.774324 0 0,-80.197718 25.774031 0 0,-80.197757 25.774975 0 0,-80.193655 25.775108 0 0,-80.193623 25.774134 0 0,-80.191855 25.772551 0 0,-80.193442 25.76969 0 0,-80.192231 25.768345 0 0,-80.192879 25.758009 0 0,-80.196301 25.759985 0 0,-80.195608 25.76152 0 0,-80.198856 25.761454 0 0,-80.200646 25.763287 0 0,-80.20401 25.763164 0 0,-80.204023 25.76367 0 0,-80.205673 25.763141 0 0,-80.214326 25.762935 0 0,-80.214451 25.765883 0 0,-80.214539 25.768649 0 0,-80.216203 25.76858 0 0,-80.214554 25.769598 0 0)))' ); $this->assertInstanceOf(MultiPolygon::class, $polygon); @@ -97,4 +173,13 @@ public function testJsonSerialize() json_encode($this->multiPolygon) ); } + + public function testJsonSerialize3d() + { + $this->assertInstanceOf(\GeoJson\Geometry\MultiPolygon::class, $this->multiPolygon3d->jsonSerialize()); + $this->assertSame( + '{"type":"MultiPolygon","coordinates":[[[[1,1,1],[2,1,3],[2,2,2],[1,2,0],[1,1,1]],[[10,10,10],[20,10,30],[20,20,20],[10,20,0],[10,10,10]]],[[[100,100,100],[200,100,300],[200,200,200],[100,200,0],[100,100,100]]]]}', + json_encode($this->multiPolygon3d) + ); + } } diff --git a/tests/Geometries/PointTest.php b/tests/Geometries/PointTest.php index f12ff09..f12a399 100644 --- a/tests/Geometries/PointTest.php +++ b/tests/Geometries/PointTest.php @@ -1,6 +1,9 @@ assertEquals(1, $point->getLng()); } + public function testFromWKT3d() + { + $point = Point::fromWKT('POINT(1 2 3)'); + + $this->assertInstanceOf(Point::class, $point); + $this->assertEquals(2, $point->getLat()); + $this->assertEquals(1, $point->getLng()); + $this->assertEquals(3, $point->getAlt()); + } + public function testToWKT() { $point = new Point(1, 2); @@ -20,6 +33,13 @@ public function testToWKT() $this->assertEquals('POINT(2 1)', $point->toWKT()); } + public function testToWKT3d() + { + $point = new Point(1, 2, 3); + + $this->assertEquals('POINT Z(2 1 3)', $point->toWKT()); + } + public function testGettersAndSetters() { $point = new Point(1, 2); @@ -33,6 +53,22 @@ public function testGettersAndSetters() $this->assertSame(4.0, $point->getLng()); } + public function testGettersAndSetters3d() + { + $point = new Point(1, 2, 3); + $this->assertSame(1.0, $point->getLat()); + $this->assertSame(2.0, $point->getLng()); + $this->assertSame(3.0, $point->getAlt()); + + $point->setLat('3'); + $point->setLng('4'); + $point->setAlt('5'); + + $this->assertSame(3.0, $point->getLat()); + $this->assertSame(4.0, $point->getLng()); + $this->assertSame(5.0, $point->getAlt()); + } + public function testPair() { $point = Point::fromPair('1.5 2'); @@ -43,6 +79,17 @@ public function testPair() $this->assertSame('1.5 2', $point->toPair()); } + public function testPair3d() + { + $point = Point::fromPair('1.5 2 2.5'); + + $this->assertSame(1.5, $point->getLng()); + $this->assertSame(2.0, $point->getLat()); + $this->assertSame(2.5, $point->getAlt()); + + $this->assertSame('1.5 2 2.5', $point->toPair()); + } + public function testToString() { $point = Point::fromString('1.3 2'); @@ -53,6 +100,17 @@ public function testToString() $this->assertEquals('1.3 2', (string)$point); } + public function testToString3d() + { + $point = Point::fromString('1.3 2 2.3'); + + $this->assertSame(1.3, $point->getLng()); + $this->assertSame(2.0, $point->getLat()); + $this->assertSame(2.3, $point->getAlt()); + + $this->assertEquals('1.3 2 2.3', (string)$point); + } + public function testJsonSerialize() { $point = new Point(1.2, 3.4); @@ -60,4 +118,28 @@ public function testJsonSerialize() $this->assertInstanceOf(\GeoJson\Geometry\Point::class, $point->jsonSerialize()); $this->assertSame('{"type":"Point","coordinates":[3.4,1.2]}', json_encode($point)); } + + public function testJsonSerialize3d() + { + $point = new Point(1.2, 3.4, 5.6); + + $this->assertInstanceOf(\GeoJson\Geometry\Point::class, $point->jsonSerialize()); + $this->assertSame('{"type":"Point","coordinates":[3.4,1.2,5.6]}', json_encode($point)); + } + + public function testPointPrecisionDefault() + { + $point = new Point(-37.8745505,144.9102885,12.38); + + $this->assertSame('144.910289 -37.87455 12.38', $point->toPair()); + + } + + public function testPointPrecision10() + { + $point = new Point(-37.87455051578,144.91028850798,7.38257341563); + $point->setPrecision(10); + + $this->assertSame('144.910288508 -37.8745505158 7.3825734156', $point->toPair()); + } } diff --git a/tests/Geometries/PolygonTest.php b/tests/Geometries/PolygonTest.php index 6f71432..b3059f7 100644 --- a/tests/Geometries/PolygonTest.php +++ b/tests/Geometries/PolygonTest.php @@ -1,14 +1,18 @@ polygon = new Polygon([$collection]); + + $collection = new LineString( + [ + new Point(1, 1, 1), + new Point(1, 2, 2), + new Point(2, 2, 2), + new Point(2, 1, 2), + new Point(1, 1, 1) + ] + ); + + $this->polygon3d = new Polygon([$collection]); } @@ -34,11 +50,26 @@ public function testFromWKT() $this->assertEquals($wkt, $polygon->toWKT()); } + public function testFromWKT3d() + { + $wkt = 'POLYGON Z((1 1 1,5 1 1,5 5 1,1 5 1,1 1 1),(2 2 2,3 2 2,3 3 2,2 3 2,2 2 2))'; + $polygon = Polygon::fromWKT($wkt); + $this->assertInstanceOf(Polygon::class, $polygon); + + $this->assertEquals(2, $polygon->count()); + $this->assertEquals($wkt, $polygon->toWKT()); + } + public function testToWKT() { $this->assertEquals('POLYGON((1 1,2 1,2 2,1 2,1 1))', $this->polygon->toWKT()); } + public function testToWKT3d() + { + $this->assertEquals('POLYGON Z((1 1 1,2 1 2,2 2 2,1 2 2,1 1 1))', $this->polygon3d->toWKT()); + } + public function testJsonSerialize() { $this->assertInstanceOf(\GeoJson\Geometry\Polygon::class, $this->polygon->jsonSerialize()); @@ -48,4 +79,14 @@ public function testJsonSerialize() ); } + + public function testJsonSerialize3d() + { + $this->assertInstanceOf(\GeoJson\Geometry\Polygon::class, $this->polygon3d->jsonSerialize()); + $this->assertSame( + '{"type":"Polygon","coordinates":[[[1,1,1],[2,1,2],[2,2,2],[1,2,2],[1,1,1]]]}', + json_encode($this->polygon3d) + ); + + } } diff --git a/tests/Geometries/UnderLocaleTest.php b/tests/Geometries/UnderLocaleTest.php index 8809241..9c146b6 100644 --- a/tests/Geometries/UnderLocaleTest.php +++ b/tests/Geometries/UnderLocaleTest.php @@ -1,46 +1,49 @@ markTestSkipped('The locale is not available for testing float output formatting'); } } - + public function testPointToWKT() { $point = new Point(1.5, 2.5); $this->assertEquals('POINT(2.5 1.5)', $point->toWKT()); } - + public function testMultiPointToWKT() { $multipoint = new MultiPoint([new Point(1.5, 1.5), new Point(1.5, 2.5), new Point(2.5, 2.5)]); $this->assertEquals('MULTIPOINT((1.5 1.5),(2.5 1.5),(2.5 2.5))', $multipoint->toWKT()); } - + public function testLineStringToWKT() { $linestring = new LineString([new Point(1.5, 1.5), new Point(2.5, 2.5), new Point(3.5, 3.5)]); @@ -64,7 +67,7 @@ public function testMultiLineStringToWKT() $this->assertSame('MULTILINESTRING((1.5 1.5,2.5 1.5,2.5 2.5,1.5 2.5,1.5 1.5))', $multilinestring->toWKT()); } - + public function testPolygonToWKT() { $collection = new LineString( @@ -78,10 +81,10 @@ public function testPolygonToWKT() ); $polygon = new Polygon([$collection]); - + $this->assertEquals('POLYGON((1.5 1.5,2.5 1.5,2.5 2.5,1.5 2.5,1.5 1.5))', $polygon->toWKT()); } - + public function testMultiPolygonToWKT() { $collection1 = new LineString( @@ -119,13 +122,13 @@ public function testMultiPolygonToWKT() $polygon2 = new Polygon([$collection3]); $multiPolygon = new MultiPolygon([$polygon1, $polygon2]); - + $this->assertEquals( 'MULTIPOLYGON(((1.5 1.5,2.5 1.5,2.5 2.5,1.5 2.5,1.5 1.5),(10.5 10.5,20.5 10.5,20.5 20.5,10.5 20.5,10.5 10.5)),((100.5 100.5,200.5 100.5,200.5 200.5,100.5 200.5,100.5 100.5)))', $multiPolygon->toWKT() ); } - + public function testGeometryCollectionToWKT() { $collection = new LineString( diff --git a/tests/PostgisConnectionTest.php b/tests/PostgisConnectionTest.php index caf336d..a9af3c2 100644 --- a/tests/PostgisConnectionTest.php +++ b/tests/PostgisConnectionTest.php @@ -1,14 +1,16 @@ 'pgsql', 'prefix' => 'prefix', 'database' => 'database', 'name' => 'foo']; $this->postgisConnection = new PostgisConnection(new PDOStub(), 'database', 'prefix', $pgConfig); diff --git a/tests/Schema/BlueprintTest.php b/tests/Schema/BlueprintTest.php index 6c74f3b..fcd6521 100644 --- a/tests/Schema/BlueprintTest.php +++ b/tests/Schema/BlueprintTest.php @@ -1,14 +1,16 @@ -blueprint->enablePostgis(); } + public function testEnablePostgisIfNotExists() + { + $this->blueprint + ->shouldReceive('addCommand') + ->with('enablePostgis', []); + + $this->blueprint->enablePostgisIfNotExists(); + } + public function testDisablePostgis() { $this->blueprint @@ -96,4 +107,13 @@ public function testDisablePostgis() $this->blueprint->disablePostgis(); } + + public function testDisablePostgisIfExists() + { + $this->blueprint + ->shouldReceive('addCommand') + ->with('disablePostgis', []); + + $this->blueprint->disablePostgisIfExists(); + } } diff --git a/tests/Schema/BuilderTest.php b/tests/Schema/BuilderTest.php index e6e43ae..e83f35e 100644 --- a/tests/Schema/BuilderTest.php +++ b/tests/Schema/BuilderTest.php @@ -1,10 +1,12 @@ -point('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOGRAPHY(POINT, 4326)', $statements[0]); + $this->assertCount(1, $statements); + $this->assertStringContainsString('GEOGRAPHY(POINT, 4326)', $statements[0]); } public function testAddingPointGeom() @@ -24,26 +27,26 @@ public function testAddingPointGeom() $blueprint = new Blueprint('test'); $blueprint->point('foo', 'GEOMETRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOMETRY(POINT, 27700)', $statements[0]); + $this->assertCount(1, $statements); + $this->assertStringContainsString('GEOMETRY(POINT, 27700)', $statements[0]); } public function testAddingPointWrongSrid() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->point('foo', 'GEOGRAPHY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements);; } public function testAddingPointUnsupported() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->point('foo', 'UNSUPPORTED_ENTRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements);; } public function testAddingLinestring() @@ -52,8 +55,8 @@ public function testAddingLinestring() $blueprint->linestring('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOGRAPHY(LINESTRING, 4326)', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('GEOGRAPHY(LINESTRING, 4326)', $statements[0]); } public function testAddingLinestringGeom() @@ -61,26 +64,26 @@ public function testAddingLinestringGeom() $blueprint = new Blueprint('test'); $blueprint->linestring('foo', 'GEOMETRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOMETRY(LINESTRING, 27700)', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('GEOMETRY(LINESTRING, 27700)', $statements[0]); } public function testAddingLinestringWrongSrid() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->linestring('foo', 'GEOGRAPHY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements);; } public function testAddingLinestringUnsupported() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->linestring('foo', 'UNSUPPORTED_ENTRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements); } public function testAddingPolygon() @@ -89,8 +92,8 @@ public function testAddingPolygon() $blueprint->polygon('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOGRAPHY(POLYGON, 4326)', $statements[0]); + $this->assertCount(1, $statements); + $this->assertStringContainsString('GEOGRAPHY(POLYGON, 4326)', $statements[0]); } public function testAddingPolygonGeom() @@ -98,26 +101,26 @@ public function testAddingPolygonGeom() $blueprint = new Blueprint('test'); $blueprint->polygon('foo', 'GEOMETRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOMETRY(POLYGON, 27700)', $statements[0]); + $this->assertCount(1, $statements); + $this->assertStringContainsString('GEOMETRY(POLYGON, 27700)', $statements[0]); } public function testAddingPolygonWrongSrid() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->polygon('foo', 'GEOGRAPHY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements); } public function testAddingPolygonUnsupported() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->polygon('foo', 'UNSUPPORTED_ENTRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements); } public function testAddingMultipoint() @@ -126,8 +129,8 @@ public function testAddingMultipoint() $blueprint->multipoint('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOGRAPHY(MULTIPOINT, 4326)', $statements[0]); + $this->assertCount(1, $statements); + $this->assertStringContainsString('GEOGRAPHY(MULTIPOINT, 4326)', $statements[0]); } public function testAddingMultipointGeom() @@ -135,26 +138,26 @@ public function testAddingMultipointGeom() $blueprint = new Blueprint('test'); $blueprint->multipoint('foo', 'GEOMETRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOMETRY(MULTIPOINT, 27700)', $statements[0]); + $this->assertCount(1, $statements); + $this->assertStringContainsString('GEOMETRY(MULTIPOINT, 27700)', $statements[0]); } public function testAddingMultiPointWrongSrid() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->multipoint('foo', 'GEOGRAPHY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements); } public function testAddingMultiPointUnsupported() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->multipoint('foo', 'UNSUPPORTED_ENTRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements);; } public function testAddingMultiLinestring() @@ -163,8 +166,8 @@ public function testAddingMultiLinestring() $blueprint->multilinestring('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOGRAPHY(MULTILINESTRING, 4326)', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('GEOGRAPHY(MULTILINESTRING, 4326)', $statements[0]); } public function testAddingMultiLinestringGeom() @@ -172,26 +175,26 @@ public function testAddingMultiLinestringGeom() $blueprint = new Blueprint('test'); $blueprint->multilinestring('foo', 'GEOMETRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOMETRY(MULTILINESTRING, 27700)', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('GEOMETRY(MULTILINESTRING, 27700)', $statements[0]); } public function testAddingMultiLinestringWrongSrid() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->multilinestring('foo', 'GEOGRAPHY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements);; } public function testAddingMultiLinestringUnsupported() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->multilinestring('foo', 'UNSUPPORTED_ENTRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements);; } public function testAddingMultiPolygon() @@ -200,8 +203,8 @@ public function testAddingMultiPolygon() $blueprint->multipolygon('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOGRAPHY(MULTIPOLYGON, 4326)', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('GEOGRAPHY(MULTIPOLYGON, 4326)', $statements[0]); } public function testAddingMultiPolygonGeom() @@ -209,26 +212,26 @@ public function testAddingMultiPolygonGeom() $blueprint = new Blueprint('test'); $blueprint->multipolygon('foo', 'GEOMETRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOMETRY(MULTIPOLYGON, 27700)', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('GEOMETRY(MULTIPOLYGON, 27700)', $statements[0]); } public function testAddingMultiPolygonWrongSrid() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->multipolygon('foo', 'GEOGRAPHY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements);; } public function testAddingMultiPolygonUnsupported() { - $this->setExpectedException(UnsupportedGeomtypeException::class); + $this->expectException(UnsupportedGeomtypeException::class); $blueprint = new Blueprint('test'); $blueprint->multipolygon('foo', 'UNSUPPORTED_ENTRY', 27700); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements);; } public function testAddingGeography() @@ -237,8 +240,8 @@ public function testAddingGeography() $blueprint->geography('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOGRAPHY', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('GEOGRAPHY', $statements[0]); } public function testAddingGeometry() @@ -246,8 +249,8 @@ public function testAddingGeometry() $blueprint = new Blueprint('test'); $blueprint->geometry('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('GEOMETRY', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('GEOMETRY', $statements[0]); } public function testAddingGeometryCollection() @@ -256,9 +259,9 @@ public function testAddingGeometryCollection() $blueprint->geometrycollection('foo'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('AddGeometryColumn', $statements[0]); - $this->assertContains('GEOMETRYCOLLECTION', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('AddGeometryColumn', $statements[0]); + $this->assertStringContainsString('GEOMETRYCOLLECTION', $statements[0]); } public function testEnablePostgis() @@ -267,8 +270,18 @@ public function testEnablePostgis() $blueprint->enablePostgis(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('CREATE EXTENSION postgis', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('CREATE EXTENSION postgis', $statements[0]); + } + + public function testEnablePostgisIfNotExists() + { + $blueprint = new Blueprint('test'); + $blueprint->enablePostgisIfNotExists(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements);; + $this->assertStringContainsString('CREATE EXTENSION IF NOT EXISTS postgis', $statements[0]); } public function testDisablePostgis() @@ -277,8 +290,18 @@ public function testDisablePostgis() $blueprint->disablePostgis(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); - $this->assertContains('DROP EXTENSION postgis', $statements[0]); + $this->assertCount(1, $statements);; + $this->assertStringContainsString('DROP EXTENSION postgis', $statements[0]); + } + + public function testDisablePostgisIfExists() + { + $blueprint = new Blueprint('test'); + $blueprint->disablePostgisIfExists(); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements);; + $this->assertStringContainsString('DROP EXTENSION IF EXISTS postgis', $statements[0]); } /** diff --git a/tests/Stubs/PDOStub.php b/tests/Stubs/PDOStub.php index 23d8b6e..89034d1 100644 --- a/tests/Stubs/PDOStub.php +++ b/tests/Stubs/PDOStub.php @@ -1,5 +1,6 @@