Laravel Lighthouse多字段联合唯一校验自定义Validator失效问题
问题根源
你在mutation参数上使用了@spread指令,会将pivot_model输入对象的字段展开为mutation的顶层参数,而你将@validator挂载在CreatePivotModelInput输入类型上,此时Validator内调用$this->arg()无法正确获取到对应参数值,导致unique规则的where闭包条件异常,只要表中存在任意一条field_1匹配的记录就会触发校验失败。
解决方案
方案1:移除@spread,调整校验规则路径
- 修改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! }
- 调整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字段上即可:
- Schema修改:
type Mutation { createPivotModel(pivot_model: CreatePivotModelInput! @spread): PivotModel! @create @validator(class: "PivotModelInputValidator") } input CreatePivotModelInput { field_1: ID! field_2: ID! field_3: ID! }
- 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
相关产品推荐
相关产品推荐

