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

时间:2019-12-29 12:53:19

标签: laravel validation graphql laravel-lighthouse

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

在这种情况下,Program有一个year_id,而Category也有一个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
}

现在,如果我使用Category创建一个year_id: 1(返回类别ID = 1):

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

然后尝试使用与新Program相关的year_id: 2创建一个Category

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

我希望验证,因此失败,并显示如下消息:“您不能在不同年份创建程序,因为它是类别!”

到目前为止,我还找不到一种基于其他模型中任何值进行验证的方法。 我该怎么办?

2 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

多亏了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)";
    }
}

这为我完成了工作。