触发CakePHP多步表单验证

时间:2015-08-22 13:56:10

标签: php validation cakephp

我已经实施了CakePHP multistep form。当用户点击“下一步”时,页面上的数据将被验证,保存,如果不是第一步/最后一步,则会与会话中的先前数据合并。除了下一步'以及之前的步骤'用户还可以使用导航栏在他们已经传递的步骤之间导航。

但是,只有点击下一步'才能触发数据保存和验证。例如,当步骤3中的用户点击“步骤1'”时,会出现问题。返回并更新数据,然后点击“第3步”'要返回,数据不会被修改。如何在点击导航链接时进行验证?

在控制器(PostController)中:

/**
 * this method is executed before starting the form and retrieves one important parameter:
 * the form steps number
 * you can hardcode it, but in this example we are getting it by counting the number of files that start with msf_step_
 */
public function msf_setup() {
    App::uses('Folder', 'Utility');
    $this->Session->delete('form');
    $usersViewFolder = new Folder(APP.'View'.DS.'Posts');
    $steps = count($usersViewFolder->find('msf_step_.*\.ctp'));
    $this->Session->write('form.params.steps', $steps);
    $this->Session->write('form.params.maxProgress', 0);
    $this->redirect(array('action' => 'msf_step', 1));
}

/**
 * this is the core step handling method
 * it gets passed the desired step number, performs some checks to prevent smart users skipping steps
 * checks fields validation, and when succeding, it saves the array in a session, merging with previous results
 * if we are at last step, data is saved
 * when no form data is submitted (not a POST request) it sets this->request->data to the values stored in session
 */
public function msf_step($stepNumber) {
    if (null == ($this->Session->read('form.params.steps'))) {
        $this->redirect(array('action' => 'msf_setup'));
    }       
    $this->set('stepNumber', $stepNumber);

    /**
     * check if a view file for this step exists, otherwise redirect to index
     */
    if (!file_exists(APP.'View'.DS.'Posts'.DS.'msf_step_'.$stepNumber.'.ctp')) {
        $this->redirect('/posts/msf_setup');
    }
    /**
     * determines the max allowed step (the last completed + 1)
     * if choosen step is not allowed (URL manually changed) the user gets redirected
     * otherwise we store the current step value in the session
     */
    $maxAllowed = $this->Session->read('form.params.maxProgress') + 1;
    if ($stepNumber > $maxAllowed) {
        $this->redirect('/posts/msf_step/'.$maxAllowed);
    } else {
        $this->Session->write('form.params.currentStep', $stepNumber);
    }

    /**
     * check if some data has been submitted via POST
     * if not, sets the current data to the session data, to automatically populate previously saved fields
     */
    if ($this->request->is('post')) {
        /**
         * if data validates we merge previous session data with submitted data, using CakePHP powerful Hash class (previously called Set)
         */
        if ($this->Post->saveAll($this->request->data, array('validate' => 'only', 'deep' => true))) {

            $prevSessionData = $this->Session->read('form.data');
            $currentSessionData = Hash::merge( (array) $prevSessionData, $this->request->data);

            /**
             * if this is not the last step we replace session data with the new merged array
             * update the max progress value and redirect to the next step
             */
            if ($stepNumber < $this->Session->read('form.params.steps')) {
                $this->Session->write('form.data', $currentSessionData);
                $this->Session->write('form.params.maxProgress', $stepNumber);
                $this->redirect(array('action' => 'msf_step', $stepNumber+1));

            } else {
                /**
                 * otherwise, this is the final step, so we have to save the data to the database
                 */

                if(AuthComponent::user('id')) {
                    $currentSessionData['Post']['email'] = AuthComponent::user('username');
                    $currentSessionData['Post']['user_id'] = AuthComponent::user('id');
                    unset($currentSessionData['User']); //Just in case a user is logged in after Step 1 that User data is already entered
                } else {
                    // We can save the User data:
                    // it should be in $this->request->data['User']
                    $currentSessionData['User']['group_id'] = '4';
                    $user = $this->Post->User->save($currentSessionData);

                    // The ID of the newly created user has been set
                    // as $this->User->id.
                    $currentSessionData['Post']['email'] = $currentSessionData['User']['username'];
                    $currentSessionData['Post']['user_id'] = $this->Post->User->id;
                    unset($currentSessionData['User']);
                }

                $this->Post->create();
                unset($this->Post->Student->validate['post_id']);
                if ($this->Post->saveAssociated($currentSessionData, array('deep' => true))) {
                    $this->Session->setFlash(__('The post has been saved.'), 'alert_box', array('class' => 'alert-success'));
                    //$this->Session->delete('form');
                    return $this->redirect(array('action' => 'index'));
                } else {
                    $this->Session->setFlash(__('The post could not be saved. Please, try again.'), 'alert_box', array('class' => 'alert-danger'));
                }                         
            }
        }
    } else {
        $this->request->data = $this->Session->read('form.data');
    }

    /**
     * here we load the proper view file, depending on the stepNumber variable passed via GET
     */
    $this->render('msf_step_'.$stepNumber);
}

在表单中,除了第一页和最后一页,上一步&#39;,导航和&#39;下一页&#39;如下:

//Previous Step
<?php echo $this->Html->link(__('Previous Step'),
    array('action' => 'msf_step', $params['currentStep'] -1),
    array('class' => 'btn btn-default')
); ?>

//navigation
<?php for ($i=1; $i <= $params['steps']; $i++) {
    if ($i > $params['maxProgress'] + 1) { ?>
        <a href="" class="btn btn-default" disabled><?php echo 'Step '.$i.''; ?></a>  
<?php } else {
    $class = ($i == $params['currentStep']) ? 'btn btn-default disabled' : 'btn btn-default';
    echo $this->Html->link('Step '. $i,
        array('action' => 'msf_step', $i),
        array('class' => $class)
        );
    }
} ?>

//Next Step
<?php $options = array(
    'label' => __('Next Step'),
    'class' => 'btn btn-default pull-right', 
    'div' => array(
        'class' => 'form-group'
    )
);
echo $this->Form->end($options); ?>

1 个答案:

答案 0 :(得分:1)

如果用户单击以直接转到步骤3,则表示您未验证数据,因为该请求不是发布请求。您只在发布请求时验证数据。

if ($this->request->is('post'))

为了将链接设为发布请求,您可以使用函数http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::postLink

它使用类似$this->Html->link的类似语法。但是在阅读文档时,在表单中使用此方法并不是一个好方法。你不能把按钮放在表格之外吗?

否则您可能需要查看if语句。

if ($this->request->is('post'))

我想有很多方法可以解决这个问题。