Laravel 5.7中Lighthouse GraphQL定义Polygon字段遇阻,求指导
在Laravel 5.7 + Lighthouse PHP中实现Polygon几何类型字段
别担心,我之前在Laravel 5.7里用Lighthouse处理空间类型字段时也踩过坑,下面一步步教你怎么搞定Polygon类型的定义和查询:
1. 先配置Laravel的空间字段支持
Laravel 5.7本身对空间字段的支持有限,建议借助grimzy/laravel-mysql-spatial包简化操作:
composer require grimzy/laravel-mysql-spatial
以Area模型为例,引入空间特性并声明空间字段:
// app/Area.php use Grimzy\LaravelMysqlSpatial\Eloquent\SpatialTrait; class Area extends Model { use SpatialTrait; protected $fillable = ['name']; protected $spatialFields = ['boundary']; // boundary就是我们要定义的Polygon字段 }
对应的迁移文件要创建Polygon类型的数据库字段:
// database/migrations/create_areas_table.php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Grimzy\LaravelMysqlSpatial\Schema\Blueprint as SpatialBlueprint; class CreateAreasTable extends Migration { public function up() { Schema::create('areas', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); /** @var SpatialBlueprint $table */ $table->polygon('boundary'); // 创建Polygon类型字段 $table->timestamps(); }); } public function down() { Schema::dropIfExists('areas'); } }
2. 为Lighthouse创建自定义Polygon标量类型
Lighthouse默认没有内置Polygon标量,我们需要自己实现一个解析/序列化逻辑。创建app/GraphQL/Scalars/PolygonScalar.php:
<?php namespace App\GraphQL\Scalars; use GraphQL\Error\Error; use GraphQL\Type\Definition\ScalarType; use Grimzy\LaravelMysqlSpatial\Types\Polygon; use Illuminate\Support\Facades\Validator; class PolygonScalar extends ScalarType { public $name = 'Polygon'; public $description = '多边形空间类型,格式为嵌套数组:外层为线性环集合,每个环是[纬度, 经度]点的数组'; // 把模型中的Polygon对象序列化为数组返回给前端 public function serialize($value) { if ($value instanceof Polygon) { return $value->toArray(); } throw new Error('Polygon标量仅接受Polygon对象'); } // 解析前端传入的数组为Polygon对象 public function parseValue($value) { $validator = Validator::make(['polygon' => $value], [ 'polygon' => 'required|array|min:1', 'polygon.*' => 'array|min:4', // 每个线性环至少4个点(需闭合) 'polygon.*.*' => 'array|size:2', // 每个点必须是[纬度, 经度]格式 ]); if ($validator->fails()) { throw new Error('Polygon格式无效:' . implode(', ', $validator->errors()->all())); } return new Polygon($value); } // 解析GraphQL查询中的字面量语法 public function parseLiteral($valueNode) { if ($valueNode->kind !== \GraphQL\Language\AST\Kind::LIST) { throw new Error('Polygon标量需要数组字面量'); } $value = []; foreach ($valueNode->values as $ringNode) { $ring = []; if ($ringNode->kind !== \GraphQL\Language\AST\Kind::LIST) { throw new Error('Polygon中的每个环必须是数组'); } foreach ($ringNode->values as $pointNode) { if ($pointNode->kind !== \GraphQL\Language\AST\Kind::LIST || count($pointNode->values) !== 2) { throw new Error('Polygon环中的每个点必须是[纬度, 经度]数组'); } $ring[] = [ (float)$pointNode->values[0]->value, (float)$pointNode->values[1]->value, ]; } $value[] = $ring; } return $this->parseValue($value); } }
3. 在Lighthouse配置中注册自定义标量
打开config/lighthouse.php,找到scalars配置项,添加我们的自定义标量:
'scalars' => [ 'Polygon' => App\GraphQL\Scalars\PolygonScalar::class, ],
4. 在GraphQL Schema中使用Polygon类型
现在就可以在schema里直接用Polygon类型定义字段了:
type Area { id: ID! name: String! boundary: Polygon! createdAt: DateTime! updatedAt: DateTime! } type Query { area(id: ID!): Area! areas: [Area!]! } input CreateAreaInput { name: String! boundary: Polygon! } type Mutation { createArea(input: CreateAreaInput!): Area! }
5. 查询与Mutation示例
查询示例
获取指定区域的Polygon边界:
query GetArea($id: ID!) { area(id: $id) { id name boundary } }
返回结果中的boundary会是嵌套数组格式:
"boundary": [ [ [40.712776, -74.005974], [34.052235, -118.243683], [41.878114, -87.629798], [40.712776, -74.005974] ] ]
创建区域的Mutation示例
mutation CreateArea($input: CreateAreaInput!) { createArea(input: $input) { id name boundary } }
传入的变量:
{ "input": { "name": "东部城市群", "boundary": [ [ [40.712776, -74.005974], [34.052235, -118.243683], [41.878114, -87.629798], [40.712776, -74.005974] ] ] } }
注意事项
- 确保你的数据库(如MySQL)支持空间类型,表引擎需为InnoDB或MyISAM(推荐InnoDB)。
- Polygon的每个线性环必须闭合,即第一个点和最后一个点坐标完全一致。
- 如果遇到解析错误,可以检查自定义标量中的验证规则是否匹配你的数据格式需求。
内容的提问来源于stack exchange,提问作者Walidovic
相关产品推荐
相关产品推荐

