Довольно часто, особенно в интернет-магазинах, вы можете увидеть страницу с формами входа или регистрации перед завершением покупки. Но в 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">
Видите разницу? Я тоже не вижу. За исключением автофокуса, который, в нашем случае, не имеет значения.
Вы можете подумать, что всё нормально, так как они отправляются данные на разные адреса и выполняют разные действия. Но, в случае неудачной проверки, вы получаете ошибки в обеих формах, а не в одной. Например, в случае неверных учетных данных при входе в систему, вы увидите это:
Как этого избежать?
В этом примере мы переименуем поля в регистрации, добавив к ним префикс «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">
Исходный метод 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.
Вот и всё! Теперь у нас есть две отдельные формы на странице оформления заказа.
В рамках этой статьи мы фактически создали типичный мини-проект процесса оформления заказа, который вы можете увидеть на Github. Домашняя страница содержит список продуктов, вы можете купить любой из них, а в сессии содержится ваша «корзина», которую вы можете оформить в любое время, нажав «Оформить заказ» наверху.
Мы не реализовали фактический процесс оплаты, но, думаю, это всё ещё полезный пример для Laravel юниоров. Наслаждайтесь!