├── .gitignore
├── config
└── postgis.php
├── tests
├── Stubs
│ └── PDOStub.php
├── BaseTestCase.php
├── PostgisConnectionTest.php
├── Schema
│ ├── BuilderTest.php
│ ├── BlueprintTest.php
│ └── Grammars
│ │ └── PostgisGrammarTest.php
├── Connectors
│ └── ConnectionFactoryTest.php
├── Geometries
│ ├── MultiPointTest.php
│ ├── MultiLineStringTest.php
│ ├── LineStringTest.php
│ ├── PolygonTest.php
│ ├── PointTest.php
│ ├── UnderLocaleTest.php
│ ├── GeometryCollectionTest.php
│ ├── GeometryTest.php
│ └── MultiPolygonTest.php
└── Eloquent
│ └── BuilderTest.php
├── src
├── Exceptions
│ ├── UnknownWKTTypeException.php
│ ├── UnsupportedGeomtypeException.php
│ ├── PostgisTypesMalformedException.php
│ └── PostgisFieldsNotDefinedException.php
├── Geometries
│ ├── GeometryInterface.php
│ ├── Polygon.php
│ ├── Factory.php
│ ├── LineString.php
│ ├── Geometry.php
│ ├── MultiPoint.php
│ ├── GeometryCollection.php
│ ├── Point.php
│ ├── MultiLineString.php
│ ├── PointCollection.php
│ └── MultiPolygon.php
├── Eloquent
│ ├── Builder.php
│ └── PostgisTrait.php
├── PostgisConnection.php
├── Connectors
│ └── ConnectionFactory.php
├── DatabaseServiceProvider.php
└── Schema
│ ├── Builder.php
│ ├── Blueprint.php
│ └── Grammars
│ └── PostgisGrammar.php
├── database
└── migrations
│ └── enable_postgis.php.stub
├── phpunit.xml
├── phpunit.php
├── LICENSE
├── .github
└── workflows
│ └── run-tests.yml
├── composer.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | composer.lock
3 | .idea
4 |
5 | .phpunit.result.cache
6 | temp
--------------------------------------------------------------------------------
/config/postgis.php:
--------------------------------------------------------------------------------
1 | 'public' // Schema for the Postgis extension
5 | ];
6 |
--------------------------------------------------------------------------------
/tests/Stubs/PDOStub.php:
--------------------------------------------------------------------------------
1 |
2 |
81 | * Count elements of an object
82 | *
83 | * @link http://php.net/manual/en/countable.count.php
84 | * @return int The custom count as an integer.
85 | *
87 | * The return value is cast to an integer. 88 | */ 89 | public function count() 90 | { 91 | return count($this->polygons); 92 | } 93 | 94 | /** 95 | * Get the polygons that make up this MultiPolygon 96 | * 97 | * @return array|Polygon[] 98 | */ 99 | public function getPolygons() 100 | { 101 | return $this->polygons; 102 | } 103 | 104 | /** 105 | * Make an array like this: 106 | * "((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1", 107 | * ")), ((", 108 | * "-1 -1,-1 -2,-2 -2,-2 -1,-1 -1", 109 | * ")), ((", 110 | * "-1 -1,-1 -2,-2 -2,-2 -1,-1 -1))" 111 | * 112 | * Into: 113 | * "((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1))", 114 | * "((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1))", 115 | * "((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1))" 116 | * 117 | * @param array $parts 118 | * @return array 119 | */ 120 | protected static function assembleParts(array $parts) 121 | { 122 | $polygons = []; 123 | $count = count($parts); 124 | 125 | for ($i = 0; $i < $count; $i++) { 126 | if ($i % 2 !== 0) { 127 | list($end, $start) = explode(',', $parts[$i]); 128 | $polygons[$i - 1] .= $end; 129 | $polygons[++$i] = $start . $parts[$i]; 130 | } else { 131 | $polygons[] = $parts[$i]; 132 | } 133 | } 134 | 135 | return $polygons; 136 | } 137 | 138 | /** 139 | * Convert to GeoJson MultiPolygon that is jsonable to GeoJSON 140 | * 141 | * @return \GeoJson\Geometry\MultiPolygon 142 | */ 143 | public function jsonSerialize(): mixed 144 | { 145 | $polygons = []; 146 | foreach ($this->polygons as $polygon) { 147 | $polygons[] = $polygon->jsonSerialize(); 148 | } 149 | 150 | return new \GeoJson\Geometry\MultiPolygon($polygons); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /tests/Geometries/PointTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(Point::class, $point); 17 | $this->assertEquals(2, $point->getLat()); 18 | $this->assertEquals(1, $point->getLng()); 19 | $this->assertEquals($geojson, $point->toGeoJSON()); 20 | } 21 | 22 | public function testFromGeoJSON3d() 23 | { 24 | $geojson = new \GeoJson\Geometry\Point([1, 2, 3]); 25 | 26 | $point = Point::fromGeoJSON($geojson); 27 | 28 | $this->assertInstanceOf(Point::class, $point); 29 | $this->assertEquals(2, $point->getLat()); 30 | $this->assertEquals(1, $point->getLng()); 31 | $this->assertEquals(3, $point->getAlt()); 32 | $this->assertEquals($geojson, $point->toGeoJSON()); 33 | } 34 | 35 | public function testFromWKT() 36 | { 37 | $point = Point::fromWKT('POINT(1 2)'); 38 | 39 | $this->assertInstanceOf(Point::class, $point); 40 | $this->assertEquals(2, $point->getLat()); 41 | $this->assertEquals(1, $point->getLng()); 42 | } 43 | 44 | public function testFromWKT3d() 45 | { 46 | $point = Point::fromWKT('POINT(1 2 3)'); 47 | 48 | $this->assertInstanceOf(Point::class, $point); 49 | $this->assertEquals(2, $point->getLat()); 50 | $this->assertEquals(1, $point->getLng()); 51 | $this->assertEquals(3, $point->getAlt()); 52 | } 53 | 54 | public function testToWKT() 55 | { 56 | $point = new Point(1, 2); 57 | 58 | $this->assertEquals('POINT(2 1)', $point->toWKT()); 59 | } 60 | 61 | public function testToWKT3d() 62 | { 63 | $point = new Point(1, 2, 3); 64 | 65 | $this->assertEquals('POINT Z(2 1 3)', $point->toWKT()); 66 | } 67 | 68 | public function testGettersAndSetters() 69 | { 70 | $point = new Point(1, 2); 71 | $this->assertSame(1.0, $point->getLat()); 72 | $this->assertSame(2.0, $point->getLng()); 73 | 74 | $point->setLat('3'); 75 | $point->setLng('4'); 76 | 77 | $this->assertSame(3.0, $point->getLat()); 78 | $this->assertSame(4.0, $point->getLng()); 79 | } 80 | 81 | public function testGettersAndSetters3d() 82 | { 83 | $point = new Point(1, 2, 3); 84 | $this->assertSame(1.0, $point->getLat()); 85 | $this->assertSame(2.0, $point->getLng()); 86 | $this->assertSame(3.0, $point->getAlt()); 87 | 88 | $point->setLat('3'); 89 | $point->setLng('4'); 90 | $point->setAlt('5'); 91 | 92 | $this->assertSame(3.0, $point->getLat()); 93 | $this->assertSame(4.0, $point->getLng()); 94 | $this->assertSame(5.0, $point->getAlt()); 95 | } 96 | 97 | public function testPair() 98 | { 99 | $point = Point::fromPair('1.5 2'); 100 | 101 | $this->assertSame(1.5, $point->getLng()); 102 | $this->assertSame(2.0, $point->getLat()); 103 | 104 | $this->assertSame('1.5 2', $point->toPair()); 105 | } 106 | 107 | public function testPair3d() 108 | { 109 | $point = Point::fromPair('1.5 2 2.5'); 110 | 111 | $this->assertSame(1.5, $point->getLng()); 112 | $this->assertSame(2.0, $point->getLat()); 113 | $this->assertSame(2.5, $point->getAlt()); 114 | 115 | $this->assertSame('1.5 2 2.5', $point->toPair()); 116 | } 117 | 118 | public function testToString() 119 | { 120 | $point = Point::fromString('1.3 2'); 121 | 122 | $this->assertSame(1.3, $point->getLng()); 123 | $this->assertSame(2.0, $point->getLat()); 124 | 125 | $this->assertEquals('1.3 2', (string)$point); 126 | } 127 | 128 | public function testToString3d() 129 | { 130 | $point = Point::fromString('1.3 2 2.3'); 131 | 132 | $this->assertSame(1.3, $point->getLng()); 133 | $this->assertSame(2.0, $point->getLat()); 134 | $this->assertSame(2.3, $point->getAlt()); 135 | 136 | $this->assertEquals('1.3 2 2.3', (string)$point); 137 | } 138 | 139 | public function testJsonSerialize() 140 | { 141 | $point = new Point(1.2, 3.4); 142 | 143 | $this->assertInstanceOf(\GeoJson\Geometry\Point::class, $point->jsonSerialize()); 144 | $this->assertSame('{"type":"Point","coordinates":[3.4,1.2]}', json_encode($point)); 145 | } 146 | 147 | public function testJsonSerialize3d() 148 | { 149 | $point = new Point(1.2, 3.4, 5.6); 150 | 151 | $this->assertInstanceOf(\GeoJson\Geometry\Point::class, $point->jsonSerialize()); 152 | $this->assertSame('{"type":"Point","coordinates":[3.4,1.2,5.6]}', json_encode($point)); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /tests/Geometries/UnderLocaleTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped('The locale is not available for testing float output formatting'); 31 | } 32 | } 33 | 34 | public function testPointToWKT() 35 | { 36 | $point = new Point(1.5, 2.5); 37 | $this->assertEquals('POINT(2.5 1.5)', $point->toWKT()); 38 | } 39 | 40 | public function testMultiPointToWKT() 41 | { 42 | $multipoint = new MultiPoint([new Point(1.5, 1.5), new Point(1.5, 2.5), new Point(2.5, 2.5)]); 43 | 44 | $this->assertEquals('MULTIPOINT((1.5 1.5),(2.5 1.5),(2.5 2.5))', $multipoint->toWKT()); 45 | } 46 | 47 | public function testLineStringToWKT() 48 | { 49 | $linestring = new LineString([new Point(1.5, 1.5), new Point(2.5, 2.5), new Point(3.5, 3.5)]); 50 | 51 | $this->assertEquals('LINESTRING(1.5 1.5,2.5 2.5,3.5 3.5)', $linestring->toWKT()); 52 | } 53 | 54 | public function testMultiLineStringToWKT() 55 | { 56 | $collection = new LineString( 57 | [ 58 | new Point(1.5, 1.5), 59 | new Point(1.5, 2.5), 60 | new Point(2.5, 2.5), 61 | new Point(2.5, 1.5), 62 | new Point(1.5, 1.5) 63 | ] 64 | ); 65 | 66 | $multilinestring = new MultiLineString([$collection]); 67 | 68 | $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()); 69 | } 70 | 71 | public function testPolygonToWKT() 72 | { 73 | $collection = new LineString( 74 | [ 75 | new Point(1.5, 1.5), 76 | new Point(1.5, 2.5), 77 | new Point(2.5, 2.5), 78 | new Point(2.5, 1.5), 79 | new Point(1.5, 1.5) 80 | ] 81 | ); 82 | 83 | $polygon = new Polygon([$collection]); 84 | 85 | $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()); 86 | } 87 | 88 | public function testMultiPolygonToWKT() 89 | { 90 | $collection1 = new LineString( 91 | [ 92 | new Point(1.5, 1.5), 93 | new Point(1.5, 2.5), 94 | new Point(2.5, 2.5), 95 | new Point(2.5, 1.5), 96 | new Point(1.5, 1.5) 97 | ] 98 | ); 99 | 100 | $collection2 = new LineString( 101 | [ 102 | new Point(10.5, 10.5), 103 | new Point(10.5, 20.5), 104 | new Point(20.5, 20.5), 105 | new Point(20.5, 10.5), 106 | new Point(10.5, 10.5) 107 | ] 108 | ); 109 | 110 | $polygon1 = new Polygon([$collection1, $collection2]); 111 | 112 | $collection3 = new LineString( 113 | [ 114 | new Point(100.5, 100.5), 115 | new Point(100.5, 200.5), 116 | new Point(200.5, 200.5), 117 | new Point(200.5, 100.5), 118 | new Point(100.5, 100.5) 119 | ] 120 | ); 121 | 122 | $polygon2 = new Polygon([$collection3]); 123 | 124 | $multiPolygon = new MultiPolygon([$polygon1, $polygon2]); 125 | 126 | $this->assertEquals( 127 | '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)))', 128 | $multiPolygon->toWKT() 129 | ); 130 | } 131 | 132 | public function testGeometryCollectionToWKT() 133 | { 134 | $collection = new LineString( 135 | [ 136 | new Point(1.5, 1.5), 137 | new Point(1.5, 2.5), 138 | new Point(2.5, 2.5), 139 | new Point(2.5, 1.5), 140 | new Point(1.5, 1.5) 141 | ] 142 | ); 143 | 144 | $point = new Point(100.5, 200.5); 145 | 146 | $geo_collection = new GeometryCollection([$collection, $point]); 147 | 148 | $this->assertEquals( 149 | 'GEOMETRYCOLLECTION(LINESTRING(1.5 1.5,2.5 1.5,2.5 2.5,1.5 2.5,1.5 1.5),POINT(200.5 100.5))', 150 | $geo_collection->toWKT() 151 | ); 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /tests/Eloquent/BuilderTest.php: -------------------------------------------------------------------------------- 1 | queryBuilder = m::mock(QueryBuilder::class); 28 | $this->queryBuilder->makePartial(); 29 | 30 | $this->queryBuilder 31 | ->shouldReceive('from') 32 | ->andReturn($this->queryBuilder); 33 | 34 | $this->queryBuilder 35 | ->shouldReceive('take') 36 | ->with(1) 37 | ->andReturn($this->queryBuilder); 38 | 39 | $this->queryBuilder 40 | ->shouldReceive('get') 41 | ->andReturn([]); 42 | 43 | $this->builder = new Builder($this->queryBuilder); 44 | $this->builder->setModel(new class extends Model { 45 | use PostgisTrait; 46 | protected $postgisFields = [ 47 | 'point' => Point::class, 48 | 'linestring' => LineString::class, 49 | 'polygon' => Polygon::class 50 | ]; 51 | }); 52 | } 53 | 54 | public function testUpdate() 55 | { 56 | $this->queryBuilder 57 | ->shouldReceive('raw') 58 | ->with("public.ST_GeogFromText('POINT(2 1)')") 59 | ->andReturn(new Expression("public.ST_GeogFromText('POINT(2 1)')")); 60 | 61 | $this->queryBuilder 62 | ->shouldReceive('update') 63 | ->andReturn(1); 64 | 65 | $builder = m::mock(Builder::class, [$this->queryBuilder])->makePartial(); 66 | $builder->shouldAllowMockingProtectedMethods(); 67 | $builder 68 | ->shouldReceive('addUpdatedAtColumn') 69 | ->andReturn(['point' => new Point(1, 2)]); 70 | 71 | $builder->update(['point' => new Point(1, 2)]); 72 | } 73 | 74 | public function testUpdateLinestring() 75 | { 76 | $this->queryBuilder 77 | ->shouldReceive('raw') 78 | ->with("public.ST_GeogFromText('LINESTRING(0 0, 1 1, 2 2)')") 79 | ->andReturn(new Expression("public.ST_GeogFromText('LINESTRING(0 0, 1 1, 2 2)')")); 80 | 81 | $this->queryBuilder 82 | ->shouldReceive('update') 83 | ->andReturn(1); 84 | 85 | $linestring = new LineString([new Point(0, 0), new Point(1, 1), new Point(2, 2)]); 86 | 87 | $builder = m::mock(Builder::class, [$this->queryBuilder])->makePartial(); 88 | $builder->shouldAllowMockingProtectedMethods(); 89 | $builder 90 | ->shouldReceive('addUpdatedAtColumn') 91 | ->andReturn(['linestring' => $linestring]); 92 | 93 | $builder 94 | ->shouldReceive('asWKT')->with($linestring)->once(); 95 | 96 | $builder->update(['linestring' => $linestring]); 97 | } 98 | 99 | public function testUpdate3d() 100 | { 101 | $this->queryBuilder 102 | ->shouldReceive('raw') 103 | ->with("public.ST_GeogFromText('POINT Z(2 1 0)')") 104 | ->andReturn(new Expression("public.ST_GeogFromText('POINT Z(2 1 0)')")); 105 | 106 | $this->queryBuilder 107 | ->shouldReceive('update') 108 | ->andReturn(1); 109 | 110 | $builder = m::mock(Builder::class, [$this->queryBuilder])->makePartial(); 111 | $builder->shouldAllowMockingProtectedMethods(); 112 | $builder 113 | ->shouldReceive('addUpdatedAtColumn') 114 | ->andReturn(['point' => new Point(1, 2, 0)]); 115 | 116 | $builder->update(['point' => new Point(1, 2, 0)]); 117 | } 118 | 119 | public function testUpdateLinestring3d() 120 | { 121 | $this->queryBuilder 122 | ->shouldReceive('raw') 123 | ->with("public.ST_GeogFromText('LINESTRING Z(0 0 0, 1 1 1, 2 2 2)')") 124 | ->andReturn(new Expression("public.ST_GeogFromText('LINESTRING Z(0 0 0, 1 1 1, 2 2 2)')")); 125 | 126 | $this->queryBuilder 127 | ->shouldReceive('update') 128 | ->andReturn(1); 129 | 130 | $linestring = new LineString([new Point(0, 0, 0), new Point(1, 1, 1), new Point(2, 2, 2)]); 131 | 132 | $builder = m::mock(Builder::class, [$this->queryBuilder])->makePartial(); 133 | $builder->shouldAllowMockingProtectedMethods(); 134 | $builder 135 | ->shouldReceive('addUpdatedAtColumn') 136 | ->andReturn(['linestring' => $linestring]); 137 | 138 | $builder 139 | ->shouldReceive('asWKT')->with($linestring)->once(); 140 | 141 | $builder->update(['linestring' => $linestring]); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/Eloquent/PostgisTrait.php: -------------------------------------------------------------------------------- 1 | getConnection()->raw(sprintf("%s.ST_GeogFromText('%s')", 32 | function_exists('config') ? config('postgis.schema') : 'public', $geometry->toWKT())); 33 | } 34 | 35 | protected function geomFromText(GeometryInterface $geometry, $srid = 4326) 36 | { 37 | return $this->getConnection()->raw(sprintf("%s.ST_GeomFromText('%s', '%d')", 38 | function_exists('config') ? config('postgis.schema') : 'public', $geometry->toWKT(), $srid)); 39 | } 40 | 41 | public function asWKT(GeometryInterface $geometry, $attrs) 42 | { 43 | switch (strtoupper($attrs['geomtype'])) { 44 | case 'GEOMETRY': 45 | return $this->geomFromText($geometry, $attrs['srid']); 46 | break; 47 | case 'GEOGRAPHY': 48 | default: 49 | return $this->geogFromText($geometry); 50 | break; 51 | } 52 | } 53 | 54 | protected function performInsert(EloquentBuilder $query, array $options = []) 55 | { 56 | foreach ($this->attributes as $key => $value) { 57 | if ($value instanceof GeometryInterface) { 58 | $this->geometries[$key] = $value; //Preserve the geometry objects prior to the insert 59 | if (! $value instanceof GeometryCollection) { 60 | $attrs = $this->getPostgisType($key); 61 | $this->attributes[$key] = $this->asWKT($value, $attrs); 62 | } else { 63 | $this->attributes[$key] = $this->geomFromText($value); 64 | } 65 | } 66 | } 67 | 68 | $insert = parent::performInsert($query, $options); 69 | 70 | foreach($this->geometries as $key => $value){ 71 | $this->attributes[$key] = $value; //Retrieve the geometry objects so they can be used in the model 72 | } 73 | 74 | return $insert; //Return the result of the parent insert 75 | } 76 | 77 | public function setRawAttributes(array $attributes, $sync = false) 78 | { 79 | $pgfields = $this->getPostgisFields(); 80 | 81 | foreach ($attributes as $attribute => &$value) { 82 | if (in_array($attribute, $pgfields) && is_string($value) && strlen($value) >= 15) { 83 | $value = Geometry::fromWKB($value); 84 | } 85 | } 86 | 87 | return parent::setRawAttributes($attributes, $sync); 88 | } 89 | 90 | public function getPostgisType($key) 91 | { 92 | $default = [ 93 | 'geomtype' => 'geography', 94 | 'srid' => 4326 95 | ]; 96 | 97 | if (property_exists($this, 'postgisTypes')) { 98 | if (Arr::isAssoc($this->postgisTypes)) { 99 | if(!array_key_exists($key, $this->postgisTypes)) { 100 | return $default; 101 | } 102 | $column = $this->postgisTypes[$key]; 103 | if (isset($column['geomtype']) && in_array(strtoupper($column['geomtype']), PostgisGrammar::$allowed_geom_types)) { 104 | return $column; 105 | } else { 106 | throw new UnsupportedGeomtypeException('Unsupported GeometryType in $postgisTypes for key ' . $key . ' in ' . __CLASS__); 107 | } 108 | } else { 109 | throw new PostgisTypesMalformedException('$postgisTypes in ' . __CLASS__ . ' has to be an assoc array'); 110 | } 111 | } 112 | 113 | // Return default geography if postgisTypes does not exist (for backward compatibility) 114 | return $default; 115 | } 116 | 117 | public function getPostgisFields() 118 | { 119 | if (property_exists($this, 'postgisFields')) { 120 | return Arr::isAssoc($this->postgisFields) ? //Is the array associative? 121 | array_keys($this->postgisFields) : //Returns just the keys to preserve compatibility with previous versions 122 | $this->postgisFields; //Returns the non-associative array that doesn't define the geometry type. 123 | } else { 124 | throw new PostgisFieldsNotDefinedException(__CLASS__ . ' has to define $postgisFields'); 125 | } 126 | 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /tests/Geometries/GeometryCollectionTest.php: -------------------------------------------------------------------------------- 1 | collection = new GeometryCollection([$collection, $point]); 33 | 34 | $collection = new LineString( 35 | [ 36 | new Point(1, 1, 1), 37 | new Point(1, 2, 3), 38 | new Point(2, 2, 2), 39 | new Point(2, 1, 0), 40 | new Point(1, 1, 1) 41 | ] 42 | ); 43 | 44 | $point = new Point(100, 200, 300); 45 | 46 | $this->collection3d = new GeometryCollection([$collection, $point]); 47 | } 48 | 49 | public function testFromGeoJSON() 50 | { 51 | $geojson = new \GeoJson\Geometry\GeometryCollection([ 52 | new \GeoJson\Geometry\Point([2, 3]), 53 | new \GeoJson\Geometry\LineString([[2, 3], [3, 4]]), 54 | ]); 55 | 56 | $geometryCollection = GeometryCollection::fromGeoJSON($geojson); 57 | 58 | $this->assertInstanceOf(GeometryCollection::class, $geometryCollection); 59 | $this->assertEquals(2, $geometryCollection->count()); 60 | $this->assertInstanceOf(Point::class, $geometryCollection->getGeometries()[0]); 61 | $this->assertInstanceOf(LineString::class, $geometryCollection->getGeometries()[1]); 62 | $this->assertEquals($geojson, $geometryCollection->toGeoJSON()); 63 | } 64 | 65 | public function testFromGeoJSON3d() 66 | { 67 | $geojson = new \GeoJson\Geometry\GeometryCollection([ 68 | new \GeoJson\Geometry\Point([2, 3, 4]), 69 | new \GeoJson\Geometry\LineString([[2, 3, 4], [3, 4, 5]]), 70 | ]); 71 | 72 | $geometryCollection = GeometryCollection::fromGeoJSON($geojson); 73 | 74 | $this->assertInstanceOf(GeometryCollection::class, $geometryCollection); 75 | $this->assertEquals(2, $geometryCollection->count()); 76 | $this->assertInstanceOf(Point::class, $geometryCollection->getGeometries()[0]); 77 | $this->assertInstanceOf(LineString::class, $geometryCollection->getGeometries()[1]); 78 | $this->assertEquals($geojson, $geometryCollection->toGeoJSON()); 79 | } 80 | 81 | public function testFromWKT() 82 | { 83 | /** 84 | * @var GeometryCollection $geometryCollection 85 | */ 86 | $geometryCollection = GeometryCollection::fromWKT('GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))'); 87 | $this->assertInstanceOf(GeometryCollection::class, $geometryCollection); 88 | 89 | $this->assertEquals(2, $geometryCollection->count()); 90 | $this->assertInstanceOf(Point::class, $geometryCollection->getGeometries()[0]); 91 | $this->assertInstanceOf(LineString::class, $geometryCollection->getGeometries()[1]); 92 | } 93 | 94 | public function testFromWKT3d() 95 | { 96 | /** 97 | * @var GeometryCollection $geometryCollection 98 | */ 99 | $geometryCollection = GeometryCollection::fromWKT('GEOMETRYCOLLECTION(POINT Z(2 3 4),LINESTRING Z(2 3 4,3 4 5))'); 100 | $this->assertInstanceOf(GeometryCollection::class, $geometryCollection); 101 | 102 | $this->assertEquals(2, $geometryCollection->count()); 103 | $this->assertInstanceOf(Point::class, $geometryCollection->getGeometries()[0]); 104 | $this->assertInstanceOf(LineString::class, $geometryCollection->getGeometries()[1]); 105 | } 106 | 107 | public function testToWKT() 108 | { 109 | $this->assertEquals( 110 | 'GEOMETRYCOLLECTION(LINESTRING(1 1,2 1,2 2,1 2,1 1),POINT(200 100))', 111 | $this->collection->toWKT() 112 | ); 113 | } 114 | 115 | public function testToWKT3d() 116 | { 117 | $this->assertEquals( 118 | 'GEOMETRYCOLLECTION(LINESTRING Z(1 1 1,2 1 3,2 2 2,1 2 0,1 1 1),POINT Z(200 100 300))', 119 | $this->collection3d->toWKT() 120 | ); 121 | } 122 | 123 | public function testJsonSerialize() 124 | { 125 | $this->assertInstanceOf( 126 | \GeoJson\Geometry\GeometryCollection::class, 127 | $this->collection->jsonSerialize() 128 | ); 129 | 130 | $this->assertSame( 131 | '{"type":"GeometryCollection","geometries":[{"type":"LineString","coordinates":[[1,1],[2,1],[2,2],[1,2],[1,1]]},{"type":"Point","coordinates":[200,100]}]}', 132 | json_encode($this->collection->jsonSerialize()) 133 | ); 134 | 135 | } 136 | 137 | public function testJsonSerialize3d() 138 | { 139 | $this->assertInstanceOf( 140 | \GeoJson\Geometry\GeometryCollection::class, 141 | $this->collection3d->jsonSerialize() 142 | ); 143 | 144 | $this->assertSame( 145 | '{"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]}]}', 146 | json_encode($this->collection3d->jsonSerialize()) 147 | ); 148 | 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /tests/Schema/BlueprintTest.php: -------------------------------------------------------------------------------- 1 | blueprint = Mockery::mock(Blueprint::class) 18 | ->makePartial()->shouldAllowMockingProtectedMethods(); 19 | } 20 | 21 | public function testMultiPoint() 22 | { 23 | $this->blueprint 24 | ->shouldReceive('addCommand') 25 | ->with('multipoint', ['col', null, 2, true]); 26 | 27 | $this->blueprint->multipoint('col'); 28 | } 29 | 30 | public function testPolygon() 31 | { 32 | $this->blueprint 33 | ->shouldReceive('addCommand') 34 | ->with('polygon', ['col', null, 2, true]); 35 | 36 | $this->blueprint->polygon('col'); 37 | } 38 | 39 | public function testMulltiPolygon() 40 | { 41 | $this->blueprint 42 | ->shouldReceive('addCommand') 43 | ->with('multipolygon', ['col', null, 2, true]); 44 | 45 | $this->blueprint->multipolygon('col'); 46 | } 47 | 48 | public function testLineString() 49 | { 50 | $this->blueprint 51 | ->shouldReceive('addCommand') 52 | ->with('linestring', ['col', null, 2, true]); 53 | 54 | $this->blueprint->linestring('col'); 55 | } 56 | 57 | public function testMultiLineString() 58 | { 59 | $this->blueprint 60 | ->shouldReceive('addCommand') 61 | ->with('multilinestring', ['col', null, 2, true]); 62 | 63 | $this->blueprint->multilinestring('col'); 64 | } 65 | 66 | public function testGeography() 67 | { 68 | $this->blueprint 69 | ->shouldReceive('addCommand') 70 | ->with('geography', ['col', null, 2, true]); 71 | 72 | $this->blueprint->geography('col'); 73 | } 74 | 75 | public function testGeometryCollection() 76 | { 77 | $this->blueprint 78 | ->shouldReceive('addCommand') 79 | ->with('geometrycollection', ['col', null, 2, true]); 80 | 81 | $this->blueprint->geometrycollection('col'); 82 | } 83 | 84 | public function testEnablePostgis() 85 | { 86 | $this->blueprint 87 | ->shouldReceive('addCommand') 88 | ->with('enablePostgis', []); 89 | 90 | $this->blueprint->enablePostgis(); 91 | } 92 | 93 | public function testEnablePostgisIfNotExists() 94 | { 95 | $this->blueprint 96 | ->shouldReceive('addCommand') 97 | ->with('enablePostgis', []); 98 | 99 | $this->blueprint->enablePostgisIfNotExists(); 100 | } 101 | 102 | public function testDisablePostgis() 103 | { 104 | $this->blueprint 105 | ->shouldReceive('addCommand') 106 | ->with('disablePostgis', []); 107 | 108 | $this->blueprint->disablePostgis(); 109 | } 110 | 111 | public function testDisablePostgisIfExists() 112 | { 113 | $this->blueprint 114 | ->shouldReceive('addCommand') 115 | ->with('disablePostgis', []); 116 | 117 | $this->blueprint->disablePostgisIfExists(); 118 | } 119 | 120 | public function testGinIndex() 121 | { 122 | $this->blueprint 123 | ->shouldReceive('indexCommand') 124 | ->with('gin', 'col', 'myName'); 125 | 126 | $this->blueprint->gin('col', 'myName'); 127 | } 128 | 129 | public function testGistIndex() 130 | { 131 | $this->blueprint 132 | ->shouldReceive('indexCommand') 133 | ->with('gist', 'col', 'myName'); 134 | 135 | $this->blueprint->gist('col', 'myName'); 136 | } 137 | 138 | public function testCharacter() 139 | { 140 | $this->blueprint 141 | ->shouldReceive('addColumn') 142 | ->with('character', 'col', 14); 143 | 144 | $this->blueprint->character('col', 14); 145 | } 146 | 147 | public function testHstore() 148 | { 149 | $this->blueprint 150 | ->shouldReceive('addColumn') 151 | ->with('hstore', 'col'); 152 | 153 | $this->blueprint->hstore('col'); 154 | } 155 | 156 | public function testUuid() 157 | { 158 | $this->blueprint 159 | ->shouldReceive('addColumn') 160 | ->with('uuid', 'col'); 161 | 162 | $this->blueprint->uuid('col'); 163 | } 164 | 165 | public function testJsonb() 166 | { 167 | $this->blueprint 168 | ->shouldReceive('addColumn') 169 | ->with('jsonb', 'col'); 170 | 171 | $this->blueprint->jsonb('col'); 172 | } 173 | 174 | public function testInt4range() 175 | { 176 | $this->blueprint 177 | ->shouldReceive('addColumn') 178 | ->with('int4range', 'col'); 179 | 180 | $this->blueprint->int4range('col'); 181 | } 182 | 183 | public function testInt8range() 184 | { 185 | $this->blueprint 186 | ->shouldReceive('addColumn') 187 | ->with('int8range', 'col'); 188 | 189 | $this->blueprint->int8range('col'); 190 | } 191 | 192 | public function testNumrange() 193 | { 194 | $this->blueprint 195 | ->shouldReceive('addColumn') 196 | ->with('numrange', 'col'); 197 | 198 | $this->blueprint->numrange('col'); 199 | } 200 | 201 | public function testTsrange() 202 | { 203 | $this->blueprint 204 | ->shouldReceive('addColumn') 205 | ->with('tsrange', 'col'); 206 | 207 | $this->blueprint->tsrange('col'); 208 | } 209 | 210 | public function testTstzrange() 211 | { 212 | $this->blueprint 213 | ->shouldReceive('addColumn') 214 | ->with('tstzrange', 'col'); 215 | 216 | $this->blueprint->tstzrange('col'); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Laravel Wrapper for PostgreSQL's Geo-Extension Postgis 2 | ====================================================== 3 | 4 |  5 | 6 | For Laravel 9+, PHP 8+ only 7 | 8 | ## Features 9 | 10 | * Work with geometry classes instead of arrays. 11 | ```php 12 | $model->myPoint = new Point(1,2); //lat, long 13 | ``` 14 | 15 | * Adds helpers in migrations. 16 | ```php 17 | $table->polygon('myColumn'); 18 | ``` 19 | 20 | 21 | 22 | ## Installation 23 | ```bash 24 | composer require mstaack/laravel-postgis 25 | ``` 26 | 27 | ## Usage 28 | 29 | To start, ensure you have PostGIS enabled in your database - you can do this in a Laravel migration or manually via SQL. 30 | 31 | ### Enable PostGIS via a Laravel migration 32 | 33 | You need to publish the migration to easily enable PostGIS: 34 | 35 | ```sh 36 | php artisan vendor:publish --provider="Ajthinking\LaravelPostgis\DatabaseServiceProvider" --tag="migrations" 37 | ``` 38 | 39 | And then you run the migrations: 40 | 41 | ```sh 42 | php artisan migrate 43 | ``` 44 | 45 | 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. 46 | 47 | 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. 48 | 49 | ### Enable PostGIS manually 50 | 51 | Use an SQL client to connect to your database and run the following command: 52 | 53 | CREATE EXTENSION postgis; 54 | 55 | To verify that PostGIS is enabled you can run: 56 | 57 | SELECT postgis_full_version(); 58 | 59 | ### Migrations 60 | 61 | Now create a model with a migration by running 62 | 63 | php artisan make:model Location 64 | 65 | If you don't want a model and just a migration run 66 | 67 | php artisan make:migration create_locations_table 68 | 69 | Open the created migrations with your editor. 70 | 71 | ```PHP 72 | use Illuminate\Database\Migrations\Migration; 73 | use Ajthinking\LaravelPostgis\Schema\Blueprint; 74 | 75 | class CreateLocationsTable extends Migration { 76 | 77 | /** 78 | * Run the migrations. 79 | * 80 | * @return void 81 | */ 82 | public function up() 83 | { 84 | Schema::create('locations', function(Blueprint $table) 85 | { 86 | $table->increments('id'); 87 | $table->string('name'); 88 | $table->string('address')->unique(); 89 | $table->point('location'); // GEOGRAPHY POINT column with SRID of 4326 (these are the default values). 90 | $table->point('location2', 'GEOGRAPHY', 4326); // GEOGRAPHY POINT column with SRID of 4326 with optional parameters. 91 | $table->point('location3', 'GEOMETRY', 27700); // GEOMETRY column with SRID of 27700. 92 | $table->polygon('polygon'); // GEOGRAPHY POLYGON column with SRID of 4326. 93 | $table->polygon('polygon2', 'GEOMETRY', 27700); // GEOMETRY POLYGON column with SRID of 27700. 94 | $table->timestamps(); 95 | }); 96 | } 97 | 98 | /** 99 | * Reverse the migrations. 100 | * 101 | * @return void 102 | */ 103 | public function down() 104 | { 105 | Schema::drop('locations'); 106 | } 107 | 108 | } 109 | ``` 110 | 111 | Available blueprint geometries: 112 | 113 | * point 114 | * multipoint 115 | * linestring 116 | * multilinestring 117 | * polygon 118 | * multipolygon 119 | * geometrycollection 120 | 121 | other methods: 122 | 123 | * enablePostgis 124 | * disablePostgis 125 | 126 | ### Models 127 | 128 | All models which are to be PostGis enabled **must** use the *PostgisTrait*. 129 | 130 | You must also define an array called `$postgisFields` which defines 131 | what attributes/columns on your model are to be considered geometry objects. By default, all attributes are of type `geography`. If you want to use `geometry` with a custom SRID, you have to define an array called `$postgisTypes`. The keys of this assoc array must match the entries in `$postgisFields` (all missing keys default to `geography`), the values are assoc arrays, too. They must have two keys: `geomtype` which is either `geography` or `geometry` and `srid` which is the desired SRID. **Note**: Custom SRID is only supported for `geometry`, not `geography`. 132 | 133 | ```PHP 134 | use Illuminate\Database\Eloquent\Model; 135 | use Ajthinking\LaravelPostgis\Eloquent\PostgisTrait; 136 | use Ajthinking\LaravelPostgis\Geometries\Point; 137 | 138 | class Location extends Model 139 | { 140 | use PostgisTrait; 141 | 142 | protected $fillable = [ 143 | 'name', 144 | 'address' 145 | ]; 146 | 147 | protected $postgisFields = [ 148 | 'location', 149 | 'location2', 150 | 'location3', 151 | 'polygon', 152 | 'polygon2' 153 | ]; 154 | 155 | protected $postgisTypes = [ 156 | 'location' => [ 157 | 'geomtype' => 'geography', 158 | 'srid' => 4326 159 | ], 160 | 'location2' => [ 161 | 'geomtype' => 'geography', 162 | 'srid' => 4326 163 | ], 164 | 'location3' => [ 165 | 'geomtype' => 'geometry', 166 | 'srid' => 27700 167 | ], 168 | 'polygon' => [ 169 | 'geomtype' => 'geography', 170 | 'srid' => 4326 171 | ], 172 | 'polygon2' => [ 173 | 'geomtype' => 'geometry', 174 | 'srid' => 27700 175 | ] 176 | ] 177 | } 178 | 179 | $linestring = new LineString( 180 | [ 181 | new Point(0, 0), 182 | new Point(0, 1), 183 | new Point(1, 1), 184 | new Point(1, 0), 185 | new Point(0, 0) 186 | ] 187 | ); 188 | 189 | $location1 = new Location(); 190 | $location1->name = 'Googleplex'; 191 | $location1->address = '1600 Amphitheatre Pkwy Mountain View, CA 94043'; 192 | $location1->location = new Point(37.422009, -122.084047); 193 | $location1->location2 = new Point(37.422009, -122.084047); 194 | $location1->location3 = new Point(37.422009, -122.084047); 195 | $location1->polygon = new Polygon([$linestring]); 196 | $location1->polygon2 = new Polygon([$linestring]); 197 | $location1->save(); 198 | 199 | $location2 = Location::first(); 200 | $location2->location instanceof Point // true 201 | ``` 202 | 203 | Available geometry classes: 204 | 205 | * Point 206 | * MultiPoint 207 | * LineString 208 | * MultiLineString 209 | * Polygon 210 | * MultiPolygon 211 | * GeometryCollection 212 | 213 | 214 | ### Achnowledgements 215 | This is a [fork](https://github.com/mstaack/laravel-postgis) from the work of great people. Thanks to : 216 | - https://github.com/njbarrett 217 | - https://github.com/phaza 218 | - https://github.com/mirzap 219 | 220 | -------------------------------------------------------------------------------- /tests/Geometries/GeometryTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 20 | '1 1', 21 | Geometry::getWKTArgument('POINT(1 1)') 22 | ); 23 | $this->assertEquals( 24 | '1 1,1 2,2 2', 25 | Geometry::getWKTArgument('LINESTRING(1 1,1 2,2 2)') 26 | ); 27 | $this->assertEquals( 28 | '(1 1,4 1,4 4,1 4,1 1),(1 1, 2 1, 2 2, 1 2,1 1)', 29 | Geometry::getWKTArgument('POLYGON((1 1,4 1,4 4,1 4,1 1),(1 1, 2 1, 2 2, 1 2,1 1))') 30 | ); 31 | $this->assertEquals( 32 | '(1 1),(1 2)', 33 | Geometry::getWKTArgument('MULTIPOINT((1 1),(1 2))') 34 | ); 35 | $this->assertEquals( 36 | '(1 1,1 2,2 2),(2 3,3 2,5 4)', 37 | Geometry::getWKTArgument('MULTILINESTRING((1 1,1 2,2 2),(2 3,3 2,5 4))') 38 | ); 39 | $this->assertEquals( 40 | '((1 1,4 1,4 4,1 4,1 1),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1))', 41 | Geometry::getWKTArgument('MULTIPOLYGON(((1 1,4 1,4 4,1 4,1 1),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))') 42 | ); 43 | $this->assertEquals( 44 | 'POINT(2 3),LINESTRING(2 3,3 4)', 45 | Geometry::getWKTArgument('GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))') 46 | ); 47 | } 48 | 49 | public function testGetWKTArgument3d() 50 | { 51 | $this->assertEquals( 52 | '1 1 1', 53 | Geometry::getWKTArgument('POINT Z(1 1 1)') 54 | ); 55 | $this->assertEquals( 56 | '1 1 1,1 2 2,2 2 3', 57 | Geometry::getWKTArgument('LINESTRING Z(1 1 1,1 2 2,2 2 3)') 58 | ); 59 | $this->assertEquals( 60 | '(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)', 61 | 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))') 62 | ); 63 | $this->assertEquals( 64 | '(1 1 1),(1 2 2)', 65 | Geometry::getWKTArgument('MULTIPOINT Z((1 1 1),(1 2 2))') 66 | ); 67 | $this->assertEquals( 68 | '(1 1 1,1 2 1,2 2 1),(2 3 2,3 2 2,5 4 2)', 69 | Geometry::getWKTArgument('MULTILINESTRING Z((1 1 1,1 2 1,2 2 1),(2 3 2,3 2 2,5 4 2))') 70 | ); 71 | $this->assertEquals( 72 | '((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))', 73 | 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)))') 74 | ); 75 | $this->assertEquals( 76 | 'POINT Z(2 3 4),LINESTRING Z(2 3 4,3 4 5)', 77 | Geometry::getWKTArgument('GEOMETRYCOLLECTION(POINT Z(2 3 4),LINESTRING Z(2 3 4,3 4 5))') 78 | ); 79 | } 80 | 81 | public function testGetWKTClass() 82 | { 83 | $this->assertEquals( 84 | Point::class, 85 | Geometry::getWKTClass('POINT(0 0)') 86 | ); 87 | $this->assertEquals( 88 | LineString::class, 89 | Geometry::getWKTClass('LINESTRING(0 0,1 1,1 2)') 90 | ); 91 | $this->assertEquals( 92 | Polygon::class, 93 | Geometry::getWKTClass('POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))') 94 | ); 95 | $this->assertEquals( 96 | MultiPoint::class, 97 | Geometry::getWKTClass('MULTIPOINT((0 0),(1 2))') 98 | ); 99 | $this->assertEquals( 100 | MultiLineString::class, 101 | Geometry::getWKTClass('MULTILINESTRING((0 0,1 1,1 2),(2 3,3 2,5 4))') 102 | ); 103 | $this->assertEquals( 104 | MultiPolygon::class, 105 | Geometry::getWKTClass('MULTIPOLYGON(((0 0,4 0,4 4,0 4,0 0),(1 1,2 1,2 2,1 2,1 1)), ((-1 -1,-1 -2,-2 -2,-2 -1,-1 -1)))') 106 | ); 107 | $this->assertEquals( 108 | GeometryCollection::class, 109 | Geometry::getWKTClass('GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))') 110 | ); 111 | } 112 | 113 | public function testGetWKTClass3d() 114 | { 115 | $this->assertEquals( 116 | Point::class, 117 | Geometry::getWKTClass('POINT Z(0 0 0)') 118 | ); 119 | $this->assertEquals( 120 | LineString::class, 121 | Geometry::getWKTClass('LINESTRING Z(0 0 0,1 1 1,1 2 3)') 122 | ); 123 | $this->assertEquals( 124 | Polygon::class, 125 | 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))') 126 | ); 127 | $this->assertEquals( 128 | MultiPoint::class, 129 | Geometry::getWKTClass('MULTIPOINT Z((0 00),(1 2 3))') 130 | ); 131 | $this->assertEquals( 132 | MultiLineString::class, 133 | Geometry::getWKTClass('MULTILINESTRING Z((0 0 0 ,1 1 1,1 2 3),(2 3 4,3 2 1,5 4 3))') 134 | ); 135 | $this->assertEquals( 136 | MultiPolygon::class, 137 | 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)))') 138 | ); 139 | $this->assertEquals( 140 | GeometryCollection::class, 141 | Geometry::getWKTClass('GEOMETRYCOLLECTION(POINT Z(2 3 4),LINESTRING Z(2 3 4,3 4 5))') 142 | ); 143 | } 144 | 145 | public function testGetWKBClass() 146 | { 147 | $this->assertInstanceOf( 148 | Point::class, 149 | Geometry::fromWKB('0101000000000000000000f03f0000000000000040') 150 | ); 151 | $this->assertInstanceOf( 152 | LineString::class, 153 | Geometry::fromWKB('010200000002000000000000000000f03f000000000000004000000000000008400000000000001040') 154 | ); 155 | $this->assertInstanceOf( 156 | Polygon::class, 157 | Geometry::fromWKB('01030000000100000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f0000000000000040') 158 | ); 159 | $this->assertInstanceOf( 160 | MultiPoint::class, 161 | Geometry::fromWKB('0104000000020000000101000000000000000000f03f0000000000000040010100000000000000000008400000000000001040') 162 | ); 163 | $this->assertInstanceOf( 164 | MultiLineString::class, 165 | Geometry::fromWKB('010500000001000000010200000002000000000000000000f03f000000000000004000000000000008400000000000001040') 166 | ); 167 | $this->assertInstanceOf( 168 | MultiLineString::class, 169 | Geometry::fromWKB('010500000002000000010200000002000000000000000000f03f000000000000004000000000000008400000000000001040010200000002000000000000000000144000000000000018400000000000001c400000000000002040') 170 | ); 171 | $this->assertInstanceOf( 172 | MultiPolygon::class, 173 | Geometry::fromWKB('01060000000200000001030000000100000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f000000000000004001030000000300000004000000000000000000f03f00000000000000400000000000000840000000000000104000000000000014400000000000001840000000000000f03f000000000000004004000000000000000000264000000000000028400000000000002a400000000000002c400000000000002e4000000000000030400000000000002640000000000000284004000000000000000000354000000000000036400000000000003740000000000000384000000000000039400000000000003a4000000000000035400000000000003640') 174 | ); 175 | $this->assertInstanceOf( 176 | GeometryCollection::class, 177 | Geometry::fromWKB('0107000000010000000101000000000000000000f03f0000000000000040') 178 | ); 179 | $this->assertInstanceOf( 180 | GeometryCollection::class, 181 | Geometry::fromWKB('0107000000020000000101000000000000000000f03f0000000000000040010200000002000000000000000000f03f000000000000004000000000000008400000000000001040') 182 | ); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /tests/Geometries/MultiPolygonTest.php: -------------------------------------------------------------------------------- 1 | multiPolygon = new MultiPolygon([$polygon1, $polygon2]); 57 | 58 | $collection1 = new LineString( 59 | [ 60 | new Point(1, 1, 1), 61 | new Point(1, 2, 3), 62 | new Point(2, 2, 2), 63 | new Point(2, 1, 0), 64 | new Point(1, 1, 1) 65 | ] 66 | ); 67 | 68 | $collection2 = new LineString( 69 | [ 70 | new Point(10, 10, 10), 71 | new Point(10, 20, 30), 72 | new Point(20, 20, 20), 73 | new Point(20, 10, 0), 74 | new Point(10, 10, 10) 75 | ] 76 | ); 77 | 78 | $polygon1 = new Polygon([$collection1, $collection2]); 79 | 80 | $collection3 = new LineString( 81 | [ 82 | new Point(100, 100, 100), 83 | new Point(100, 200, 300), 84 | new Point(200, 200, 200), 85 | new Point(200, 100, 0), 86 | new Point(100, 100, 100) 87 | ] 88 | ); 89 | 90 | 91 | $polygon2 = new Polygon([$collection3]); 92 | 93 | $this->multiPolygon3d = new MultiPolygon([$polygon1, $polygon2]); 94 | } 95 | 96 | public function testFromGeoJSON() 97 | { 98 | $geojson = new \GeoJson\Geometry\MultiPolygon([ 99 | [[[1, 1], [2, 1], [2, 2], [1, 2], [1, 1]], [[1, 1], [2, 1], [2, 2], [1, 2], [1, 1]]], 100 | [[[-1, -1], [-2, -2], [-2, -2], [-2, -1], [-1, -1]]], 101 | ]); 102 | 103 | $multipolygon = MultiPolygon::fromGeoJSON($geojson); 104 | 105 | $this->assertInstanceOf(MultiPolygon::class, $multipolygon); 106 | $this->assertEquals(2, $multipolygon->count()); 107 | $this->assertEquals($geojson, $multipolygon->toGeoJSON()); 108 | } 109 | 110 | public function testFromGeoJSON3d() 111 | { 112 | $geojson = new \GeoJson\Geometry\MultiPolygon([ 113 | [[[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]]], 114 | [[[-1, -1, -1], [-2, -2, -3], [-2, -2, -2], [-2, -1, 0], [-1, -1, -1]]], 115 | ]); 116 | 117 | $multipolygon = MultiPolygon::fromGeoJSON($geojson); 118 | 119 | $this->assertInstanceOf(MultiPolygon::class, $multipolygon); 120 | $this->assertEquals(2, $multipolygon->count()); 121 | $this->assertEquals($geojson, $multipolygon->toGeoJSON()); 122 | } 123 | 124 | public function testFromWKT() 125 | { 126 | $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)))'; 127 | $polygon = MultiPolygon::fromWKT($wkt); 128 | 129 | $this->assertInstanceOf(MultiPolygon::class, $polygon); 130 | $this->assertEquals(2, $polygon->count()); 131 | $this->assertEquals($wkt, $polygon->toWKT()); 132 | } 133 | 134 | public function testFromWKT3d() 135 | { 136 | $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)))'; 137 | $polygon = MultiPolygon::fromWKT($wkt); 138 | 139 | $this->assertInstanceOf(MultiPolygon::class, $polygon); 140 | $this->assertEquals(2, $polygon->count()); 141 | $this->assertEquals($wkt, $polygon->toWKT()); 142 | } 143 | 144 | public function testToWKT() 145 | { 146 | $this->assertEquals( 147 | 'MULTIPOLYGON(((1 1,2 1,2 2,1 2,1 1),(10 10,20 10,20 20,10 20,10 10)),((100 100,200 100,200 200,100 200,100 100)))', 148 | $this->multiPolygon->toWKT() 149 | ); 150 | } 151 | 152 | public function testToWKT3d() 153 | { 154 | $this->assertEquals( 155 | '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)))', 156 | $this->multiPolygon3d->toWKT() 157 | ); 158 | } 159 | 160 | public function testGetPolygons() 161 | { 162 | $polygon = MultiPolygon::fromWKT( 163 | '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)))' 164 | ); 165 | 166 | $this->assertInstanceOf(Polygon::class, $polygon->getPolygons()[0]); 167 | } 168 | 169 | public function testGetPolygons3d() 170 | { 171 | $polygon = MultiPolygon::fromWKT( 172 | '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)))' 173 | ); 174 | 175 | $this->assertInstanceOf(Polygon::class, $polygon->getPolygons()[0]); 176 | } 177 | 178 | public function testIssue12() 179 | { 180 | $polygon = MultiPolygon::fromWKT( 181 | '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)))' 182 | ); 183 | 184 | $this->assertInstanceOf(MultiPolygon::class, $polygon); 185 | } 186 | 187 | public function testIssue123d() 188 | { 189 | $polygon = MultiPolygon::fromWKT( 190 | '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)))' 191 | ); 192 | 193 | $this->assertInstanceOf(MultiPolygon::class, $polygon); 194 | } 195 | 196 | public function testJsonSerialize() 197 | { 198 | $this->assertInstanceOf(\GeoJson\Geometry\MultiPolygon::class, $this->multiPolygon->jsonSerialize()); 199 | $this->assertSame( 200 | '{"type":"MultiPolygon","coordinates":[[[[1,1],[2,1],[2,2],[1,2],[1,1]],[[10,10],[20,10],[20,20],[10,20],[10,10]]],[[[100,100],[200,100],[200,200],[100,200],[100,100]]]]}', 201 | json_encode($this->multiPolygon) 202 | ); 203 | } 204 | 205 | public function testJsonSerialize3d() 206 | { 207 | $this->assertInstanceOf(\GeoJson\Geometry\MultiPolygon::class, $this->multiPolygon3d->jsonSerialize()); 208 | $this->assertSame( 209 | '{"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]]]]}', 210 | json_encode($this->multiPolygon3d) 211 | ); 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /src/Schema/Blueprint.php: -------------------------------------------------------------------------------- 1 | inherits = $table; 24 | } 25 | 26 | /** 27 | * Add the index commands fluently specified on columns. 28 | * 29 | * @return void 30 | */ 31 | protected function addFluentIndexes() 32 | { 33 | foreach ($this->columns as $column) { 34 | foreach (array('primary', 'unique', 'index', 'gin', 'gist') as $index) { 35 | // If the index has been specified on the given column, but is simply 36 | // equal to "true" (boolean), no name has been specified for this 37 | // index, so we will simply call the index methods without one. 38 | if ($column->$index === true) { 39 | $this->$index($column->name); 40 | 41 | continue 2; 42 | } 43 | 44 | // If the index has been specified on the column and it is something 45 | // other than boolean true, we will assume a name was provided on 46 | // the index specification, and pass in the name to the method. 47 | elseif (isset($column->$index)) { 48 | $this->$index($column->name, $column->$index); 49 | 50 | continue 2; 51 | } 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * Specify an index for the table. 58 | * 59 | * @param string|array $columns 60 | * @param string $name 61 | * @return \Illuminate\Support\Fluent 62 | */ 63 | public function gin($columns, $name = null) 64 | { 65 | return $this->indexCommand('gin', $columns, $name); 66 | } 67 | 68 | /** 69 | * Specify a gist index for the table. 70 | * 71 | * @param string|array $columns 72 | * @param string $name 73 | * @return \Illuminate\Support\Fluent 74 | */ 75 | public function gist($columns, $name = null) 76 | { 77 | return $this->indexCommand('gist', $columns, $name); 78 | } 79 | 80 | /** 81 | * Create a new character column on the table. 82 | * 83 | * @param string $column 84 | * @param int $length 85 | * @return \Illuminate\Database\Schema\ColumnDefinition 86 | */ 87 | public function character($column, $length = 255) 88 | { 89 | return $this->addColumn('character', $column, compact('length')); 90 | } 91 | 92 | /** 93 | * @param $column 94 | * @return \Illuminate\Database\Schema\ColumnDefinition 95 | */ 96 | public function hstore($column) 97 | { 98 | return $this->addColumn('hstore', $column); 99 | } 100 | 101 | /** 102 | * Create a new netmask (CIDR-notation) (cidr) column on the table. 103 | * 104 | * @param string $column 105 | * @return \Illuminate\Database\Schema\ColumnDefinition 106 | */ 107 | public function netmask($column) 108 | { 109 | return $this->addColumn('netmask', $column); 110 | } 111 | 112 | /** 113 | * Create a new line column on the table. 114 | * 115 | * @param string $column 116 | * @return \Illuminate\Database\Schema\ColumnDefinition 117 | */ 118 | public function line($column) 119 | { 120 | return $this->addColumn('line', $column); 121 | } 122 | 123 | /** 124 | * Create a new line segment (lseg) column on the table. 125 | * 126 | * @param string $column 127 | * @return \Illuminate\Database\Schema\ColumnDefinition 128 | */ 129 | public function lineSegment($column) 130 | { 131 | return $this->addColumn('lineSegment', $column); 132 | } 133 | 134 | /** 135 | * Create a new path column on the table. 136 | * 137 | * @param string $column 138 | * @return \Illuminate\Database\Schema\ColumnDefinition 139 | */ 140 | public function path($column) 141 | { 142 | return $this->addColumn('path', $column); 143 | } 144 | 145 | /** 146 | * Create a new box column on the table. 147 | * 148 | * @param string $column 149 | * @return \Illuminate\Database\Schema\ColumnDefinition 150 | */ 151 | public function box($column) 152 | { 153 | return $this->addColumn('box', $column); 154 | } 155 | 156 | /** 157 | * Create a new circle column on the table. 158 | * 159 | * @param string $column 160 | * @return \Illuminate\Database\Schema\ColumnDefinition 161 | */ 162 | public function circle($column) 163 | { 164 | return $this->addColumn('circle', $column); 165 | } 166 | 167 | /** 168 | * Create a new money column on the table. 169 | * 170 | * @param string $column 171 | * @return \Illuminate\Database\Schema\ColumnDefinition 172 | */ 173 | public function money($column) 174 | { 175 | return $this->addColumn('money', $column); 176 | } 177 | 178 | /** 179 | * Create a new int4range column on the table. 180 | * 181 | * @param string $column 182 | * 183 | * @return \Illuminate\Database\Schema\ColumnDefinition 184 | */ 185 | public function int4range($column) 186 | { 187 | return $this->addColumn('int4range', $column); 188 | } 189 | 190 | /** 191 | * Create a new int8range column on the table. 192 | * 193 | * @param string $column 194 | * 195 | * @return \Illuminate\Database\Schema\ColumnDefinition 196 | */ 197 | public function int8range($column) 198 | { 199 | return $this->addColumn('int8range', $column); 200 | } 201 | 202 | /** 203 | * Create a new numrange column on the table. 204 | * 205 | * @param string $column 206 | * 207 | * @return \Illuminate\Database\Schema\ColumnDefinition 208 | */ 209 | public function numrange($column) 210 | { 211 | return $this->addColumn('numrange', $column); 212 | } 213 | 214 | /** 215 | * Create a new tsrange column on the table. 216 | * 217 | * @param string $column 218 | * 219 | * @return \Illuminate\Database\Schema\ColumnDefinition 220 | */ 221 | public function tsrange($column) 222 | { 223 | return $this->addColumn('tsrange', $column); 224 | } 225 | 226 | /** 227 | * Create a new tstzrange column on the table. 228 | * 229 | * @param string $column 230 | * 231 | * @return \Illuminate\Database\Schema\ColumnDefinition 232 | */ 233 | public function tstzrange($column) 234 | { 235 | return $this->addColumn('tstzrange', $column); 236 | } 237 | 238 | /** 239 | * Create a new daterange column on the table. 240 | * 241 | * @param $column 242 | * 243 | * @return \Illuminate\Database\Schema\ColumnDefinition 244 | */ 245 | public function daterange($column) 246 | { 247 | return $this->addColumn('daterange', $column); 248 | } 249 | 250 | /** 251 | * Create a new tsvector column on the table. 252 | * 253 | * @param $column 254 | * 255 | * @return \Illuminate\Database\Schema\ColumnDefinition 256 | */ 257 | public function tsvector($column) 258 | { 259 | return $this->addColumn('tsvector', $column); 260 | } 261 | 262 | /** 263 | * Add a point column on the table 264 | * 265 | * @param $column 266 | * @return \Illuminate\Database\Schema\ColumnDefinition 267 | */ 268 | public function point($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 269 | { 270 | return $this->addColumn('point', $column, compact('geomtype', 'srid')); 271 | } 272 | 273 | /** 274 | * Add a multipoint column on the table 275 | * 276 | * @param $column 277 | * @return \Illuminate\Database\Schema\ColumnDefinition 278 | */ 279 | public function multipoint($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 280 | { 281 | return $this->addColumn('multipoint', $column, compact('geomtype', 'srid')); 282 | } 283 | 284 | /** 285 | * Add a polygon column on the table 286 | * 287 | * @param $column 288 | * @return \Illuminate\Database\Schema\ColumnDefinition 289 | */ 290 | public function polygon($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 291 | { 292 | return $this->addColumn('polygon', $column, compact('geomtype', 'srid')); 293 | } 294 | 295 | /** 296 | * Add a multipolygon column on the table 297 | * 298 | * @param $column 299 | * @return \Illuminate\Database\Schema\ColumnDefinition 300 | */ 301 | public function multipolygon($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 302 | { 303 | return $this->addColumn('multipolygon', $column, compact('geomtype', 'srid')); 304 | } 305 | 306 | /** 307 | * Add a multipolygonz column on the table 308 | * 309 | * @param $column 310 | * @return \Illuminate\Database\Schema\ColumnDefinition 311 | */ 312 | public function multipolygonz($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 313 | { 314 | return $this->addColumn('multipolygonz', $column, compact('geomtype', 'srid')); 315 | } 316 | 317 | /** 318 | * Add a linestring column on the table 319 | * 320 | * @param $column 321 | * @return \Illuminate\Database\Schema\ColumnDefinition 322 | */ 323 | public function linestring($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 324 | { 325 | return $this->addColumn('linestring', $column, compact('geomtype', 'srid')); 326 | } 327 | 328 | /** 329 | * Add a multilinestring column on the table 330 | * 331 | * @param $column 332 | * @return \Illuminate\Database\Schema\ColumnDefinition 333 | */ 334 | public function multilinestring($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 335 | { 336 | return $this->addColumn('multilinestring', $column, compact('geomtype', 'srid')); 337 | } 338 | 339 | /** 340 | * Add a geography column on the table 341 | * 342 | * @param string $column 343 | * @return \Illuminate\Database\Schema\ColumnDefinition 344 | */ 345 | public function geography($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 346 | { 347 | return $this->addColumn('geography', $column, compact('geomtype', 'srid')); 348 | } 349 | 350 | /** 351 | * Add a geometry column on the table 352 | * 353 | * @param string $column 354 | * @return \Illuminate\Database\Schema\ColumnDefinition 355 | */ 356 | public function geometry($column, $geomtype = 'GEOGRAPHY', $srid = '4326') 357 | { 358 | return $this->addColumn('geometry', $column, compact('geomtype', 'srid')); 359 | } 360 | 361 | /** 362 | * Add a geometrycollection column on the table 363 | * 364 | * @param $column 365 | * @param null $srid 366 | * @param int $dimensions 367 | * @param bool $typmod 368 | * @return \Illuminate\Support\Fluent 369 | */ 370 | public function geometrycollection($column, $srid = null, $dimensions = 2, $typmod = true) 371 | { 372 | return $this->addCommand('geometrycollection', compact('column', 'srid', 'dimensions', 'typmod')); 373 | } 374 | 375 | /** 376 | * Enable postgis on this database. 377 | * Will create the extension in the database. 378 | * 379 | * @return \Illuminate\Support\Fluent 380 | */ 381 | public function enablePostgis() 382 | { 383 | return $this->addCommand('enablePostgis'); 384 | } 385 | 386 | /** 387 | * Enable postgis on this database. 388 | * Will create the extension in the database if it doesn't already exist. 389 | * 390 | * @return \Illuminate\Support\Fluent 391 | */ 392 | public function enablePostgisIfNotExists() 393 | { 394 | return $this->addCommand('enablePostgisIfNotExists'); 395 | } 396 | 397 | /** 398 | * Disable postgis on this database. 399 | * WIll drop the extension in the database. 400 | * 401 | * @return \Illuminate\Support\Fluent 402 | */ 403 | public function disablePostgis() 404 | { 405 | return $this->addCommand('disablePostgis'); 406 | } 407 | 408 | /** 409 | * Disable postgis on this database. 410 | * WIll drop the extension in the database if it exists. 411 | * 412 | * @return \Illuminate\Support\Fluent 413 | */ 414 | public function disablePostgisIfExists() 415 | { 416 | return $this->addCommand('disablePostgisIfExists'); 417 | } 418 | 419 | } 420 | -------------------------------------------------------------------------------- /src/Schema/Grammars/PostgisGrammar.php: -------------------------------------------------------------------------------- 1 | length})"; 38 | } 39 | 40 | /** 41 | * Create the column definition for a hstore type. 42 | * 43 | * @param Fluent $column 44 | * @return string 45 | */ 46 | protected function typeHstore(Fluent $column) 47 | { 48 | return "hstore"; 49 | } 50 | 51 | /** 52 | * Create the column definition for a uuid type. 53 | * 54 | * @param Fluent $column 55 | * @return string 56 | */ 57 | protected function typeUuid(Fluent $column) 58 | { 59 | return "uuid"; 60 | } 61 | 62 | /** 63 | * Create the column definition for a jsonb type. 64 | * 65 | * @param Fluent $column 66 | * @return string 67 | */ 68 | protected function typeJsonb(Fluent $column) 69 | { 70 | return "jsonb"; 71 | } 72 | 73 | /** 74 | * Create the column definition for an IPv4 or IPv6 address. 75 | * 76 | * @param \Illuminate\Support\Fluent $column 77 | * @return string 78 | */ 79 | protected function typeIpAddress(Fluent $column) 80 | { 81 | return 'inet'; 82 | } 83 | /** 84 | * Create the column definition for a CIDR notation-style netmask. 85 | * 86 | * @param \Illuminate\Support\Fluent $column 87 | * @return string 88 | */ 89 | protected function typeNetmask(Fluent $column) 90 | { 91 | return 'cidr'; 92 | } 93 | 94 | /** 95 | * Create the column definition for a MAC address. 96 | * 97 | * @param \Illuminate\Support\Fluent $column 98 | * @return string 99 | */ 100 | protected function typeMacAddress(Fluent $column) 101 | { 102 | return 'macaddr'; 103 | } 104 | 105 | /** 106 | * Create the column definition for a line represented as a standard linear equation Ax + By + C = 0. 107 | * 108 | * @param \Illuminate\Support\Fluent $column 109 | * @return string 110 | */ 111 | protected function typeLine(Fluent $column) 112 | { 113 | return 'line'; 114 | } 115 | 116 | /** 117 | * Create the column definition for a line segment represented by two points (x1, y1), (x2, y2). 118 | * 119 | * @param \Illuminate\Support\Fluent $column 120 | * @return string 121 | */ 122 | protected function typeLineSegment(Fluent $column) 123 | { 124 | return 'lseg'; 125 | } 126 | 127 | /** 128 | * Create the column definition for a path represented as a list of points (x1, y1), (x2, y2), ..., (xn, yn). 129 | * 130 | * @param \Illuminate\Support\Fluent $column 131 | * @return string 132 | */ 133 | protected function typePath(Fluent $column) 134 | { 135 | return 'path'; 136 | } 137 | 138 | /** 139 | * Create the column definition for a box represented by opposite corners of the box as points (x1, y1), (x2, y2). 140 | * 141 | * @param \Illuminate\Support\Fluent $column 142 | * @return string 143 | */ 144 | protected function typeBox(Fluent $column) 145 | { 146 | return 'box'; 147 | } 148 | 149 | /** 150 | * Create the column definition for a circle represented by a center point and a radius <(x, y), r> 151 | * 152 | * @param \Illuminate\Support\Fluent $column 153 | * @return string 154 | */ 155 | protected function typeCircle(Fluent $column) 156 | { 157 | return 'circle'; 158 | } 159 | 160 | /** 161 | * Create the column definition for storing amounts of currency with a fixed fractional precision. 162 | * 163 | * This will store values in the range of: -92233720368547758.08 to +92233720368547758.07. (92 quadrillion). 164 | * Output is locale-sensitive, see lc_monetary setting of PostgreSQL instance/s. 165 | * 166 | * @param \Illuminate\Support\Fluent $column 167 | * @return string 168 | */ 169 | protected function typeMoney(Fluent $column) 170 | { 171 | return 'money'; 172 | } 173 | 174 | /** 175 | * Create the column definition for an int4range type. 176 | * 177 | * @param Fluent $column 178 | * 179 | * @return string 180 | */ 181 | protected function typeInt4range(Fluent $column) 182 | { 183 | return "int4range"; 184 | } 185 | 186 | /** 187 | * Create the column definition for an int8range type. 188 | * 189 | * @param Fluent $column 190 | * 191 | * @return string 192 | */ 193 | protected function typeInt8range(Fluent $column) 194 | { 195 | return "int8range"; 196 | } 197 | 198 | /** 199 | * Create the column definition for an numrange type. 200 | * 201 | * @param Fluent $column 202 | * 203 | * @return string 204 | */ 205 | protected function typeNumrange(Fluent $column) 206 | { 207 | return "numrange"; 208 | } 209 | 210 | /** 211 | * Create the column definition for an tsrange type. 212 | * 213 | * @param Fluent $column 214 | * 215 | * @return string 216 | */ 217 | protected function typeTsrange(Fluent $column) 218 | { 219 | return "tsrange"; 220 | } 221 | 222 | /** 223 | * Create the column definition for an tstzrange type. 224 | * 225 | * @param Fluent $column 226 | * 227 | * @return string 228 | */ 229 | protected function typeTstzrange(Fluent $column) 230 | { 231 | return "tstzrange"; 232 | } 233 | 234 | /** 235 | * Create the column definition for an daterange type. 236 | * 237 | * @param Fluent $column 238 | * 239 | * @return string 240 | */ 241 | protected function typeDaterange(Fluent $column) 242 | { 243 | return "daterange"; 244 | } 245 | 246 | /** 247 | * Create the column definition for a Text Search Vector type. 248 | * 249 | * @param Fluent $column 250 | * 251 | * @return string 252 | */ 253 | protected function typeTsvector(Fluent $column) 254 | { 255 | return "tsvector"; 256 | } 257 | 258 | /** 259 | * @param mixed $value 260 | * @return mixed|string 261 | */ 262 | protected function getDefaultValue($value) 263 | { 264 | if($this->isUuid($value)) return strval($value); 265 | 266 | return parent::getDefaultValue($value); 267 | } 268 | 269 | /** 270 | * Check if string matches on of uuid_generate functions 271 | * 272 | * @param $value 273 | * @return int 274 | */ 275 | protected function isUuid($value) 276 | { 277 | return preg_match('/^uuid_generate_v/', $value); 278 | } 279 | 280 | /** 281 | * Compile a gin index key command. 282 | * 283 | * @param \Ajthinking\LaravelPostgis\Schema\Blueprint $blueprint 284 | * @param \Illuminate\Support\Fluent $command 285 | * @return string 286 | */ 287 | public function compileGin(Blueprint $blueprint, Fluent $command) 288 | { 289 | $columns = $this->columnize($command->columns); 290 | 291 | return sprintf('CREATE INDEX %s ON %s USING GIN(%s)', $command->index, $this->wrapTable($blueprint), $columns); 292 | } 293 | 294 | /** 295 | * Compile a gist index key command. 296 | * 297 | * @param \Ajthinking\LaravelPostgis\Schema\Blueprint $blueprint 298 | * @param \Illuminate\Support\Fluent $command 299 | * @return string 300 | */ 301 | public function compileGist(Blueprint $blueprint, Fluent $command) 302 | { 303 | $columns = $this->columnize($command->columns); 304 | 305 | return sprintf('CREATE INDEX %s ON %s USING GIST(%s)', $command->index, $this->wrapTable($blueprint), $columns); 306 | } 307 | 308 | /** 309 | * Adds a statement to add a point geometry column 310 | * 311 | * @param \Illuminate\Support\Fluent $column 312 | * @return string 313 | */ 314 | public function typePoint(Fluent $column) 315 | { 316 | return $this->createTypeDefinition($column, 'POINT'); 317 | } 318 | 319 | /** 320 | * Adds a statement to add a point geometry column 321 | * 322 | * @param \Illuminate\Support\Fluent $column 323 | * @return string 324 | */ 325 | public function typeMultipoint(Fluent $column) 326 | { 327 | return $this->createTypeDefinition($column, 'MULTIPOINT'); 328 | } 329 | 330 | /** 331 | * Adds a statement to add a polygon geometry column 332 | * 333 | * @param \Illuminate\Support\Fluent $column 334 | * @return string 335 | */ 336 | public function typePolygon(Fluent $column) 337 | { 338 | return $this->createTypeDefinition($column, 'POLYGON'); 339 | } 340 | 341 | /** 342 | * Adds a statement to add a multipolygon geometry column 343 | * 344 | * @param \Illuminate\Support\Fluent $column 345 | * @return string 346 | */ 347 | public function typeMultipolygon(Fluent $column) 348 | { 349 | return $this->createTypeDefinition($column, 'MULTIPOLYGON'); 350 | } 351 | 352 | /** 353 | * Adds a statement to add a multipolygonz geometry column 354 | * 355 | * @param \Illuminate\Support\Fluent $column 356 | * @return string 357 | */ 358 | public function typeMultiPolygonZ(Fluent $column) 359 | { 360 | return $this->createTypeDefinition($column, 'MULTIPOLYGONZ'); 361 | } 362 | 363 | /** 364 | * Adds a statement to add a linestring geometry column 365 | * 366 | * @param \Illuminate\Support\Fluent $column 367 | * @return string 368 | */ 369 | public function typeLinestring(Fluent $column) 370 | { 371 | return $this->createTypeDefinition($column, 'LINESTRING'); 372 | } 373 | 374 | /** 375 | * Adds a statement to add a multilinestring geometry column 376 | * 377 | * @param \Illuminate\Support\Fluent $column 378 | * @return string 379 | */ 380 | public function typeMultilinestring(Fluent $column) 381 | { 382 | return $this->createTypeDefinition($column, 'MULTILINESTRING'); 383 | } 384 | 385 | /** 386 | * Adds a statement to add a linestring geometry column 387 | * 388 | * @param \Illuminate\Support\Fluent $column 389 | * @return string 390 | */ 391 | public function typeGeography(Fluent $column) 392 | { 393 | return 'GEOGRAPHY'; 394 | } 395 | 396 | /** 397 | * Adds a statement to add a geometry column 398 | * 399 | * @param \Illuminate\Support\Fluent $column 400 | * @return string 401 | */ 402 | public function typeGeometry(Fluent $column) 403 | { 404 | return 'GEOMETRY'; 405 | } 406 | 407 | /** 408 | * Adds a statement to add a geometrycollection geometry column 409 | * 410 | * @param Blueprint $blueprint 411 | * @param Fluent $command 412 | * @return string 413 | */ 414 | public function compileGeometrycollection(Blueprint $blueprint, Fluent $command) 415 | { 416 | $command->type = 'GEOMETRYCOLLECTION'; 417 | 418 | return $this->compileGeometry($blueprint, $command); 419 | } 420 | 421 | /** 422 | * Adds a statement to create the postgis extension 423 | * 424 | * @return string 425 | */ 426 | public function compileEnablePostgis() 427 | { 428 | return 'CREATE EXTENSION postgis'; 429 | } 430 | 431 | /** 432 | * Adds a statement to create the postgis extension, if it doesn't already exist 433 | * 434 | * @return string 435 | */ 436 | public function compileEnablePostgisIfNotExists() 437 | { 438 | return 'CREATE EXTENSION IF NOT EXISTS postgis'; 439 | } 440 | 441 | /** 442 | * Adds a statement to drop the postgis extension 443 | * 444 | * @return string 445 | */ 446 | public function compileDisablePostgis() 447 | { 448 | return 'DROP EXTENSION postgis'; 449 | } 450 | 451 | /** 452 | * Adds a statement to drop the postgis extension, if it exists 453 | * 454 | * @return string 455 | */ 456 | public function compileDisablePostgisIfExists() 457 | { 458 | return 'DROP EXTENSION IF EXISTS postgis'; 459 | } 460 | 461 | /** 462 | * Adds a statement to add a geometry column 463 | * 464 | * @param Blueprint $blueprint 465 | * @param Fluent $command 466 | * @return string 467 | */ 468 | protected function compileGeometry(Blueprint $blueprint, Fluent $command) 469 | { 470 | 471 | $dimensions = $command->dimensions ?: 2; 472 | $typmod = $command->typmod ? 'true' : 'false'; 473 | $srid = $command->srid ?: 4326; 474 | $schema = function_exists('config') ? config('postgis.schema') : 'public'; 475 | 476 | return sprintf( 477 | "SELECT %s.AddGeometryColumn('%s', '%s', %d, '%s.%s', %d, %s)", 478 | $schema, 479 | $blueprint->getTable(), 480 | $command->column, 481 | $srid, 482 | $schema, 483 | strtoupper($command->type), 484 | $dimensions, 485 | $typmod 486 | ); 487 | } 488 | 489 | /** 490 | * Checks if the given $column is a valid geometry type 491 | * 492 | * @param \Illuminate\Support\Fluent $column 493 | * @return boolean 494 | */ 495 | protected function isValid($column) 496 | { 497 | return in_array(strtoupper($column->geomtype), PostgisGrammar::$allowed_geom_types) && is_int((int) $column->srid); 498 | } 499 | 500 | /** 501 | * Create definition for geometry types. 502 | * @param Fluent $column 503 | * @param string $geometryType 504 | * @return string 505 | * @throws UnsupportedGeomtypeException 506 | */ 507 | private function createTypeDefinition(Fluent $column, $geometryType) 508 | { 509 | $schema = function_exists('config') ? config('postgis.schema') : 'public'; 510 | $type = strtoupper($column->geomtype); 511 | if ($this->isValid($column)) { 512 | if ($type == 'GEOGRAPHY' && $column->srid != 4326) { 513 | throw new UnsupportedGeomtypeException('Error with validation of srid! SRID of GEOGRAPHY must be 4326)'); 514 | } 515 | return $schema . '.' . $type . '(' . $geometryType . ', ' . $column->srid . ')'; 516 | } else { 517 | throw new UnsupportedGeomtypeException('Error with validation of geom type or srid!'); 518 | } 519 | } 520 | 521 | } 522 | -------------------------------------------------------------------------------- /tests/Schema/Grammars/PostgisGrammarTest.php: -------------------------------------------------------------------------------- 1 | point('foo'); 19 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 20 | 21 | $this->assertCount(1, $statements); 22 | $this->assertStringContainsString('GEOGRAPHY(POINT, 4326)', $statements[0]); 23 | } 24 | 25 | public function testAddingPointGeom() 26 | { 27 | $blueprint = new Blueprint('test'); 28 | $blueprint->point('foo', 'GEOMETRY', 27700); 29 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 30 | $this->assertCount(1, $statements); 31 | $this->assertStringContainsString('GEOMETRY(POINT, 27700)', $statements[0]); 32 | } 33 | 34 | public function testAddingPointWrongSrid() 35 | { 36 | $this->expectException(UnsupportedGeomtypeException::class); 37 | $blueprint = new Blueprint('test'); 38 | $blueprint->point('foo', 'GEOGRAPHY', 27700); 39 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 40 | $this->assertCount(1, $statements);; 41 | } 42 | 43 | public function testAddingPointUnsupported() 44 | { 45 | $this->expectException(UnsupportedGeomtypeException::class); 46 | $blueprint = new Blueprint('test'); 47 | $blueprint->point('foo', 'UNSUPPORTED_ENTRY', 27700); 48 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 49 | $this->assertCount(1, $statements);; 50 | } 51 | 52 | public function testAddingLinestring() 53 | { 54 | $blueprint = new Blueprint('test'); 55 | $blueprint->linestring('foo'); 56 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 57 | 58 | $this->assertCount(1, $statements);; 59 | $this->assertStringContainsString('GEOGRAPHY(LINESTRING, 4326)', $statements[0]); 60 | } 61 | 62 | public function testAddingLinestringGeom() 63 | { 64 | $blueprint = new Blueprint('test'); 65 | $blueprint->linestring('foo', 'GEOMETRY', 27700); 66 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 67 | $this->assertCount(1, $statements);; 68 | $this->assertStringContainsString('GEOMETRY(LINESTRING, 27700)', $statements[0]); 69 | } 70 | 71 | public function testAddingLinestringWrongSrid() 72 | { 73 | $this->expectException(UnsupportedGeomtypeException::class); 74 | $blueprint = new Blueprint('test'); 75 | $blueprint->linestring('foo', 'GEOGRAPHY', 27700); 76 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 77 | $this->assertCount(1, $statements);; 78 | } 79 | 80 | public function testAddingLinestringUnsupported() 81 | { 82 | $this->expectException(UnsupportedGeomtypeException::class); 83 | $blueprint = new Blueprint('test'); 84 | $blueprint->linestring('foo', 'UNSUPPORTED_ENTRY', 27700); 85 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 86 | $this->assertCount(1, $statements); 87 | } 88 | 89 | public function testAddingPolygon() 90 | { 91 | $blueprint = new Blueprint('test'); 92 | $blueprint->polygon('foo'); 93 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 94 | 95 | $this->assertCount(1, $statements); 96 | $this->assertStringContainsString('GEOGRAPHY(POLYGON, 4326)', $statements[0]); 97 | } 98 | 99 | public function testAddingPolygonGeom() 100 | { 101 | $blueprint = new Blueprint('test'); 102 | $blueprint->polygon('foo', 'GEOMETRY', 27700); 103 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 104 | $this->assertCount(1, $statements); 105 | $this->assertStringContainsString('GEOMETRY(POLYGON, 27700)', $statements[0]); 106 | } 107 | 108 | public function testAddingPolygonWrongSrid() 109 | { 110 | $this->expectException(UnsupportedGeomtypeException::class); 111 | $blueprint = new Blueprint('test'); 112 | $blueprint->polygon('foo', 'GEOGRAPHY', 27700); 113 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 114 | $this->assertCount(1, $statements); 115 | } 116 | 117 | public function testAddingPolygonUnsupported() 118 | { 119 | $this->expectException(UnsupportedGeomtypeException::class); 120 | $blueprint = new Blueprint('test'); 121 | $blueprint->polygon('foo', 'UNSUPPORTED_ENTRY', 27700); 122 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 123 | $this->assertCount(1, $statements); 124 | } 125 | 126 | public function testAddingMultipoint() 127 | { 128 | $blueprint = new Blueprint('test'); 129 | $blueprint->multipoint('foo'); 130 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 131 | 132 | $this->assertCount(1, $statements); 133 | $this->assertStringContainsString('GEOGRAPHY(MULTIPOINT, 4326)', $statements[0]); 134 | } 135 | 136 | public function testAddingMultipointGeom() 137 | { 138 | $blueprint = new Blueprint('test'); 139 | $blueprint->multipoint('foo', 'GEOMETRY', 27700); 140 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 141 | $this->assertCount(1, $statements); 142 | $this->assertStringContainsString('GEOMETRY(MULTIPOINT, 27700)', $statements[0]); 143 | } 144 | 145 | public function testAddingMultiPointWrongSrid() 146 | { 147 | $this->expectException(UnsupportedGeomtypeException::class); 148 | $blueprint = new Blueprint('test'); 149 | $blueprint->multipoint('foo', 'GEOGRAPHY', 27700); 150 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 151 | $this->assertCount(1, $statements); 152 | } 153 | 154 | public function testAddingMultiPointUnsupported() 155 | { 156 | $this->expectException(UnsupportedGeomtypeException::class); 157 | $blueprint = new Blueprint('test'); 158 | $blueprint->multipoint('foo', 'UNSUPPORTED_ENTRY', 27700); 159 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 160 | $this->assertCount(1, $statements);; 161 | } 162 | 163 | public function testAddingMultiLinestring() 164 | { 165 | $blueprint = new Blueprint('test'); 166 | $blueprint->multilinestring('foo'); 167 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 168 | 169 | $this->assertCount(1, $statements);; 170 | $this->assertStringContainsString('GEOGRAPHY(MULTILINESTRING, 4326)', $statements[0]); 171 | } 172 | 173 | public function testAddingMultiLinestringGeom() 174 | { 175 | $blueprint = new Blueprint('test'); 176 | $blueprint->multilinestring('foo', 'GEOMETRY', 27700); 177 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 178 | $this->assertCount(1, $statements);; 179 | $this->assertStringContainsString('GEOMETRY(MULTILINESTRING, 27700)', $statements[0]); 180 | } 181 | 182 | public function testAddingMultiLinestringWrongSrid() 183 | { 184 | $this->expectException(UnsupportedGeomtypeException::class); 185 | $blueprint = new Blueprint('test'); 186 | $blueprint->multilinestring('foo', 'GEOGRAPHY', 27700); 187 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 188 | $this->assertCount(1, $statements);; 189 | } 190 | 191 | public function testAddingMultiLinestringUnsupported() 192 | { 193 | $this->expectException(UnsupportedGeomtypeException::class); 194 | $blueprint = new Blueprint('test'); 195 | $blueprint->multilinestring('foo', 'UNSUPPORTED_ENTRY', 27700); 196 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 197 | $this->assertCount(1, $statements);; 198 | } 199 | 200 | public function testAddingMultiPolygon() 201 | { 202 | $blueprint = new Blueprint('test'); 203 | $blueprint->multipolygon('foo'); 204 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 205 | 206 | $this->assertCount(1, $statements);; 207 | $this->assertStringContainsString('GEOGRAPHY(MULTIPOLYGON, 4326)', $statements[0]); 208 | } 209 | 210 | public function testAddingMultiPolygonGeom() 211 | { 212 | $blueprint = new Blueprint('test'); 213 | $blueprint->multipolygon('foo', 'GEOMETRY', 27700); 214 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 215 | $this->assertCount(1, $statements);; 216 | $this->assertStringContainsString('GEOMETRY(MULTIPOLYGON, 27700)', $statements[0]); 217 | } 218 | 219 | public function testAddingMultiPolygonWrongSrid() 220 | { 221 | $this->expectException(UnsupportedGeomtypeException::class); 222 | $blueprint = new Blueprint('test'); 223 | $blueprint->multipolygon('foo', 'GEOGRAPHY', 27700); 224 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 225 | $this->assertCount(1, $statements);; 226 | } 227 | 228 | public function testAddingMultiPolygonUnsupported() 229 | { 230 | $this->expectException(UnsupportedGeomtypeException::class); 231 | $blueprint = new Blueprint('test'); 232 | $blueprint->multipolygon('foo', 'UNSUPPORTED_ENTRY', 27700); 233 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 234 | $this->assertCount(1, $statements);; 235 | } 236 | 237 | public function testAddingGeography() 238 | { 239 | $blueprint = new Blueprint('test'); 240 | $blueprint->geography('foo'); 241 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 242 | 243 | $this->assertCount(1, $statements);; 244 | $this->assertStringContainsString('GEOGRAPHY', $statements[0]); 245 | } 246 | 247 | public function testAddingGeometry() 248 | { 249 | $blueprint = new Blueprint('test'); 250 | $blueprint->geometry('foo'); 251 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 252 | $this->assertCount(1, $statements);; 253 | $this->assertStringContainsString('GEOMETRY', $statements[0]); 254 | } 255 | 256 | public function testAddingGeometryCollection() 257 | { 258 | $blueprint = new Blueprint('test'); 259 | $blueprint->geometrycollection('foo'); 260 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 261 | 262 | $this->assertCount(1, $statements);; 263 | $this->assertStringContainsString('AddGeometryColumn', $statements[0]); 264 | $this->assertStringContainsString('GEOMETRYCOLLECTION', $statements[0]); 265 | } 266 | 267 | public function testEnablePostgis() 268 | { 269 | $blueprint = new Blueprint('test'); 270 | $blueprint->enablePostgis(); 271 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 272 | 273 | $this->assertCount(1, $statements);; 274 | $this->assertStringContainsString('CREATE EXTENSION postgis', $statements[0]); 275 | } 276 | 277 | public function testEnablePostgisIfNotExists() 278 | { 279 | $blueprint = new Blueprint('test'); 280 | $blueprint->enablePostgisIfNotExists(); 281 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 282 | 283 | $this->assertCount(1, $statements);; 284 | $this->assertStringContainsString('CREATE EXTENSION IF NOT EXISTS postgis', $statements[0]); 285 | } 286 | 287 | public function testDisablePostgis() 288 | { 289 | $blueprint = new Blueprint('test'); 290 | $blueprint->disablePostgis(); 291 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 292 | 293 | $this->assertCount(1, $statements);; 294 | $this->assertStringContainsString('DROP EXTENSION postgis', $statements[0]); 295 | } 296 | 297 | public function testDisablePostgisIfExists() 298 | { 299 | $blueprint = new Blueprint('test'); 300 | $blueprint->disablePostgisIfExists(); 301 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 302 | 303 | $this->assertCount(1, $statements);; 304 | $this->assertStringContainsString('DROP EXTENSION IF EXISTS postgis', $statements[0]); 305 | } 306 | 307 | /** 308 | * @return Connection 309 | */ 310 | protected function getConnection() 311 | { 312 | return Mockery::mock(PostgisConnection::class); 313 | } 314 | 315 | protected function getGrammar() 316 | { 317 | return new PostgisGrammar(); 318 | } 319 | 320 | public function testAddingGinIndex() 321 | { 322 | $blueprint = new Blueprint('test'); 323 | $blueprint->gin('foo'); 324 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 325 | 326 | $this->assertEquals(1, count($statements)); 327 | 328 | $this->assertStringContainsString('CREATE INDEX', $statements[0]); 329 | $this->assertStringContainsString('GIN("foo")', $statements[0]); 330 | } 331 | 332 | public function testAddingGistIndex() 333 | { 334 | $blueprint = new Blueprint('test'); 335 | $blueprint->gist('foo'); 336 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 337 | 338 | $this->assertEquals(1, count($statements)); 339 | $this->assertStringContainsString('CREATE INDEX', $statements[0]); 340 | $this->assertStringContainsString('GIST("foo")', $statements[0]); 341 | } 342 | 343 | public function testAddingCharacter() 344 | { 345 | $blueprint = new Blueprint('test'); 346 | $blueprint->character('foo', 14); 347 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 348 | 349 | $this->assertEquals(1, count($statements)); 350 | $this->assertStringContainsString('alter table', $statements[0]); 351 | $this->assertStringContainsString('add column "foo" character(14)', $statements[0]); 352 | } 353 | 354 | public function testAddingHstore() 355 | { 356 | $blueprint = new Blueprint('test'); 357 | $blueprint->hstore('foo'); 358 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 359 | 360 | $this->assertEquals(1, count($statements)); 361 | $this->assertStringContainsString('alter table', $statements[0]); 362 | $this->assertStringContainsString('add column "foo" hstore', $statements[0]); 363 | } 364 | 365 | public function testAddingUuid() 366 | { 367 | $blueprint = new Blueprint('test'); 368 | $blueprint->uuid('foo'); 369 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 370 | 371 | $this->assertEquals(1, count($statements)); 372 | $this->assertStringContainsString('alter table', $statements[0]); 373 | $this->assertStringContainsString('add column "foo" uuid', $statements[0]); 374 | } 375 | 376 | public function testAddingJsonb() 377 | { 378 | $blueprint = new Blueprint('test'); 379 | $blueprint->jsonb('foo'); 380 | $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); 381 | 382 | $this->assertEquals(1, count($statements)); 383 | $this->assertStringContainsString('alter table', $statements[0]); 384 | $this->assertStringContainsString('add column "foo" jsonb', $statements[0]); 385 | } 386 | 387 | public function testAddingInt4range() 388 | { 389 | $blueprint = new Blueprint('test'); 390 | $blueprint->int4range('foo'); 391 | $statements = $blueprint->toSql( 392 | $this->getConnection(), 393 | $this->getGrammar() 394 | ); 395 | 396 | $this->assertEquals(1, count($statements)); 397 | $this->assertStringContainsString('alter table', $statements[0]); 398 | $this->assertStringContainsString('add column "foo" int4range', $statements[0]); 399 | } 400 | 401 | public function testAddingInt8range() 402 | { 403 | $blueprint = new Blueprint('test'); 404 | $blueprint->int8range('foo'); 405 | $statements = $blueprint->toSql( 406 | $this->getConnection(), 407 | $this->getGrammar() 408 | ); 409 | 410 | $this->assertEquals(1, count($statements)); 411 | $this->assertStringContainsString('alter table', $statements[0]); 412 | $this->assertStringContainsString('add column "foo" int8range', $statements[0]); 413 | } 414 | 415 | public function testAddingNumrange() 416 | { 417 | $blueprint = new Blueprint('test'); 418 | $blueprint->numrange('foo'); 419 | $statements = $blueprint->toSql( 420 | $this->getConnection(), 421 | $this->getGrammar() 422 | ); 423 | 424 | $this->assertEquals(1, count($statements)); 425 | $this->assertStringContainsString('alter table', $statements[0]); 426 | $this->assertStringContainsString('add column "foo" numrange', $statements[0]); 427 | } 428 | 429 | public function testAddingTsrange() 430 | { 431 | $blueprint = new Blueprint('test'); 432 | $blueprint->tsrange('foo'); 433 | $statements = $blueprint->toSql( 434 | $this->getConnection(), 435 | $this->getGrammar() 436 | ); 437 | 438 | $this->assertEquals(1, count($statements)); 439 | $this->assertStringContainsString('alter table', $statements[0]); 440 | $this->assertStringContainsString('add column "foo" tsrange', $statements[0]); 441 | } 442 | 443 | public function testAddingTstzrange() 444 | { 445 | $blueprint = new Blueprint('test'); 446 | $blueprint->tstzrange('foo'); 447 | $statements = $blueprint->toSql( 448 | $this->getConnection(), 449 | $this->getGrammar() 450 | ); 451 | 452 | $this->assertEquals(1, count($statements)); 453 | $this->assertStringContainsString('alter table', $statements[0]); 454 | $this->assertStringContainsString('add column "foo" tstzrange', $statements[0]); 455 | } 456 | 457 | public function testAddingDatarange() 458 | { 459 | $blueprint = new Blueprint('test'); 460 | $blueprint->daterange('foo'); 461 | $statements = $blueprint->toSql( 462 | $this->getConnection(), 463 | $this->getGrammar() 464 | ); 465 | 466 | $this->assertEquals(1, count($statements)); 467 | $this->assertStringContainsString('alter table', $statements[0]); 468 | $this->assertStringContainsString('add column "foo" daterange', $statements[0]); 469 | } 470 | 471 | public function testAddingTsvector() 472 | { 473 | $blueprint = new Blueprint('test'); 474 | $blueprint->tsvector('foo'); 475 | $statements = $blueprint->toSql( 476 | $this->getConnection(), 477 | $this->getGrammar() 478 | ); 479 | 480 | $this->assertEquals(1, count($statements)); 481 | $this->assertStringContainsString('alter table', $statements[0]); 482 | $this->assertStringContainsString('add column "foo" tsvector', $statements[0]); 483 | } 484 | } 485 | --------------------------------------------------------------------------------