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

Laravel Lighthouse多字段联合唯一校验自定义Validator失效问题

问题根源

你在mutation参数上使用了@spread指令,会将pivot_model输入对象的字段展开为mutation的顶层参数,而你将@validator挂载在CreatePivotModelInput输入类型上,此时Validator内调用$this->arg()无法正确获取到对应参数值,导致unique规则的where闭包条件异常,只要表中存在任意一条field_1匹配的记录就会触发校验失败。

解决方案

方案1:移除@spread,调整校验规则路径

  1. 修改GraphQL Schema,移除参数上的@spread,将validator挂载到mutation字段上:
type PivotModel {
  id: ID!
  field_1: ID!
  field_2: ID!
  field_3: ID!
}

type Mutation {
  createPivotModel(pivot_model: CreatePivotModelInput!): PivotModel!
    @create
    @validator(class: "PivotModelInputValidator")
}

input CreatePivotModelInput {
  field_1: ID!
  field_2: ID!
  field_3: ID!
}
  1. 调整Validator的规则和消息前缀,匹配嵌套参数路径:
<?php
declare(strict_types=1);

namespace App\GraphQL\Validators;

use Illuminate\Validation\Rule;
use Nuwave\Lighthouse\Validation\Validator;

class PivotModelInputValidator extends Validator
{
    public function rules(): array
    {
        return [
            'pivot_model.field_1' => [
                'filled',
                'numeric',
                'integer',
                Rule::unique('pivot_model')
                    ->where('field_2', $this->arg('pivot_model.field_2'))
                    ->where('field_3', $this->arg('pivot_model.field_3'))
            ],
            'pivot_model.field_2' => [
                'filled',
                'numeric',
                'integer',
            ],
            'pivot_model.field_3' => [
                'filled',
                'numeric',
                'integer',
            ],
        ];
    }

    public function messages(): array
    {
        return [
            'pivot_model.field_1.unique' => 'duplicate_entry'
        ];
    }
}

方案2:保留@spread,调整Validator挂载位置

如果需要保留参数展开的特性,直接将validator挂载到mutation字段上即可:

  1. Schema修改:
type Mutation {
  createPivotModel(pivot_model: CreatePivotModelInput! @spread): PivotModel!
    @create
    @validator(class: "PivotModelInputValidator")
}

input CreatePivotModelInput {
  field_1: ID!
  field_2: ID!
  field_3: ID!
}
  1. Validator直接读取顶层参数即可,无需嵌套路径:
public function rules(): array
{
    return [
        'field_1' => [
            'filled',
            'numeric',
            'integer',
            Rule::unique('pivot_model')
                ->where('field_2', $this->arg('field_2'))
                ->where('field_3', $this->arg('field_3'))
        ],
        'field_2' => [
            'filled',
            'numeric',
            'integer',
        ],
        'field_3' => [
            'filled',
            'numeric',
            'integer',
        ],
    ];
}

方案3:捕获数据库异常兜底(推荐)

无需提前做校验查询,直接匹配数据库层的联合唯一约束,性能更高且不会出现规则和约束不一致的问题:
在app/Exceptions/Handler.php的render方法中添加异常捕获逻辑:

use Illuminate\Database\UniqueConstraintViolationException;

public function render($request, Throwable $e)
{
    if ($e instanceof UniqueConstraintViolationException && $e->getCode() === '23000') {
        if (str_contains($e->getMessage(), 'pivot_model_unique')) {
            return response()->json([
                'errors' => [
                    [
                        'message' => 'Validation failed for the field [createPivotModel].',
                        'extensions' => [
                            'validation' => [
                                'pivot_model' => ['duplicate_entry']
                            ],
                            'category' => 'validation'
                        ]
                    ]
                ]
            ], 422);
        }
    }
    return parent::render($request, $e);
}

内容的提问来源于stack exchange,提问作者user1108579

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 15:36:03