Формы входа и регистрации на одной странице

Довольно часто, особенно в интернет-магазинах, вы можете увидеть страницу с формами входа или регистрации перед завершением покупки. Но в Laravel эти два маршрута ведут на отдельные страницы входа и регистрации. Как их объединить и избежать конфликта?

Обратите внимание: в конце этой статьи вы найдете ссылку на Github с простым проектом оформления заказа.

Это страница перед покупкой, к которой мы стремимся:

На первый взгляд, это довольно просто — скопировать/вставить весь код из /resources/views/auth/login.blade.php и /resources/views/auth/register.blade.php в один общий, скажем, /resources/views/checkout.blade.php. Так и есть, но это еще не всё.

Проблема возникнет из-за одинаковых имен полей.

Форма входа:

<input id="email" type="email"
       class="form-control @error('email') is-invalid @enderror" name="email"
       value="{{ old('email') }}" required autocomplete="email" autofocus>

Форма регистрации:

<input id="email" type="email"
       class="form-control @error('email') is-invalid @enderror" name="register_email"
       value="{{ old('email') }}" required autocomplete="email">

Видите разницу? Я тоже не вижу. За исключением автофокуса, который, в нашем случае, не имеет значения.

Вы можете подумать, что всё нормально, так как они отправляются данные на разные адреса и выполняют разные действия. Но, в случае неудачной проверки, вы получаете ошибки в обеих формах, а не в одной. Например, в случае неверных учетных данных при входе в систему, вы увидите это:

Как этого избежать?

 

Шаг 1. Переименуйте поля в одной из форм.

В этом примере мы переименуем поля в регистрации, добавив к ним префикс «register_»:

<input id="register_name" type="text"
       class="form-control @error('register_name') is-invalid @enderror" name="register_name"
       value="{{ old('register_name') }}" required autocomplete="name" autofocus>
@error('register_name')
    <span class="invalid-feedback" role="alert">
        <strong>{{ $message }}</strong>
    </span>
@enderror
...
<input id="register_email" type="email"
       class="form-control @error('register_email') is-invalid @enderror" name="register_email"
       value="{{ old('register_email') }}" required autocomplete="email">
@error('register_email')
    <span class="invalid-feedback" role="alert">
        <strong>{{ $message }}</strong>
    </span>
@enderror
...
<input id="register_password" type="password"
       class="form-control @error('register_password') is-invalid @enderror"
       name="register_password"
       required autocomplete="new-password">
@error('register_password')
    <span class="invalid-feedback" role="alert">
        <strong>{{ $message }}</strong>
    </span>
@enderror
...
<input id="password-confirm" type="password" class="form-control"
    name="register_password_confirmation" required autocomplete="new-password">

Шаг 2. Переопределите валидатор в RegisterController.

Исходный метод validator() из
/Http/Controllers/Auth/RegisterController.php, прямо из фреймворка:

protected function validator(array $data)
{
    return Validator::make($data, [
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => ['required', 'string', 'min:8', 'confirmed'],
    ]);
}

Итак, нам нужно переопределить этот валидатор своим собственным, добавив в него некоторые правила. Фактически нам просто нужно использовать переименованные поля из шага 1, а затем правильно назначить их имена. Вот код:

protected function validator(array $data)
{
    $validator = Validator::make($data, [
        'register_name' => ['required', 'string', 'max:255'],
        'register_email' => ['required', 'string', 'email', 'max:255', 'unique:users,email'],
        'register_password' => ['required', 'string', 'min:8', 'confirmed'],
    ]);
    $validator->setAttributeNames([
        'register_name' => 'name',
        'register_email' => 'email',
        'register_password' => 'password',
    ]);
    return $validator;
}

Как видите, теперь мы используем поля register_xxx вместо просто xxx, но нам также нужно убедиться, что они возвращают ошибки с их «оригинальными» именами, поэтому для этого мы используем не очень известный метод setAttributeNames(). Это официально не упоминается в документации, но вы можете увидеть пример его использования в этой теме на StackOverflow.

Вот и всё! Теперь у нас есть две отдельные формы на странице оформления заказа.

Бонус: Интернет-магазин Checkout Demo

В рамках этой статьи мы фактически создали типичный мини-проект процесса оформления заказа, который вы можете увидеть на Github. Домашняя страница содержит список продуктов, вы можете купить любой из них, а в сессии содержится ваша «корзина», которую вы можете оформить в любое время, нажав «Оформить заказ» наверху.

Мы не реализовали фактический процесс оплаты, но, думаю, это всё ещё полезный пример для Laravel юниоров. Наслаждайтесь!



Загрузка комментариев...