Laravel - Исключающая валидация полей в Request
Есть запрос такой структуры:
{
"anything": false,
"specifications": [
{
"nomenclature_id": null,
"nomenclature_name": "Деревянный камень",
"anything": true,
},
{
"nomenclature_id": 3, // !!!
"nomenclature_name": null,
"anything": true,
},
]
}
Нужно описать правила совместной валидации полей
specifications.*.nomenclature_id
specifications.*.nomenclature_name
таким образом, чтобы одно из них обязательно было null, а другое !== null, при этом:
если nomenclature_id !== null, то проверка на exists:nomenclatures,id
если nomenclature_name !== null, то проверка на string
Пробовал разные варианты с использованием правил типа required_if, exclude_if, sometimes etc. но нужного результата не добился. Понятно, что я могу не мудрить и убрать эту проверку в контроллер, описав её кодом, но ИМХО если что-то можно сделать встроенными средствами фреймворка, то нужно это делать средствами фреймворка.
PHP 8.2
Laravel 10
Ответы (3 шт):
Я решил вашу проблему. Я по своему реализовал получение данных в вашем формате ( немного садамаза ) Но это я для наглядности.
не важно что у меня там в view, ,будем считать что массив specifications пришел правильный как у вас.
public function form(Request $request) { $request['specifications'] = [ [ "nomenclature_id" => null, "nomenclature_name" => "Деревянный камень", "anything" => true, ], [ "nomenclature_id" => 3, "nomenclature_name" => null, "anything" => true, ] ]; $request->validate([ 'specifications.*' => [new TestNull()] ]); dd('validated success'); }
- Создаю Валидатор php artisan make:rule TestNull
Условия я сделал, так насколько я понял. (лучше поправить)
class TestNull implements ValidationRule
{
/**
* Run the validation rule.
*
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if(!is_null($value['nomenclature_id']) && is_null($value['nomenclature_name'])) {
$rules = ['nomenclature_id' => 'exists:posts,id'];
Validator::make($value, $rules)->passes();
}elseif (is_null($value['nomenclature_id']) && !is_null($value['nomenclature_name'])){
$rules = ['nomenclature_name' => 'string'];
Validator::make($value, $rules)->passes();
}
else {
$fail('The problems');
}
}
}
Используйте:
nullable
для полей, которые могут бытьnull
;required_if
для полей, которые должны быть обязательными, если другое поле имеет определенное значение.prohibited_unless
для полей, которые должны быть пустыми, если другое имеет значение отличое от указанного.
public function rules(): array
{
return [
'specifications.*.nomenclature_id' => 'nullable|required_if:specifications.*.nomenclature_name,null|prohibited_unless:specifications.*.nomenclature_name,null|exists:telegraph_bots,id',
'specifications.*.nomenclature_name' => 'nullable|required_if:specifications.*.nomenclature_id,null|prohibited_unless:specifications.*.nomenclature_id,null|string'
];
}
В вашем случае на примере поля specifications.*.nomenclature_id
required_if:specifications.*.nomenclature_name,null|prohibited_unless:specifications.*.nomenclature_name,null
Поле обязательное если поле specifications.*.nomenclature_name
отсутствует или пустое
Поле должно быть null
или отсутствовать если поле specifications.*.nomenclature_name
не null
Из озвученных вариантов я собрал рабочую компиляцию. Сперва создаём кастомное правило валидации:
php artisan make:rule Specifications/IdXorName
Rules/Specifications/IdXorName.php
<?php
// ...
class IdXorName implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail) : void
{
if(isset($value['nomenclature_id'], $value['nomenclature_name'])
|| (!isset($value['nomenclature_id']) && !isset($value['nomenclature_name']))) {
$fail('The ' . $attribute . ' must contain either a nomenclature_id or an nomenclature_name');
}
}
}
Http/Requests/SpecificationRequest.php:
<?php
// ...
use App\Rules\Specifications\IdXorName;
class SpecificationOfferRequest extends FormRequest
{
public function rules(): array
{
return [
// ...
'specifications.*' => new IdXorName,
'specifications.*. nomenclature_id' => 'nullable|exists: nomenclatures,id',
'specifications.*. nomenclature_name' => 'nullable|string|max:255',
// ...
];
}
}