You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:55:53