delphinpro
@delphinpro
frontend developer

Как валидировать обязательно-необязательное поле и вернуть предыдущее значение в форму?

Есть такая таблица

Schema::create('roles', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('slug')->unique();
    $table->string('description')->nullable();
});


name – обязательное
slug – необязательное на фронте, но должно быть заполнено при сохранении модели

Форма выглядит так
6389ad179aa95822532516.png


Создан реквест и обработка ввода перед валидацией

class StoreRequest extends FormRequest {
    public function rules(): array {
        return [
            'role.name' => 'required',
            'role.slug' => ['required', Rule::unique(Role::class, 'slug')],
            'role.description' => 'string|max:255|nullable',
        ];
    }
    protected function prepareForValidation() {
        if (!$this->input('role.slug')) {
            $role = $this->input('role');
            Arr::set($role, 'slug', Str::slug($this->input('role.name')));
            $this->merge([
                'role' => $role,
            ]);
        }
    }
}


Технически всё работает, но есть вопросы.

Первый вопрос.

Имена полей в форме имеют вид name="role[name]", name="role[slug]", то есть на бэк прилетают в виде массива roles в реквесте.
Есть ли какой-то более красивый способ объединения входных данных в prepareForValidation, без вытаскивания массива, его изменения и мержа? То есть напрямую изменить одно поле в массиве входящих данных?
Что-то типа такого:
$this->merge([
    'role.slug' => Str::slug($this->input('role.name')),
]);

Дот-нотация, увы, не работает, создаётся новый ключ
[
  '_token' => '',
  'role' => [
    'name' => '',
    'slug' => '',
  ]
  'role.slug' => '',
]


Второй вопрос.

Мы изменили входящие данные, и, допустим, не сработало правило уникальности на slug.
Получаем на фронте следующее:

6389aee74d323589335434.png

То есть в old('role.slug') отсутствует то значение, которое мы вставили в prepareForValidation

Как его туда прокинуть?
  • Вопрос задан
  • 137 просмотров
Решения вопроса 1
iMedved2009
@iMedved2009
Не люблю людей
То есть напрямую изменить одно поле в массиве входящих данных?

есть решение в какой нибудь сервис провайдер запихнуть макрос ибо реквест у нас macroable, аля

Illuminate\Http\Request::macro(
    'mergeGently', function($array){
// где делаем магию аля проверки и прочее.
});

после чего будет работать $request->mergeGently($array);

Как его туда прокинуть?

app/Exceptions/Handler.php
public function register()
    {
        $this->renderable(function (ValidationException $exception) {
            return redirect($exception->redirectTo ?? url()->previous())
                ->withInput(Arr::except($exception->validator->getData(), $this->dontFlash))
                ->withErrors($exception->errors(), $exception->errorBag);
        });
    }

В принципе после этой правки все эксепшены с валидацией будут содержать ваши merge из prepareForValidation и не надо дублировать merge. Но стоит проверить как это будет реагировать на json запросы. мне лень

З.Ы. Чего то сообразил - можно же легче - просто переопределить метод invalid у app/Exceptions/Handler.php
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Fragster
@Fragster
помогло? отметь решением!
Ничего во входящих данных не надо менять, надо просто почитать вот это: https://laravel.com/docs/8.x/validation#validating... и тогда волшебным образом всё сильно упростится
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы