angel-source-labs / laravel-spatial
Laravel的空间数据类型扩展。
Requires
- php: >=7.2.5
- ext-json: *
- ext-pdo: *
- angel-source-labs/laravel-expressions: ^1.1
- doctrine/dbal: ^2.6|^3.0
- geo-io/wkb-parser: ^1.0
- jmikola/geojson: ^1.0
- laravel/framework: >=6.0
Requires (Dev)
This package is auto-updated.
Last update: 2024-09-06 07:13:03 UTC
README
Laravel包,用于轻松地在PostGIS、MySQL 5.7和MySQL 8中处理GIS数据类型。
支持的兼容性
Laravel
此包针对以下Laravel版本进行了测试
- Laravel 6.x
- Laravel 7.x
- Laravel 8.x
- Laravel 9.x
- Laravel 10.x
数据库
此包针对以下数据库进行了测试
未来
这些数据库的支持可能在未来版本中提供。此包已设计为支持这些数据库,但工作尚未完成。
- SQLServer
- SQLite
历史和动机
我们非常喜欢grimzy/laravel-mysql-spatial Laravel Eloquent API,并且我们希望也能使用Postgis。(参见问题137)。此包的目标是提供一个与grimzy/laravel-mysql-spatial包兼容的API,同时也支持Postgis和额外的数据库驱动程序。
此包是grimzy/laravel-mysql-spatial
的分支和大量重构
- 重构以使用
laravel-expressions
提供Postgis、MySQL 8和MySQL 5.7之间的数据库兼容性 - 重构以在PHPUnit测试中使用
orchestra/testbench
- PHPUnit测试已更新为使用PHPUnit 9.x而不是PHPUnit 6.x
历史上,grimzy/laravel-mysql-spatial
本身是njbarrett/laravel-postgis
的分支,现在是mstaack/laravel-postgis
。这些laravel-postgis
包提供了对Postgis的访问,但不提供grimzy/laravel-mysql-spatial
添加的Laravel Eloquent空间分析函数。
- 2015年3月:phaza/laravel-postgres Peter Haza
- 2016年5月:njbarrett/laravel-postgis Nick Barrett
- 2017年3月:grimzy/laravel-mysql-spatial Joseph Estefane
- 2022年2月:(此包)Angel-Source-Labs/laravel-spatial Brion Finlay
- 2020年3月:mstaack/laravel-postgis Max Staack
- 2017年3月:grimzy/laravel-mysql-spatial Joseph Estefane
- 2016年5月:njbarrett/laravel-postgis Nick Barrett
安装
使用composer添加包
$ composer require angel-source-labs/laravel-spatial
快速入门
创建迁移
从命令行
php artisan make:migration create_places_table
然后编辑您刚刚创建的迁移,添加至少一个空间数据字段。
use Illuminate\Database\Migrations\Migration; // use SpatialBlueprint for Spatial features and for proper code completion use AngelSourceLabs\LaravelSpatial\Schema\SpatialBlueprint as Blueprint; class CreatePlacesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('places', function(Blueprint $table) { $table->increments('id'); $table->string('name')->unique(); // Add a Point spatial data field named location $table->point('location')->nullable(); // Add a Polygon spatial data field named area $table->polygon('area')->nullable(); $table->timestamps(); }); // Or create the spatial fields with an SRID (e.g. 4326 WGS84 spheroid) Schema::create('places_with_srid', function(Blueprint $table) { $table->increments('id'); $table->string('name')->unique(); // Add a Point spatial data field named location with SRID 4326 $table->point('location', 4326)->nullable(); // Add a Polygon spatial data field named area with SRID 4326 $table->polygon('area', 4326)->nullable(); $table->timestamps(); }); // In Postgis, you can also create spatial fields that are Geography types instead of Geometry types Schema::create('places_with_geography', function(Blueprint $table) { $table->increments('id'); $table->string('name')->unique(); // Add a Point spatial data field named location with SRID 4326 $table->point('location', 4326, Blueprint::GEOGRAPHY)->nullable(); // Add a Polygon spatial data field named area with SRID 4326 $table->polygon('area', 4326, Blueprint::GEOGRAPHY)->nullable(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('places'); } }
运行迁移
php artisan migrate
创建模型
从命令行
php artisan make:model Place
然后编辑您刚刚创建的模型。它必须使用SpatialTrait
并定义一个名为$spatialFields
的数组,其中包含在迁移中创建的空间数据字段名称
namespace App; use AngelSourceLabs\LaravelSpatial\Eloquent\SpatialTrait; use Illuminate\Database\Eloquent\Model; /** * @property \AngelSourceLabs\LaravelSpatial\Types\Point $location * @property \AngelSourceLabs\LaravelSpatial\Types\Polygon $area */ class Place extends Model { use SpatialTrait; protected $fillable = [ 'name' ]; protected $spatialFields = [ 'location', 'area' ]; }
保存模型
use AngelSourceLabs\LaravelSpatial\Types\LineString; use AngelSourceLabs\LaravelSpatial\Types\Point; use AngelSourceLabs\LaravelSpatial\Types\Polygon; $place1 = new Place(); $place1->name = 'Empire State Building'; // saving a point $place1->location = new Point(40.7484404, -73.9878441); // (lat, lng) $place1->save(); // saving a polygon $place1->area = new Polygon([new LineString([ new Point(40.74894149554006, -73.98615270853043), new Point(40.74848633046773, -73.98648262023926), new Point(40.747925497790725, -73.9851602911949), new Point(40.74837050671544, -73.98482501506805), new Point(40.74894149554006, -73.98615270853043) ])]); $place1->save();
或者如果您的数据库字段是用特定的SRID创建的
use AngelSourceLabs\LaravelSpatial\Types\LineString; use AngelSourceLabs\LaravelSpatial\Types\Point; use AngelSourceLabs\LaravelSpatial\Types\Polygon; $place1 = new Place(); $place1->name = 'Empire State Building'; // saving a point with SRID 4326 (WGS84 spheroid) $place1->location = new Point(40.7484404, -73.9878441, 4326); // (lat, lng, srid) $place1->save(); // saving a polygon with SRID 4326 (WGS84 spheroid) $place1->area = new Polygon([new LineString([ new Point(40.74894149554006, -73.98615270853043), new Point(40.74848633046773, -73.98648262023926), new Point(40.747925497790725, -73.9851602911949), new Point(40.74837050671544, -73.98482501506805), new Point(40.74894149554006, -73.98615270853043) ])], 4326); $place1->save();
注意:当保存集合几何体(
LineString
、Polygon
、MultiPoint
、MultiLineString
和GeometryCollection
)时,仅顶部几何体应在构造函数中设置SRID。在上面的示例中,当创建一个
new Polygon()
时,我们只设置了Polygon
上的SRID,并使用默认值用于LineString
和Point
对象。
检索模型
$place2 = Place::first(); $lat = $place2->location->getLat(); // 40.7484404 $lng = $place2->location->getLng(); // -73.9878441
几何类
可用的几何类
@startuml interface GeometryInterface interface Jsonable Interface JsonSerializable interface Arrayable interface IteratorAggregate Interface Countable Interface ArrayAccess abstract Class Geometry Class GeometryCollection Class Point abstract Class PointCollection Class MultiLineString Class MultiPolygon Class MultiPoint Class LineString Class Polygon Jsonable <|.. Geometry JsonSerializable <|.. Geometry GeometryInterface <|.. Geometry Geometry <|-- Point Geometry <|-- GeometryCollection Arrayable <|.. GeometryCollection IteratorAggregate <|.. GeometryCollection Countable <|.. GeometryCollection ArrayAccess <|.. GeometryCollection GeometryCollection <|-- PointCollection PointCollection <|-- MultiPoint PointCollection <|-- LineString GeometryCollection <|-- MultiLineString MultiLineString <|-- Polygon GeometryCollection <|-- MultiPolygon
使用几何类
为了使您的Eloquent模型处理几何类,它必须使用AngelSourceLabs\LaravelSpatial\Eloquent\SpatialTrait
特性,并定义一个protected
属性$spatialFields
,该属性为一个包含空间数据类型列名的数组(示例请见快速入门)。
IteratorAggregate和ArrayAccess
几何集合(LineString
、Polygon
、MultiPoint
、MultiLineString
和GeometryCollection
)实现了IteratorAggregate
和ArrayAccess
,这使得进行迭代器和数组操作变得容易。例如
$polygon = $multipolygon[10]; // ArrayAccess // IteratorAggregate for($polygon as $i => $linestring) { echo (string) $linestring; }
辅助函数
从/到已知文本(WKT)
// fromWKT($wkt, $srid = 0) $point = Point::fromWKT('POINT(2 1)'); $point->toWKT(); // POINT(2 1) $polygon = Polygon::fromWKT('POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))'); $polygon->toWKT(); // POLYGON((0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1))
从/到字符串
// fromString($wkt, $srid = 0) $point = new Point(1, 2); // lat, lng (string)$point // lng, lat: 2 1 $polygon = Polygon::fromString('(0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)'); (string)$polygon; // (0 0,4 0,4 4,0 4,0 0),(1 1, 2 1, 2 2, 1 2,1 1)
从/到JSON(GeoJSON)
几何类实现了JsonSerializable
和Illuminate\Contracts\Support\Jsonable
,以帮助将其序列化为GeoJSON
$point = new Point(40.7484404, -73.9878441); json_encode($point); // or $point->toJson(); // { // "type": "Feature", // "properties": {}, // "geometry": { // "type": "Point", // "coordinates": [ // -73.9878441, // 40.7484404 // ] // } // }
要将GeoJSON字符串反序列化为几何类,可以使用Geometry::fromJson($json_string)
$location = Geometry::fromJson('{"type":"Point","coordinates":[3.4,1.2]}'); $location instanceof Point::class; // true $location->getLat(); // 1.2 $location->getLng()); // 3.4
作用域:空间分析函数
空间分析函数是通过使用Eloquent本地作用域实现的。
可用作用域
distance($geometryColumn, $geometry, $distance)
distanceExcludingSelf($geometryColumn, $geometry, $distance)
distanceSphere($geometryColumn, $geometry, $distance)
distanceSphereExcludingSelf($geometryColumn, $geometry, $distance)
comparison($geometryColumn, $geometry, $relationship)
within($geometryColumn, $polygon)
crosses($geometryColumn, $geometry)
contains($geometryColumn, $geometry)
disjoint($geometryColumn, $geometry)
equals($geometryColumn, $geometry)
intersects($geometryColumn, $geometry)
overlaps($geometryColumn, $geometry)
doesTouch($geometryColumn, $geometry)
orderBySpatial($geometryColumn, $geometry, $orderFunction, $direction = 'asc')
orderByDistance($geometryColumn, $geometry, $direction = 'asc')
orderByDistanceSphere($geometryColumn, $geometry, $direction = 'asc')
请注意,空间分析函数的行为和可用性在每个数据库和数据库版本中都有所不同。
空间函数参考
迁移
use AngelSourceLabs\LaravelSpatial\Schema\SpatialBlueprint; use Illuminate\Database\Migrations\Migration; class CreatePlacesTable extends Migration { // ... }
列
可用的空间类型迁移蓝图
$table->geometry(string $column_name, int $srid = 0)
$table->point(string $column_name, int $srid = 0)
$table->lineString(string $column_name, int $srid = 0)
$table->polygon(string $column_name, int $srid = 0)
$table->multiPoint(string $column_name, int $srid = 0)
$table->multiLineString(string $column_name, int $srid = 0)
$table->multiPolygon(string $column_name, int $srid = 0)
$table->geometryCollection(string $column_name, int $srid = 0)
空间类型参考
空间索引
您可以在迁移中使用spatialIndex
和dropSpatialIndex
蓝图来添加或删除空间索引。
$table->spatialIndex('column_name')
$table->dropSpatialIndex(['column_name'])
或$table->dropSpatialIndex('index_name')
关于空间索引的说明,请见MySQL文档
对于
MyISAM
和(从MySQL 5.7.5开始)InnoDB
表,MySQL可以使用类似于创建常规索引的语法创建空间索引,但使用SPATIAL
关键字。空间索引中的列必须声明为NOT NULL
。
请务必阅读这篇有关 Laravel 文档中索引长度的重要说明(点击查看)。
例如,作为快速入门的后续步骤;在命令行中,生成一个新的迁移文件
php artisan make:migration update_places_table
然后编辑您刚才创建的迁移文件
use Illuminate\Database\Migrations\Migration; use AngelSourceLabs\LaravelSpatial\Schema\SpatialBlueprint as Blueprint; use Illuminate\Support\Facades\Schema; class UpdatePlacesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { // MySQL < 5.7.5: table has to be MyISAM // \DB::statement('ALTER TABLE places ENGINE = MyISAM'); Schema::table('places', function (Blueprint $table) { // Make sure point is not nullable $table->point('location')->change(); // Add a spatial index on the location field $table->spatialIndex('location'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('places', function (Blueprint $table) { $table->dropSpatialIndex(['location']); // either an array of column names or the index name }); // \DB::statement('ALTER TABLE places ENGINE = InnoDB'); Schema::table('places', function (Blueprint $table) { $table->point('location')->nullable()->change(); }); } }
测试
启动用于测试的 MySQL 5.7、MySQL8 和 Postgis Docker 容器。
$ composer docker
运行测试。单元测试可以在没有数据库服务器 Docker 容器的情况下运行。
$ composer test # or $ composer test:unit $ composer test:integration
贡献
欢迎提出建议和拉取请求!带有测试的拉取请求是最好的!还有许多空间函数需要实现或以创新的方式使用空间函数。
鸣谢
本项目的灵感来源于 grimzy/laravel-mysql-spatial 和 njbarrett 的 Laravel postgis 包。
许可证
为 Laravel 的空间函数是开源软件,使用 MIT 许可证授权。