假设有两个 Laravel API 资源
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
方法必须返回一个布尔值(即我们应该为每个属性重写所有验证逻辑)。
有什么优雅/官方的方法可以做到这一点吗?
如果您想在多个地方使用相同的验证规则,也许可以使用一个特征,然后在多个表单请求中使用它。所以对于书籍规则:
<?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',
...
]
);
}
}
我还没有测试过这个,但看起来可行。
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
);
}
}
就您的情况而言,我看到了解决此问题的一种方法,但我也想演示一个示例,当您需要验证一个实体(例如,一本书)时,该示例可以在更简单的情况下提供帮助:
通过 DI 使用 BookRequest:
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...'
];
}
}