Laravel 6 - лучший способ повторно использовать существующие валидаторы запросов в других валидаторах запросов

Допустим, есть два ресурса API Laravel Book а также Author, каждый с некоторыми правилами для проверки store запрос.

Затем есть третий ресурс API, где потребители API могут публиковать определенную вещь вместе с Book и Author. То естьstore запрос должен принять Book объект, Author объект, а третий FooBar объект:

// sample POST body
{
  "book": {...book object...},
  "author": {...author object...},
  "foobar": {...foobar object...}
}

в FooBarRequest Проверка rules(), имеет смысл повторно использовать BookRequest::rules() а также AuthorRequest::rules(), но это не работает:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class FooBarRequest extends FormRequest
{
    public function rules()
    {
        $bookRules = BookRequest::$validationRules;
        $authorRules = AuthorRequest::$validationRules;

        return [
            'book' => $bookRules,
            'authorRules' => $authorRules,
            'foobar' => 'required|...some rules...'
        ];
    }
}

Возможно, используя собственные правила Laravel, но это не так сильно помогает, посколькуpasses метод должен возвращать логическое значение (т.е. мы должны переписать всю логику проверки для каждого атрибута).

Есть ли какой-нибудь элегантный / официальный способ сделать это?

3 ответа

В вашем случае я вижу один способ решения этой проблемы, но также я хотел бы продемонстрировать пример, который может помочь в более простых случаях, когда вам нужно проверить только одну сущность, например, книгу:

Используйте BookRequest через DI:

      class FooBarRequest extends FormRequest
{
    public function rules(BookRequest $request)
    {
        return [
            'foobar' => 'required|...some rules...'
        ];
    }
}

Конкретно для вашего случая советую воспользоваться правилами . Вы можете использовать их в FooBarRequest, а также повторно использовать в других классах FormRequest:

      class FooBarRequest extends FormRequest
{
    public function rules()
    {
        return [
            'book' => [new BookValidationRule()],
            'authorRules' => [new AuthorValidationRule()],
            'foobar' => 'required|...some rules...'
        ];
    }
}

bookа также titleАтрибуты подпадают под действие правил проверки ввода вложенных массивов .

Например, если у вас есть:

      $bookRules = ['title' => 'required', 'body' => 'text'];
$authorRules = ['name' => 'required'];

Вы хотите, чтобы правила были такими:

      [
    'book.title' => 'required',
    'book.body' => 'text',
    'author.name' => 'required',
    'foobar' => 'required|...some rules...',
];

Предполагая BookRequest::$validationRulesа также AuthorRequest::$validationRulesуже вернуть то, что вы хотите, вам нужно сделать следующее, чтобы добраться туда:

      <?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class FooBarRequest extends FormRequest
{
    public function rules()
    {
        $bookRules = BookRequest::$validationRules;
        $authorRules = AuthorRequest::$validationRules;

        return array_merge(
            $this->getNestedArrayRules($bookRules, 'book'),
            $this->getNestedArrayRules($authorRules, 'author'),
            ['foobar' => 'required|...some rules...']
        );
    }

    protected function getNestedArrayRules($rules, $key) {
        return array_combine(
            array_map(fn ($attribute) =>  "$key.$attribute", array_keys($rules)), 
            $rules
        );
    }
}

Посмотрите этот ответ на Ларакасты:

Если вы хотите использовать одни и те же правила проверки в нескольких местах, возможно, используйте признак, а затем используйте его в нескольких запросах формы. Итак, для правил книги:

<?php

namespace App\Traits;

trait BookValidationTrait
{
    protected function bookRules ()
    {
        return [
            'book_input_1' => 'your rules here',
            'book_input_2' => 'your rules here',
            ...
        ]
    }
}

Тогда для авторских правил:

<?php

namespace App\Traits;

trait AuthorValidationTrait
{
    protected function authorRules ()
    {
        return [
            'author_input_1' => 'your rules here',
            'author_input_2' => 'your rules here',
            ...
        ]
    }
}

Затем в классе запроса формы вашей книги:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Traits\BookValidationTrait;

class BookRequest extends FormRequest
{
    use BookValidationTrait;

    public function rules()
    {
        return $this->bookRules();
    }
}

В вашем классе запроса формы автора:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Traits\AuthorValidationTrait;

class AuthorRequest extends FormRequest
{
    use AuthorValidationTrait;

    public function rules()
    {
        return $this->authorRules();
    }
}

И, наконец, в классе запроса формы FooBar:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use App\Traits\BookValidationTrait;
use App\Traits\AuthorValidationTrait;

class FooBarRequest extends FormRequest
{
    use BookValidationTrait, AuthorValidationTrait;

    public function rules()
    {
        return array_merge(
            $this->bookRules(),
            $this->authorRules(),
            [
                'foobar_input_1' => 'your rules here',
                'foobar_input_2' => 'your rules here',
                ...
            ]
        );
    }
}

Я не тестировал это, но похоже, что это может сработать.

Другие вопросы по тегам