本文目录导读:

在 Laravel 中处理数组验证和嵌套数据是非常常见的需求,让我详细介绍各种验证技巧和最佳实践。
基础数组验证
简单数组验证
$request->validate([
'tags' => 'required|array',
'tags.*' => 'required|string|max:50',
]);
数组长度验证
$request->validate([
'items' => 'required|array|min:1|max:10',
]);
嵌套数组验证
多维数组验证
$request->validate([
'users' => 'required|array',
'users.*.name' => 'required|string|max:255',
'users.*.email' => 'required|email|unique:users,email',
'users.*.age' => 'required|integer|min:18',
'users.*.addresses' => 'sometimes|array',
'users.*.addresses.*.city' => 'required_with:users.*.addresses|string',
'users.*.addresses.*.zip' => 'required_with:users.*.addresses|digits:5',
]);
使用 FormRequest 类
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreOrderRequest extends FormRequest
{
public function rules(): array
{
return [
'customer' => 'required|array',
'customer.name' => 'required|string|max:255',
'customer.email' => 'required|email',
'items' => 'required|array|min:1',
'items.*.product_id' => 'required|exists:products,id',
'items.*.quantity' => 'required|integer|min:1|max:99',
'items.*.size' => 'nullable|in:S,M,L,XL',
'items.*.extras' => 'array',
'items.*.extras.*' => 'string|max:50',
];
}
public function messages(): array
{
return [
'items.*.quantity.min' => '每个商品至少需要订购1件',
'items.*.product_id.exists' => '商品不存在',
];
}
}
数组嵌套验证的高级技巧
条件验证
$request->validate([
'products' => 'array',
'products.*.type' => 'required|in:physical,digital',
// 物理商品需要重量
'products.*.weight' => 'required_if:products.*.type,physical|numeric|min:0.1',
// 数字商品需要下载链接
'products.*.download_url' => 'required_if:products.*.type,digital|url',
]);
自定义验证规则
Validator::make($request->all(), [
'selections' => [
'required',
'array',
function ($attribute, $value, $fail) {
// 检查数组中对值
if (count($value) !== count(array_unique($value))) {
$fail('选择项不能重复。');
}
},
],
]);
数组项之间验证
public function rules(): array
{
return [
'items' => 'required|array|min:2',
'items.*.quantity' => 'required|integer|min:1',
];
}
public function withValidator($validator): void
{
$validator->after(function ($validator) {
$items = $this->input('items');
// 检查总数量不超过库存
$totalQuantity = array_sum(array_column($items, 'quantity'));
if ($totalQuantity > 100) {
$validator->errors()->add('items', '总数量不能超过100件。');
}
});
}
数据准备与验证前处理
使用 prepareForValidation
class UpdateProfileRequest extends FormRequest
{
protected function prepareForValidation(): void
{
$this->merge([
'interests' => is_string($this->interests)
? explode(',', $this->interests)
: $this->interests,
'settings' => [
'notifications' => $this->boolean('notifications'),
'theme' => $this->input('theme', 'light'),
],
]);
}
}
验证嵌套数组的常用场景
JSON 数据验证
$request->validate([
'data' => 'required|json',
]);
// 验证 JSON 解码后的数据
$data = json_decode($request->input('data'), true);
$validator = Validator::make($data, [
'items' => 'required|array',
'items.*.name' => 'required|string',
'items.*.price' => 'required|numeric|min:0',
]);
动态字段验证
public function rules(): array
{
$rules = [
'type' => 'required|in:appointment,order,custom',
'fields' => 'required|array',
];
// 根据类型动态添加规则
if ($this->input('type') === 'appointment') {
$rules['fields.date'] = 'required|date|after:today';
$rules['fields.time'] = 'required|date_format:H:i';
$rules['fields.doctor'] = 'required|exists:doctors,id';
}
return $rules;
}
FormRequest 中的复杂验证示例
namespace App\Http\Requests;
class ProcessSurveyRequest extends FormRequest
{
public function rules(): array
{
return [
'survey_id' => 'required|exists:surveys,id',
'respondent' => 'required|array',
'respondent.age_group' => 'required|in:18-25,26-35,36-50,50+',
'respondent.gender' => 'nullable|in:male,female,other',
'answers' => 'required|array|min:1',
'answers.*.question_id' => 'required|distinct|exists:questions,id',
'answers.*.answer' => 'required_without:answers.*.answer_text',
'answers.*.answer_text' => 'required_without:answers.*.answer',
'answers.*.rating' => 'nullable|integer|between:1,5',
'optional_questions' => 'sometimes|array',
'optional_questions.*' => 'nullable|string|max:500',
];
}
public function withValidator($validator): void
{
$validator->after(function ($validator) {
// 检查是否回答了所有必答题
$survey = \App\Models\Survey::find($this->survey_id);
$requiredQuestions = $survey->questions()->where('required', true)->pluck('id')->toArray();
$answeredQuestions = array_column($this->answers, 'question_id');
$missingQuestions = array_diff($requiredQuestions, $answeredQuestions);
if (!empty($missingQuestions)) {
$validator->errors()->add(
'answers',
'请回答所有必答题: ' . implode(', ', $missingQuestions)
);
}
});
}
public function messages(): array
{
return [
'answers.*.distinct' => '每个问题只能回答一次',
'answers.*.rating.between' => '评分必须在1-5之间',
];
}
}
验证后的数据提取
// 在控制器中
public function store(Request $request)
{
$validated = $request->validate([...]);
// 提取部分数据
$userData = $request->safe()->only(['name', 'email']);
$arrayData = $request->safe()->only(['items', 'tags']);
// 排除某些字段
$data = $request->safe()->except(['items', 'tags']);
}
使用自定义规则类
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class ValidItemCombination implements Rule
{
public function passes($attribute, $value)
{
// $value 是数组
$categories = array_column($value, 'category');
$names = array_column($value, 'name');
// 检查组合是否唯一
$combinations = array_map(function($cat, $name) {
return $cat . '-' . $name;
}, $categories, $names);
return count($combinations) === count(array_unique($combinations));
}
public function message()
{
return '每个商品组合必须唯一。';
}
}
// 使用
$request->validate([
'items' => ['required', 'array', new ValidItemCombination],
]);
性能优化建议
// 避免过多嵌套层级 'items.*.details.specifications.technical.description' => 'required'; // 太深了 // 应该扁平化或拆分 'items.*.description' => 'required';
常见陷阱和解决方案
处理可选数组
// 错误方式(可能导致 null)
$request->validate([
'tags.*' => 'string',
]);
// 正确方式
$request->validate([
'tags' => 'sometimes|array',
'tags.*' => 'string',
]);
数组索引连续性
$validator = Validator::make($request->all(), [
'items' => 'required|array',
'items.*' => 'required',
]);
// 检查索引是否连续
$validator->after(function ($validator) {
$items = $this->input('items');
$keys = array_keys($items);
if ($keys !== range(0, count($items) - 1)) {
// 可以重新索引
$reindexed = array_values($items);
$this->merge(['items' => $reindexed]);
}
});
这些技巧可以帮助你处理几乎所有 Laravel 数组验证场景,关键是要根据项目实际需求选择合适的验证策略,并充分利用 Laravel 提供的验证功能。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播