我已经实施了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); ?>
答案 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'))
我想有很多方法可以解决这个问题。