Сохранять данные формы через несколько шагов в Laravel
Когда я делал многоступенчатые формы в прошлом, я обычно сохранял данные формы в сеансе, прежде чем возвращать его в представление, таким образом данные сохраняются, если пользователь обновляет страницу или нажимает на кнопки обратной связи браузера.
Передача моей прошлой логики в Laravel Я построил следующую форму, состоящую из трех этапов:
[Input -> Confirm -> Success]
routes.php
Route::group(array('prefix' => 'account'), function(){
Route::get('register', array(
'before' => 'guest',
'as' => 'account-create',
'uses' => '[email protected]'
));
Route::post('register', array(
'before' => 'guest|csrf',
'as' => 'account-create-post',
'uses' => '[email protected]'
));
Route::get('register/confirm', array(
'before' => 'guest',
'as' => 'account-create-confirm',
'uses' => '[email protected]'
));
Route::post('register/confirm', array(
'before' => 'guest|csrf',
'as' => 'account-create-confirm-post',
'uses' => '[email protected]'
));
Route::get('register/complete', array(
'before' => 'guest',
'as' => 'account-create-complete',
'uses' => '[email protected]'
));
});
AccountController.php
<?php
class AccountController extends BaseController {
private $form_session = 'register_form';
public function getCreate()
{
if(Session::has($this->form_session))
{
// get forms session data
$data = Session::get($this->form_session);
// clear forms session data
Session::forget($this->form_session);
// load the form view /w the session data as input
return View::make('account.create')->with('input',$data);
}
return View::make('account.create');
}
public function postCreate()
{
// set the form input to the session
Session::set($this->form_session, Input::all());
$validation_rules = array(
'email' => 'required|max:50|email|unique:users',
'password' => 'required|max:60|min:6',
'password_conf' => 'required|max:60|same:password'
);
$validator = Validator::make(Input::all(), $validation_rules);
// get forms session data
$data = Session::get($this->form_session);
// Return back to form w/ validation errors & session data as input
if($validator->fails()) {
return Redirect::back()->withErrors($validator);
}
// redirect to the confirm step
return Redirect::route('account-create-confirm');
}
public function getCreateConfirm()
{
// prevent access without filling out step1
if(!Session::has($this->form_session)) {
return Redirect::route('account-create');
}
// get forms session data
$data = Session::get($this->form_session);
// retun the confirm view w/ session data as input
return View::make('account.create-confirm')->with('input', $data);
}
public function postCreateConfirm()
{
$data = Session::get($this->form_session);
// insert into DB
// send emails
// etc.
// clear forms session data
Session::forget($this->form_session);
// redirect to the complete/success step
return Redirect::route('account-create-complete');
}
public function getCreateComplete() {
return View::make('account.create-complete');
}
}
create.blade.php
<form action="{{ URL::route('account-create-post') }}" method="post">
Email: <input type="text" name="email" value="{{ (isset($input['email'])) ? e($input['email']) : '' }}">
@if($errors->has('email'))
{{ $errors->first('email') }}
@endif
<br />
Password: <input type="text" name="password" value="">
@if($errors->has('password'))
{{ $errors->first('password') }}
@endif
<br />
Password Confirm: <input type="text" name="password_conf" value="">
@if($errors->has('password_conf'))
{{ $errors->first('password_conf') }}
@endif
<br />
{{ Form::token() }}
<input type="submit" value="Confirm">
</form>
создать-confirm.blade.php
Email: {{ $input['email']; }}
Password: {{ $input['password']; }}
<form action="{{ URL::route('account-create-confirm-post') }}" method="post">
{{ Form::token() }}
<a href="{{ URL::previous() }}">return</a>
<input type="submit" name="submit_forward" value="Submit">
</form>
Вышеизложенное работает отлично, однако мне интересно, если это лучший способ подхода к многоэтапным формам в Laravel?
Ответы
Ответ 1
Когда я создавал многокомпонентные формы, я всегда делал это таким образом, чтобы пользователь всегда мог вернуться и закончить форму позже, заставляя каждую форму сохранять то, что она имеет в базе данных.
Например
Шаг 1 - Создание учетной записи
На этом шаге я хотел бы, чтобы пользователь создал свои данные для аутентификации, создал учетную запись пользователя (с паролем), а также вошел в систему, перенаправив на панель управления. Там я могу проверить, есть ли у пользователя профиль, и если нет, перенаправить его в форму создания профиля.
Шаг 2 - Создание профиля
Поскольку у нас есть аутентифицированный пользователь, форма создания профиля может сохранить свои данные для текущего вошедшего в систему пользователя. Последующие разделы следуют тому же процессу, но проверяют наличие предыдущего шага.
Похоже, ваш вопрос касается подтверждения того, хочет ли пользователь создать учетную запись. Что бы я сделал в вашей ситуации, в форме, которую вы создали для подтверждения учетной записи пользователя, я бы оставил данные пользователя в скрытых полях ввода.
Email: {{ $input['email'] }}
Password: {{ $input['password'] }}
<form action="{{ URL::route('account-create-confirm-post') }}" method="post">
<input type="hidden" name="email" value="{{ $input['email'] }}">
<input type="hidden" name="password" value="{{ $input['password'] }}">
{{ Form::token() }}
<a href="{{ URL::previous() }}">return</a>
<input type="submit" name="submit_forward" value="Submit">
</form>
Хотя отображение выбранного пользователем пароля обратно на этой странице кажется излишним, когда вы просите их подтвердить свой пароль на предыдущей странице, плюс некоторые пользователи могут задаться вопросом, почему их пароль отображается в виде открытого текста на экране, особенно если они получают доступ к сайту с общедоступного компьютера.
Третий вариант, который я бы предложил, это создать учетную запись пользователя и мягко удалить ее (Laravel 4.2 Docs/Laravel 5 Docs), вернув номер учетной записи пользователя в новую форму:
Email: {{ $input['email'] }}
Password: {{ $input['password'] }}
<form action="{{ URL::route('account-create-confirm-post') }}" method="post">
<input type="hidden" name="id" value="{{ $user_id }}">
{{ Form::token() }}
<a href="{{ URL::previous() }}">return</a>
<input type="submit" name="submit_forward" value="Submit">
</form>
затем отмените мягкое удаление, когда пользователь подтвердит свою учетную запись. Это дает дополнительный бонус, который вы можете отслеживать людей, пытающихся зарегистрировать несколько раз для учетной записи и не завершающих процесс, и посмотреть, если есть проблемы с вашим UX.
Заключение
Конечно, вы все равно можете делать это так, как вы всегда это делали во время сеанса, все, что я пытался сделать здесь, это показать вам некоторые другие способы, как вы можете подойти к нему, как со всем, что связано с лучшим способом сделать что-то, это это предмет с высокой степенью самоуверенности и, вероятно, получит много противоположных взглядов на то, как это должно быть сделано. Лучший способ сделать это - способ, который лучше всего работает для вас и ваших пользователей... в основном для ваших пользователей.
Ответ 2
Есть два способа сделать это (что я могу думать). Я предпочитаю второй.
- Клиентская сторона - все может обрабатываться javascript. Базовая проверка (если поле является адресом электронной почты, если поле имеет достаточно символов и т.д.), Будет проверяться с помощью javascript. После подтверждения запрос AJAX будет проходить проверку на стороне сервера, и если что-то пойдет не так, вы можете выделить недопустимые входы. "проверьте, доступна ли электронная почта" (через AJAX). Кроме того,
- Серверная сторона - в значительной степени то, что вы сделали, но я бы переместил ее на службу - это сделало бы ее намного чище.
public function getCreate() {
if ($this->formRememberService->hasData()) {
return View::make('account.create')
->with('input', $this->formRememberService->getData());
}
return View::make('account.create');
}
public function postCreate() {
$this->formRememberService->saveData(Input::all());
// ...
}
public function postCreateConfirm() {
// ...
$this->formRememberService->clear();
return Redirect::route('account-create-complete');
}
Добавление действия "забыть меня" было бы неплохо (особенно если форма требует больше личных данных).
Почему getCreate()
имеет Session::forget()
? Если кто-то вернется, чтобы что-то изменить и случайно покинет ваш сайт, его данные будут потеряны.
Ответ 3
1st) Создайте собственное скрытое поле в форме, содержащей случайный набор символов md5, чтобы отправить его с помощью формы... (это может быть метка времени, адрес пользователя и страна, объединенные вместе как 3 строки md5, разделенные любой символ или #, поэтому он может работать как знак формы)
2nd) передайте скрытое поле в ваш контроллер и подтвердите его после получения пользователем ввода из формы, создав те же значения в вашем контроллере, зашифровав эти значения как md5, затем объедините их все вместе и сравните значения, которые поступает из формы ввода пользователя со значениями, которые вы генерируете в контроллере.
3rd) Поместите значения формы в ваш контроллер в сеансе, а затем восстановите идентификатор сеанса каждый визит в каждое представление, которое посетитель посетит.
4th) обновите временную метку в своем сеансе согласно временной отметке, которую пользователь посещает на каждой странице.
Ответ 4
Просто потому, что вы знаете Laravel, не означает, что вы должны делать все в Laravel.
Многоступенчатые формы никогда не должны включать магию на стороне сервера. Самый лучший и простой способ - скрыть некоторые шаги с помощью display:none;
и перейти к следующему шагу, используя только видимость javascript.