Когда я делал многоступенчатые формы в прошлом, я обычно сохранял данные формы в сеансе, прежде чем возвращать его в представление, таким образом данные сохраняются, если пользователь обновляет страницу или нажимает на собственные обратные кнопки браузера.
Передавая мою прошлую логику в Laravel, я построил следующую форму, состоящую из трех этапов:
[Input -> Confirm -> Success]
Route::group(array('prefix' => 'account'), function(){ Route::get('register', array( 'before' => 'guest', 'as' => 'account-create', 'uses' => 'AccountController@getCreate' )); Route::post('register', array( 'before' => 'guest|csrf', 'as' => 'account-create-post', 'uses' => 'AccountController@postCreate' )); Route::get('register/confirm', array( 'before' => 'guest', 'as' => 'account-create-confirm', 'uses' => 'AccountController@getCreateConfirm' )); Route::post('register/confirm', array( 'before' => 'guest|csrf', 'as' => 'account-create-confirm-post', 'uses' => 'AccountController@postCreateConfirm' )); Route::get('register/complete', array( 'before' => 'guest', 'as' => 'account-create-complete', 'uses' => 'AccountController@getCreateComplete' )); });
<?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'); } }
<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>
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?
Когда я создал многочастные формы, я всегда делал это так, чтобы пользователь мог всегда возвращаться и заканчивать форму позже, делая каждую форму сохраняющейся в базе данных.
Например
Я хотел бы, чтобы пользователь создал свои данные аутентификации на этом шаге, создайте учетную запись пользователя (с паролем) здесь, а также зарегистрируйте пользователя, перенаправляя его на панель управления. Там я могу проверить, есть ли у пользователя профиль, а если нет, перенаправляйте его в форму создания профиля.
Поскольку у нас есть аутентифицированный пользователь, форма создания профиля может сохранять его данные для текущего пользователя. Последующие разделы следуют одному и тому же процессу, но проверяют наличие предыдущего шага.
Ваш вопрос, похоже, заключается в подтверждении того, хочет ли пользователь создать учетную запись. То, что я сделал бы в вашей ситуации, было бы в форме, которую вы создали для подтверждения учетной записи пользователя, я бы сохранил данные пользователей в скрытых полях ввода.
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>
затем отмените soft-delete, когда пользователь подтвердит свою учетную запись. У этого есть дополнительный бонус, который вы могли бы отслеживать людей, пытающихся зарегистрироваться несколько раз для учетной записи, а не завершения процесса и посмотреть, есть ли проблемы с вашим UX.
Конечно, вы также можете делать это так, как всегда, с сеансом, все, что я пытался сделать здесь, это показать вам некоторые другие способы, с помощью которых вы можете приблизиться к нему, как и все, что связано с лучшим способом сделать что-то, это является весьма упрямым субъектом и, вероятно, получит много противоположных взглядов на то, как это должно быть сделано. Лучший способ сделать это – это лучший способ для вас и ваших пользователей … в основном ваших пользователей.
Есть два способа сделать это (что я могу придумать). Я предпочитаю второй.
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()
? Если кто-то вернется, чтобы что-то изменить и случайно покинет ваш сайт, его данные будут потеряны.
1) Создайте собственное скрытое поле в форме, содержащей случайный набор символов md5, чтобы отправить его с формой … (это может быть метка времени, адрес пользователя и страна, объединенные вместе как 3 строки md5, разделенные любым символом, или #, поэтому он может работать как знак формы)
2-й) передайте скрытое поле в ваш контроллер и подтвердите его после ввода пользователя из формы, создав те же значения в вашем контроллере, зашифровав эти значения как md5, затем объедините их все вместе и сравните значения, которые поступают из пользовательская форма ввода со значениями, которые вы генерируете в контроллере.
3rd) Поместите значения формы в ваш контроллер в сеансе, а затем обновите идентификатор сеанса каждый визит до каждого просмотра, которое посетитель посетит.
4-е) обновить временную метку в вашем сеансе согласно временной отметке, которую пользователь посещает на каждой странице.
Просто потому, что вы знаете Ларавела, это не значит, что вы должны делать все в Ларавеле.
Многоступенчатые формы никогда не должны включать магию на стороне сервера. Самый лучший и самый простой способ – скрыть некоторые шаги с display:none;
и переключитесь на следующий шаг, используя только javascript.