jackardios/laravel-eloquent-spatial 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

jackardios/laravel-eloquent-spatial

Composer 安装命令:

composer require jackardios/laravel-eloquent-spatial

包简介

Spatial library for Laravel

README 文档

README

Latest Version on Packagist Total Downloads

Laravel package for working with spatial data types and functions in Eloquent.

Supported Databases

  • MySQL 5.7 / 8.x
  • MariaDB 10.x
  • PostgreSQL 12+ with PostGIS 3.4+

Requirements

  • PHP 8.1+
  • Laravel 10.x / 11.x / 12.x

Installation

composer require jackardios/laravel-eloquent-spatial

Quick Start

1. Create a Migration

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('places', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->geometry('location', subtype: 'point')->nullable();
            $table->geometry('area', subtype: 'polygon')->nullable();
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('places');
    }
};

2. Set Up Your Model

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Jackardios\EloquentSpatial\Objects\Point;
use Jackardios\EloquentSpatial\Objects\Polygon;
use Jackardios\EloquentSpatial\Traits\HasSpatial;

/**
 * @property Point $location
 * @property Polygon $area
 */
class Place extends Model
{
    use HasSpatial;

    protected $fillable = [
        'name',
        'location',
        'area',
    ];

    protected $casts = [
        'location' => Point::class,
        'area' => Polygon::class,
    ];
}

3. Work with Spatial Data

use App\Models\Place;
use Jackardios\EloquentSpatial\Objects\Point;
use Jackardios\EloquentSpatial\Objects\Polygon;
use Jackardios\EloquentSpatial\Objects\LineString;
use Jackardios\EloquentSpatial\Enums\Srid;

// Create a place with a point location
// Note: Point constructor uses (longitude, latitude) order
$place = Place::create([
    'name' => 'Eiffel Tower',
    'location' => new Point(2.2945, 48.8584),
]);

// Create with SRID
$place = Place::create([
    'name' => 'Big Ben',
    'location' => new Point(-0.1246, 51.5007, Srid::WGS84),
]);

// Create with polygon area
$place = Place::create([
    'name' => 'Central Park',
    'area' => new Polygon([
        new LineString([
            new Point(-73.9819, 40.7681),
            new Point(-73.9580, 40.8006),
            new Point(-73.9498, 40.7969),
            new Point(-73.9737, 40.7644),
            new Point(-73.9819, 40.7681), // Close the ring
        ]),
    ]),
]);

// Access coordinates
echo $place->location->longitude; // 2.2945
echo $place->location->latitude;  // 48.8584
echo $place->location->srid;      // 4326 (if using WGS84)

// Convert to different formats
$place->location->toWkt();     // POINT(2.2945 48.8584)
$place->location->toJson();    // {"type":"Point","coordinates":[2.2945,48.8584]}
$place->location->toArray();   // ['type' => 'Point', 'coordinates' => [2.2945, 48.8584]]

Geometry Classes

All geometry classes support creating instances from various formats:

use Jackardios\EloquentSpatial\Objects\Point;

// From constructor
$point = new Point(longitude: 2.2945, latitude: 48.8584, srid: 4326);

// From WKT
$point = Point::fromWkt('POINT(2.2945 48.8584)', srid: 4326);

// From GeoJSON
$point = Point::fromJson('{"type":"Point","coordinates":[2.2945,48.8584]}');

// From array
$point = Point::fromArray(['type' => 'Point', 'coordinates' => [2.2945, 48.8584]]);

// From WKB
$point = Point::fromWkb($binaryData);

Available Geometry Types

Class Description
Point Single coordinate (longitude, latitude)
LineString Ordered sequence of Points
Polygon Closed shape defined by LineStrings
MultiPoint Collection of Points
MultiLineString Collection of LineStrings
MultiPolygon Collection of Polygons
GeometryCollection Mixed collection of any geometry types
BoundingBox Rectangular bounds with antimeridian support

Coordinate Validation

The Point class validates coordinates automatically:

// Valid coordinates
$point = new Point(180, 90);    // OK
$point = new Point(-180, -90);  // OK

// Invalid coordinates throw InvalidArgumentException
$point = new Point(200, 0);     // Error: Longitude must be between -180 and 180
$point = new Point(0, 100);     // Error: Latitude must be between -90 and 90

Spatial Query Scopes

The HasSpatial trait provides query scopes for spatial operations:

Distance Queries

use App\Models\Place;
use Jackardios\EloquentSpatial\Objects\Point;

$referencePoint = new Point(-0.1246, 51.5007, 4326);

// Add distance to results
$places = Place::query()
    ->withDistanceSphere('location', $referencePoint)
    ->get();

foreach ($places as $place) {
    echo $place->distance; // Distance in meters
}

