├── .gitignore ├── src ├── Database │ ├── Schema │ │ ├── MySqlBuilder.php │ │ ├── Blueprint.php │ │ └── Grammar │ │ │ └── MySqlGrammar.php │ ├── MySqlConnection.php │ └── Eloquent │ │ ├── LaraGisTrait.php │ │ └── Builder.php ├── LaraGisServiceProvider.php ├── Area.php └── Coordinates.php ├── composer.json └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /src/Database/Schema/MySqlBuilder.php: -------------------------------------------------------------------------------- 1 | addColumn('point', $column); 12 | } 13 | 14 | public function polygon($column) 15 | { 16 | return $this->addColumn('polygon', $column); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Database/Schema/Grammar/MySqlGrammar.php: -------------------------------------------------------------------------------- 1 | proxiedConnection = $connection; 16 | foreach (get_object_vars($connection) as $name => $value) { 17 | $this->{$name} = &$this->proxiedConnection->{$name}; 18 | } 19 | $this->schemaGrammar = new Schema\Grammar\MySqlGrammar; 20 | } 21 | 22 | public function getSchemaBuilder() 23 | { 24 | return new Schema\MySqlBuilder($this); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/LaraGisServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->runningInConsole()) { 13 | $this->app->resolving('db', function (DatabaseManager $dbManager) { 14 | $extender = function ($config, $name) { 15 | $mysqlConnection = $this->factory->make($config, $name); 16 | return new Database\MySqlConnection($mysqlConnection); 17 | }; 18 | 19 | $dbManager->extend('mysql', $extender->bindTo($dbManager, get_class($dbManager))); 20 | return $dbManager; 21 | }); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ralphschindler/laragis", 3 | "description": "A geospatial library and set of utilities for Laravel", 4 | "keywords": ["php", "geo", "gis", "spatial", "geospatial", "laravel"], 5 | "type": "library", 6 | "license": "UNLICENSE", 7 | "authors": [ 8 | { 9 | "name": "Ralph Schindler" 10 | } 11 | ], 12 | "require": { 13 | "php": ">=5.5" 14 | }, 15 | "require-dev": { 16 | "illuminate/database": "~5.3", 17 | "illuminate/support": "~5.3", 18 | "phpunit/phpunit": "~5.5" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "LaraGis\\": "src/" 23 | } 24 | }, 25 | "extra": { 26 | "branch-alias": { 27 | "dev-master": "1.0.x-dev" 28 | }, 29 | "laravel": { 30 | "providers": [ 31 | "LaraGis\\LaraGisServiceProvider" 32 | ] 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Database/Eloquent/LaraGisTrait.php: -------------------------------------------------------------------------------- 1 | getCastType($key); 18 | if (substr($type, 0, 7) === 'laragis') { 19 | $geoJson = json_decode($value, true); 20 | switch ($geoJson['type']) { 21 | case 'Polygon': 22 | $polygon = new Area(); 23 | foreach ($geoJson['coordinates'][0] as $coordinate) { 24 | $polygon->addCoordinates(new Coordinates($coordinate[0], $coordinate[1])); 25 | } 26 | return $polygon; 27 | case 'Point': 28 | return new Coordinates($geoJson['coordinates'][0], $geoJson['coordinates'][1]); 29 | } 30 | } 31 | 32 | return parent::castAttribute($key, $value); 33 | } 34 | } -------------------------------------------------------------------------------- /src/Area.php: -------------------------------------------------------------------------------- 1 | coordinatesSet[] = $coordinates; 15 | } 16 | 17 | public function getCoordinatesSet() 18 | { 19 | return $this->coordinatesSet; 20 | } 21 | 22 | public function castToString($separator, $coordinatesSeparator = ', ', $coordinatesOrder = Coordinates::LATITUDE_FIRST) 23 | { 24 | 25 | } 26 | 27 | public function __toString() 28 | { 29 | $strs = []; 30 | foreach ($this->coordinatesSet as $coordinates) { 31 | $strs[] = (string) $coordinates; 32 | } 33 | return '[' . implode(' -> ', $strs) . ']'; 34 | } 35 | 36 | public function getIterator() 37 | { 38 | return new \ArrayIterator($this->coordinatesSet); 39 | } 40 | 41 | public function count() 42 | { 43 | return count($this->coordinatesSet); 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/Database/Eloquent/Builder.php: -------------------------------------------------------------------------------- 1 | getModel(); 13 | $casts = $model->getCasts(); 14 | $connection = $model->getConnection(); 15 | 16 | foreach ($casts as $column => $type) { 17 | if (substr($type, 0, 7) === 'laragis') { 18 | $columns[] = $connection->raw("ST_AsGeoJSON($column) as $column"); 19 | } 20 | } 21 | 22 | return parent::get($columns); 23 | } 24 | 25 | public function update(array $values) 26 | { 27 | foreach ($values as $key => $value) { 28 | $model = $this->getModel(); 29 | $casts = $model->getCasts(); 30 | $connection = $model->getConnection(); 31 | 32 | foreach ($casts as $column => $type) { 33 | // @todo Additional checking on cast type 34 | if (substr($type, 0, 7) === 'laragis') { 35 | switch (true) { 36 | case ($value instanceof Coordinates); 37 | $values[$key] = $connection->raw("ST_ToWKF(POINT({$value->getLatitudeLongitude(' ')}))"); 38 | break; 39 | case ($value instanceof Area): 40 | 41 | break; 42 | } 43 | } 44 | } 45 | } 46 | return parent::update($values); 47 | } 48 | 49 | } 50 | 51 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # LaraGis 2 | 3 | LaraGis provides geospatial database and Eloquent features to Laravel. 4 | 5 | Features: 6 | 7 | - Simple Entity API, for use in casting model properties 8 | - Fast serialization of geospatial data from MySql (not PHP userland) via `ST_AsGeoJSON()` 9 | 10 | ## Installation 11 | 12 | To get started with Socialite, add to your `composer.json` file as a dependency: 13 | 14 | composer require ralphschindler/laragis 15 | 16 | ### Configuration 17 | 18 | After installing the Socialite library, register the `LaraGis\LaraGisProvider` in your `config/app.php` configuration file: 19 | 20 | ```php 21 | 'providers' => [ 22 | // Other service providers... 23 | 24 | LaraGis\LaraGisProvider::class, 25 | ], 26 | ``` 27 | 28 | ## Basic Usage 29 | 30 | To use in `Eloquent` based models, use the `LaraGisTrait`, and specify a column to be cast into a geospatial datatype with the `laragis` key in the $casts array: 31 | 32 | ```php 33 | class Place extends Model 34 | { 35 | use LaraGisTrait; 36 | 37 | protected $table = 'places'; 38 | 39 | protected $casts = [ 40 | 'coordinates' => 'laragis' 41 | ]; 42 | } 43 | ``` 44 | 45 | ```php 46 | $place = App\Places::find(1); 47 | $coordinates = $place->coordinates; 48 | echo $coordinates->getLatitudeLongitude(); // "30, -90" 49 | ``` 50 | 51 | ## Entity API 52 | 53 | ```php 54 | 55 | /** 56 | * @property double $latitude 57 | * @property double $longitude 58 | */ 59 | class Coordinates { 60 | public function __construct($latitude = null, $longitude = null); 61 | public function setLatitude($latitude); 62 | public function getLatitude(); 63 | public function setLongitude($longitude); 64 | public function getLongitude(); 65 | public function castToString($separator, $coordinatesOrder = self::LATITUDE_FIRST) 66 | } 67 | 68 | class Area implements \IteratorAggregate, \Countable { 69 | public function addCoordinates(Coordinates $coordinates); 70 | public function getCoordinates(); 71 | } 72 | ``` -------------------------------------------------------------------------------- /src/Coordinates.php: -------------------------------------------------------------------------------- 1 | latitude = $latitude; 20 | $this->longitude = $longitude; 21 | } 22 | 23 | public function setLatitude($latitude) 24 | { 25 | $this->latitude = $latitude; 26 | } 27 | 28 | public function getLatitude() 29 | { 30 | return $this->latitude; 31 | } 32 | 33 | public function setLongitude($longitude) 34 | { 35 | $this->longitude = $longitude; 36 | } 37 | 38 | public function getLongitude() 39 | { 40 | return $this->longitude; 41 | } 42 | 43 | public function castToString($separator = ', ', $coordinatesOrder = self::LATITUDE_FIRST) 44 | { 45 | switch ($coordinatesOrder) { 46 | case self::LONGITUDE_FIRST: 47 | return "{$this->longitude}{$separator}{$this->latitude}"; 48 | default: 49 | return "{$this->latitude}{$separator}{$this->longitude}"; 50 | } 51 | } 52 | 53 | public function __get($name) 54 | { 55 | switch (strtolower($name)) { 56 | case 'latitude': return $this->latitude; 57 | case 'longitude': return $this->longitude; 58 | default: throw new \DomainException('A point property must be a longitude or latitude'); 59 | } 60 | } 61 | 62 | public function __set($name, $value) 63 | { 64 | switch (strtolower($name)) { 65 | case 'latitude': $this->setLatitude($value); break; 66 | case 'longitude': $this->setLongitude($value); break; 67 | default: throw new \DomainException('A point property must be a longitude or latitude'); 68 | } 69 | } 70 | 71 | public function __toString() 72 | { 73 | return $this->getLatitudeLongitude(); 74 | } 75 | } 76 | 77 | --------------------------------------------------------------------------------