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',
...
]
);
}
}
Я не тестировал это, но похоже, что это может сработать.