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