Laravel 基于相关模型的 Lighthouse GraphQL 验证

Laravel Lighthouse GraphQL validation based on related model

使用 Laravel Lighthouse GraphQL,我想验证一个模型中的值,以便它始终与相关模型中的值匹配。

在这种情况下,Program 有一个 year_idCategory 也有一个 year_id。我想验证 ProgramCategory 使用相同的 year_id.

GraphQL 架构如下所示:

input CreateCategory {
    year_id: ID!
    name: String!
}

input CreateProgram {
    year_id: ID!
    name: String!
    category: CreateCategoryRelation
}

input CreateCategoryRelation {
    connect: ID
}

现在,如果我用 year_id: 1 创建一个 Category(return 类别 id=1):

mutation {
  createCategory(input:{
    year_id: 1
    name: "category in year 1"
  }) {
    name
    id
  }
}

然后尝试创建一个 Programyear_id: 2 相关的新 Category

mutation {
  createProgram(input:{
    year_id: 2
    name: "Program in year 2"
    category: {
      connect: 1
    }
  }) {
    id
    name
  }
}

我希望验证失败并显示类似 "You cannot create a Program in a different year as it's Category!"

的消息

到目前为止,我找不到基于另一个模型中的任何值进行验证的方法。 我该怎么做?

您可以使用 https://lighthouse-php.com/4.7/security/validation.html#validate-fields

进行自己的验证

感谢 Enzo Notario 的回答,我找到了解决方案。 如果其他人想了解更多关于如何可以(我相信这可以做得更漂亮)的详细信息,请编写您自己的验证,这是我的代码:

type Mutation {
    createProgram(input: CreateProgram! @spread): Program! @create @yearValidation
}

文件App/GraphQL/Directives/YearValidationDirective.php:

<?php

namespace App\GraphQL\Directives;

use App\Rules\SameYear;
use Illuminate\Support\Facades\DB;
use Nuwave\Lighthouse\Schema\Directives\ValidationDirective;

class YearValidationDirective extends ValidationDirective
{
    /**
     * List of all relations that should be checked for having the same year
     */
    private $relations = [
        'category' => true
    ];

    /**
     * Name of the directive.
     *
     * @return string
     */
    public function name(): string
    {
        return 'yearValidation';
    }

    /**
     * @return mixed[]
     */
    public function rules(): array
    {
        if (isset($this->args['year_id'])) {
            // year_id is given, get it
            $year_id = $this->args['year_id'];
        } else {
            // year_id not given, get it from the model
            $id = $this->args['id'];
            $fieldName = $this->resolveInfo->fieldName; // "updateTableName"
            $tableName = substr($fieldName, 6);
            $year_id= DB::table($tableName)->findOrFail($id)->year_id;
        }

        $relationFields = [];

        foreach($this->args as $field => $arg) {
            if (is_array($arg) && isset($this->relations[$field])) {
                $relationFields[$field] = [new SameYear($year_id)];
            }
        }

        return $relationFields;
    }
}

文件App/Rules/SameYear.php:

<?php

namespace App\Rules;

use Illuminate\Support\Facades\DB;
use Illuminate\Contracts\Validation\Rule;

class SameYear implements Rule
{
    protected $year_id;
    protected $found_year_id;
    protected $tableName;
    protected $connect;

    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct($year_id)
    {
        $this->year_id = $year_id;
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $this->connect = $value['connect'];
        $this->tableName = ucfirst($attribute);
        $this->found_year_id = DB::table($this->tableName)->find($this->connect)->year_id;
        return intval($this->found_year_id) === intval($this->year_id);
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return "Year_id's must be the same! $this->tableName (id: $this->connect) must have year_id: $this->year_id (found: $this->found_year_id)";
    }
}

这适合我。