grimzy / laravel-mysql-spatial
Laravel 的 MySQL 空间数据类型扩展。
Requires
- php: >=7.3
- ext-json: *
- ext-pdo: *
- geo-io/wkb-parser: ^1.0
- illuminate/database: ^8.0
- jmikola/geojson: ^1.0
Requires (Dev)
- doctrine/dbal: ^2.5
- laravel/browser-kit-testing: ^2.0
- laravel/laravel: ^8.0
- mockery/mockery: ^1.3
- phpunit/phpunit: ~6.5
- 5.0.0
- dev-master / 4.0.x-dev
- 4.0.0
- 3.0.0
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.0
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- dev-mysql-5.6 / 1.0.x-dev
- 1.0.0
- dev-mysql-5.7
- dev-laravel-8
- dev-srid
- dev-fix/locale-polyfill
- dev-test-issue-26
- dev-builder-as-trait
This package is auto-updated.
Last update: 2024-09-17 16:20:18 UTC
README
Laravel 包,用于轻松处理 MySQL 空间数据类型 和 MySQL 空间函数。
请检查您 MySQL 版本的文档。MySQL 的空间数据扩展自 MySQL 5.5 开始支持,但许多空间函数在 5.6 和 5.7 中发生了变化。
版本
1.x.x
: MySQL 5.6(也支持 MySQL 5.5,但不是所有空间分析函数)2.x.x
: MySQL 5.7 和 8.0(Laravel 版本 < 8.0)3.x.x
: MySQL 8.0,支持 SRID(Laravel 版本 < 8.0)4.x.x
: MySQL 8.0,支持 SRID(Laravel 8+)[当前分支]5.x.x
: MySQL 5.7 和 8.0(Laravel 8+)
此包也支持 MariaDB。请参阅 MySQL/MariaDB 空间支持矩阵 了解兼容性。
安装
使用 composer 添加包
$ composer require grimzy/laravel-mysql-spatial:^4.0
# or for Laravel version < 8.0
$ composer require grimzy/laravel-mysql-spatial:^3.0
对于 MySQL 5.7
$ composer require grimzy/laravel-mysql-spatial:^2.0
对于 MySQL 5.6 和 5.5
$ composer require grimzy/laravel-mysql-spatial:^1.0
对于 Laravel 版本低于 5.5 或未使用自动发现时,请在 config/app.php
中注册服务提供器
'providers' => [ /* * Package Service Providers... */ Grimzy\LaravelMysqlSpatial\SpatialServiceProvider::class, ],
快速入门
创建迁移
从命令行
php artisan make:migration create_places_table
然后通过添加至少一个空间数据字段来编辑您刚刚创建的迁移。对于 Laravel 版本低于 5.5,您可以使用此包提供的 Blueprint(Grimzy\LaravelMysqlSpatial\Schema\Blueprint)
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; // For Laravel < 5.5 // use Grimzy\LaravelMysqlSpatial\Schema\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', 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(); // }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::drop('places'); } }
运行迁移
php artisan migrate
创建模型
从命令行
php artisan make:model Place
然后编辑您刚刚创建的模型。它必须使用 SpatialTrait
并定义一个名为 $spatialFields
的数组,包含在迁移中创建的 MySQL 空间数据字段名称(示例在 快速入门 中)
namespace App; use Illuminate\Database\Eloquent\Model; use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait; /** * @property \Grimzy\LaravelMysqlSpatial\Types\Point $location * @property \Grimzy\LaravelMysqlSpatial\Types\Polygon $area */ class Place extends Model { use SpatialTrait; protected $fillable = [ 'name' ]; protected $spatialFields = [ 'location', 'area' ]; }
保存模型
use Grimzy\LaravelMysqlSpatial\Types\Point; use Grimzy\LaravelMysqlSpatial\Types\Polygon; use Grimzy\LaravelMysqlSpatial\Types\LineString; $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 Grimzy\LaravelMysqlSpatial\Types\Point; use Grimzy\LaravelMysqlSpatial\Types\Polygon; use Grimzy\LaravelMysqlSpatial\Types\LineString; $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
几何类
可用的几何类
查看 类图。
使用几何类
为了使您的 Eloquent 模型处理几何类,它必须使用 Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait
特性并定义一个名为 protected
的属性 $spatialFields
,它是一个包含 MySQL 空间数据类型列名称的数组(示例在 快速入门 中)
迭代聚合和 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 Local Scopes 实现。
可用作用域
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')
请注意,MySQL 空间分析函数的行为和可用性在每个 MySQL 版本中都有所不同(参见 文档)。
迁移
对于 5.5 版本之前的 Laravel,您可以使用此包提供的 Blueprint:Grimzy\LaravelMysqlSpatial\Schema\Blueprint
。
use Illuminate\Database\Migrations\Migration; use Grimzy\LaravelMysqlSpatial\Schema\Blueprint; class CreatePlacesTable extends Migration { // ... }
列
可用的 MySQL 空间类型 迁移 Blueprint
$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
Blueprint 在迁移中添加或删除空间索引。
$table->spatialIndex('column_name')
$table->dropSpatialIndex(['column_name'])
或$table->dropSpatialIndex('index_name')
有关空间索引的更多信息,请参阅 MySQL 文档
对于
MyISAM
和(自 MySQL 5.7.5 以来)InnoDB
表,MySQL 可以使用与创建常规索引类似的语法创建空间索引,但使用SPATIAL
关键字。空间索引中的列必须声明为NOT NULL
。
另外,请参阅 Laravel 5.6 文档中的这条 重要说明,关于索引长度。
例如,作为 快速入门 的后续操作;从命令行,生成新的迁移
php artisan make:migration update_places_table
然后编辑您刚刚创建的迁移文件
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\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(); }); } }
测试
$ composer test # or $ composer test:unit $ composer test:integration
集成测试需要运行中的 MySQL 数据库。如果您已安装 Docker,可以轻松启动一个
$ make start_db # starts MySQL 8.0 # or $ make start_db V=5.7 # starts MySQL 5.7
贡献
欢迎提出建议和 pull request!带测试的 pull request 是最好的!还有很多 MySQL 空间函数要实现或创造性地使用空间函数的方法。
致谢
最初受到 njbarrett 的 Laravel postgis 包 的启发。