2015-08-22 50 views
0

我已經實現了一個CakePHP multistep form。當用戶點擊「下一步」時,頁面上的數據將被驗證並保存,如果不是第一步/最後一步,則與會話中的以前數據合併。除了「下一步」和「上一步」之外,用戶還可以使用導航欄在已經經過的步驟之間導航。觸發CakePHP多步表單驗證

但是,只有點擊'下一步'才能觸發數據保存和驗證。例如,當用戶在步驟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); 
} 

在表單中,除了第一個和最後一頁, '前一步驟',導航和 '下一個頁面' 如下:

//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); ?> 
+0

是的,這是我的問題的直接答案。你確實救了我兩次。不過,我想我的問題是有缺陷的。即使用戶只進入上一步,我也無法讓導航按鈕觸發每次點擊驗證。我需要以某種方式以其他方式觸發驗證,以便系統在每次更改以前的數據時發出通知。 –

回答

0

如果用戶點擊直接進入第3步,那麼您不驗證數據,因爲請求不是發佈請求。您僅在發佈請求時驗證數據。

​​

爲了使鏈接作爲POST請求,您可以使用該功能http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::postLink

它使用類似的語法像$this->Html->link。但是當閱讀文檔時,在表單中使用這種方法並不是一個好方法。你不能把按鈕放在窗體外面嗎?

否則,您可能需要檢查您的if語句。

​​

我想有很多方法可以解決這個問題。

+0

我陷在$ this-> Session中。我正在使用CakePHP 3.2,看起來Session對象現在與Auth有某種關聯,但$ this-> request-> session() - >讀/寫的直接替換對我來說不起作用:「錯誤:調用成員函數read()null「。 此外,函數名稱,如「msf_step」我已經重命名爲msfStep - 這似乎工作。 – rafz