在Laravel中跨多个步骤保持表单数据 [英] Persist Form Data Across Multiple Steps in Laravel

查看:113
本文介绍了在Laravel中跨多个步骤保持表单数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

过去我制作多步表单时,通常会在返回到视图之前将表单数据存储在会话中,这样,如果用户刷新页面或单击浏览器的本机后退按钮,该数据就会保留. /p>

将过去的逻辑转移给Laravel,我构建了以下形式,包括三个阶段:

[Input -> Confirm -> Success]

Routes.php

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'
    ));
});

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>

create-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-创建帐户

我将在此步骤中让用户创建其身份验证详细信息,在此处创建用户帐户(使用密码),并登录用户,重定向到仪表板.在那里,我可以检查用户是否有个人资料,如果没有,请将其重定向到个人资料创建表单.

第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 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是否存在问题.


结论

当然,您仍然可以像往常一样使用它,我在这里尝试做的就是向您展示其他方法,例如与最佳方法有关的一切做某事的方式,这是一个非常有主见的主题,并且在如何做方面可能会引起许多反对意见.最好的方法是最适合您和您的用户(主要是您的用户)的方法.

When I've made multistep forms in the past I would generally store the form data in the session before returning it to the view, that way the data persists if the user refreshes the page or clicks the browser's native back buttons.

Transferring my past logic to Laravel I built the following form consisting of three stages:

[Input -> Confirm -> Success]

Routes.php

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'
    ));
});

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>

create-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>

The above works fine, however I am wondering if this is the best way to approach multi-step forms in Laravel?

解决方案

When I have created multi-part forms, I have always done it in a way so that the user can always come back and finish the form later, by making each form persist what it has to the database.

For instance


Step 1 - Account Creation

I would have the user create their authentication details at this step, create the user account (with password) here and also log the user in, redirecting to the dashboard. There I can do a check to see if the user has a profile and if they don't, redirect them to the profile creation form.

Step 2 - Profile Creation

Because we have an authenticated user, the profile creation form can save its data to the currently logged in user. Subsequent sections follow the same process but check the existence of the previous step.


Your question seems to be about confirming whether a user wishes to create an account. What I would do in your situation would be, on the form you created to confirm the user account, I would keep the user's data in hidden input fields.

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>

Although displaying the user's chosen password back to them on this page seems to be a bit superfluous when you ask them to confirm their password on the previous page, plus some users might question why their password is being shown in plaintext on the screen, especially if they are accessing the site from a public computer.


The third option I would suggest would be to create the user account and soft-delete it (Laravel 4.2 Docs / Laravel 5 Docs), returning the user's account number to the new form:

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>

then undo the soft-delete when the user confirms their account. This has the added bonus that you could track people trying to sign up multiple times for an account and not completing the process and see if there's a problem with your UX.


Conclusion

Of course, you could also still do it the way you always have with a session, all I have tried to do here is show you some other ways you can approach it, as with everything to do with the best way of doing something, this is a highly opinionated subject and is likely to get many opposing views on how it should be done. The best way to do it is the way that works best for you and your users... mainly your users.

这篇关于在Laravel中跨多个步骤保持表单数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