// Filter by distance
$nearbyPlaces = Place::query()
    ->whereDistanceSphere('location', $referencePoint, '<', 5000) // Within 5km
    ->get();

// Order by distance
$closestPlaces = Place::query()
    ->orderByDistanceSphere('location', $referencePoint)
    ->limit(10)
    ->get();

Spatial Relationship Queries

use Jackardios\EloquentSpatial\Objects\Polygon;

$searchArea = Polygon::fromJson('{"type":"Polygon","coordinates":[[[-1,-1],[1,-1],[1,1],[-1,1],[-1,-1]]]}');

// Find places within an area
Place::whereWithin('location', $searchArea)->get();
Place::whereNotWithin('location', $searchArea)->get();

// Find places containing a point
Place::whereContains('area', $point)->get();
Place::whereNotContains('area', $point)->get();

// Other spatial relationships
Place::whereTouches('area', $geometry)->get();
Place::whereIntersects('location', $geometry)->get();
Place::whereCrosses('route', $geometry)->get();
Place::whereDisjoint('location', $geometry)->get();
Place::whereOverlaps('area', $geometry)->get();
Place::whereEquals('location', $point)->get();

// Filter by SRID
Place::whereSrid('location', '=', 4326)->get();

// Get centroid
Place::query()
    ->withCentroid('area')
    ->withCasts(['centroid' => Point::class])
    ->get();

BoundingBox

The BoundingBox class represents rectangular geographic bounds:

use Jackardios\EloquentSpatial\Objects\BoundingBox;
use Jackardios\EloquentSpatial\Objects\Point;

// Create from corner points
$bbox = new BoundingBox(
    leftBottom: new Point(-74.0, 40.7),
    rightTop: new Point(-73.9, 40.8)
);

// Create from geometry
$bbox = BoundingBox::fromGeometry($polygon);

// Create from points with padding
$bbox = BoundingBox::fromPoints($pointsArray, minPadding: 0.01);

// Access bounds
$bbox->getLeftBottom();  // Bottom-left Point
$bbox->getRightTop();    // Top-right Point

// Convert to geometry
$polygon = $bbox->toPolygon();
$geometry = $bbox->toGeometry(); // Returns MultiPolygon if crosses antimeridian

// Check if crosses antimeridian (dateline)
$bbox->crossesAntimeridian(); // true/false

// Serialize
$bbox->toArray();  // ['left' => ..., 'bottom' => ..., 'right' => ..., 'top' => ...]
$bbox->toJson();

BoundingBox as Model Attribute

use Jackardios\EloquentSpatial\Objects\BoundingBox;

class Region extends Model
{
    use HasSpatial;

    protected $casts = [
        // Store as geometry column
        'bounds' => BoundingBox::class,

        // Or store as JSON
        'bounds' => BoundingBox::class . ':json',
    ];
}

SRID Support

Spatial Reference Identifiers define coordinate systems:

use Jackardios\EloquentSpatial\Enums\Srid;
use Jackardios\EloquentSpatial\EloquentSpatial;

// Available SRID constants
Srid::WGS84;        // 4326 - GPS coordinates
Srid::WEB_MERCATOR; // 3857 - Web maps (Google Maps, etc.)

// Set default SRID for all geometries
EloquentSpatial::setDefaultSrid(Srid::WGS84);

Extending Geometry Classes

Using Macros

use Jackardios\EloquentSpatial\Objects\Geometry;

// Register in a service provider
Geometry::macro('distanceToKm', function (Point $other): float {
    /** @var Geometry $this */
    // Custom distance calculation
});

// Usage
$point->distanceToKm($otherPoint);

Custom Geometry Classes

use Jackardios\EloquentSpatial\Objects\Point;
use Jackardios\EloquentSpatial\EloquentSpatial;

class CustomPoint extends Point
{
    public function toLatLngArray(): array
    {
        return ['lat' => $this->latitude, 'lng' => $this->longitude];
    }
}

// Register in service provider
EloquentSpatial::usePoint(CustomPoint::class);

API Reference

For complete API documentation, see API.md.

Upgrading

See UPGRADE.md for upgrade instructions from previous versions.

Development

# Start database containers
docker-compose up -d

# Run tests
composer pest:mysql
composer pest:mariadb
composer pest:postgres

# Static analysis
composer phpstan

# Code formatting
composer pint

License

MIT License. See LICENSE.md for details.

jackardios/laravel-eloquent-spatial 适用场景与选型建议

jackardios/laravel-eloquent-spatial 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 734 次下载、GitHub Stars 达 0, 最近一次更新时间为 2021 年 10 月 09 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 jackardios/laravel-eloquent-spatial 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 jackardios/laravel-eloquent-spatial 我们能提供哪些服务?
定制开发 / 二次开发

基于 jackardios/laravel-eloquent-spatial 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 734
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 13
  • 依赖项目数: 1
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2021-10-09