题
我正在尝试使用YII构建一个多页面,但是对PHP和YII来说是新的,并且想知道编写多页面的最佳实践是什么。到目前为止,我打算做的是添加一个名为“步骤”的隐藏字段,该字段包含用户在表单中打开的当前步骤(该表单已分为3个步骤/页面)。因此,考虑到这一点,这就是我计划处理用户单击控制器中的上一个/下一个按钮的方式:
public function actionCreate()
{
$userModel = new User;
$data['activityModel'] = $activityModel;
$data['userModel'] = $userModel;
if (!empty($_POST['step']))
{
switch $_POST['step']:
case '1':
$this->render('create_step1', $data);
break;
case '2':
$this->render('create_step2', $data);
break;
}else
{
$this->render('create_step1', $data);
}
}
这种方法有意义吗?还是我远离基地,在YII/PHP中有一种更好,更优化的方法?
谢谢!
解决方案
有几种方法可以解决这个问题。我看到您在YII论坛上发布了发布,所以我假设您也在那里搜索过,但是以防万一您没有:
- http://www.yiiframework.com/forum/index.php?/topic/6203-stateful-forms-and-wizards-howto/
- http://www.yiiframework.com/forum/index.php?/topic/8413-wizard-forms/
我所做的是(仅适用于简单的2步activerecord表单)采取了一个动作,并根据按钮名称将其分为条件块,yii在表单上发布了该措施(注意:不使用Ajax,可以使用Ajax提交)。然后,根据按下哪个按钮,请呈现正确的表单,并在验证目的上设置正确的模型方案。
像您所拥有的隐藏的“步骤”字段可以与检查提交屁股名称相同的目的。我也许会将“步骤”保存到表单状态中,而不是添加一个隐藏的字段,但要么可以。
有些人使用状态ActiveForm属性从向导中的单个步骤中保存数据,或者您可以使用会话,甚至可以保存到TEMP数据库表。在下面我完全未经测试的示例中,我使用的是状态形式功能。
这是我基本上为ActivereCord表格所做的示例。这是在“ Action Create”中进行的:
<?php if (isset($_POST['cancel'])) {
$this->redirect(array('home'));
} elseif (isset($_POST['step2'])) {
$this->setPageState('step1',$_POST['Model']); // save step1 into form state
$model=new Model('step1');
$model->attributes = $_POST['Model'];
if($model->validate())
$this->render('form2',array('model'=>$model));
else {
$this->render('form1',array('model'=>$model));
}
} elseif (isset($_POST['finish'])) {
$model=new Model('finish');
$model->attributes = $this->getPageState('step1',array()); //get the info from step 1
$model->attributes = $_POST['Model']; // then the info from step2
if ($model->save())
$this->redirect(array('home'));
else {
$this->render('form2',array('model'=>$model));
} else { // this is the default, first time (step1)
$model=new Model('new');
$this->render('form1',array('model'=>$model));
} ?>
表格看起来像这样:
form1:
<?php $form=$this->beginWidget('CActiveForm', array(
'enableAjaxValidation'=>false,
'id'=>'model-form',
'stateful'=>true,
));
<!-- form1 fields go here -->
echo CHtml::submitButton("Cancel",array('name'=>'cancel');
echo CHtml::submitButton("On to Step 2 >",array('name'=>'step2');
$this->endWidget(); ?>
表2:
<?php $form=$this->beginWidget('CActiveForm', array(
'enableAjaxValidation'=>false,
'id'=>'model-form',
'stateful'=>true,
));
<!-- form2 fields go here -->
echo CHtml::submitButton("Back to Step 1",array('name'=>'step1');
echo CHtml::submitButton("Finish",array('name'=>'finish');
$this->endWidget(); ?>
我希望这很有帮助!
其他提示
YII提供了一个称为页面状态的功能,以实现多步 /多页面向导之类的功能。
让我们先看一下YII文档:
页面状态是一个变量,在同一页面的POST请求中持续存在。为了使用持久的页面状态,必须使用{@link chtml :: statefulform}生成的状态形式。
因此,每个步骤 /页面的形式都需要是状态形式。要渲染一种状态表格,您只需要设置 CActiveForm::stateful
财产为 true
当您启动ActiveForm-Widget时。在您的控制器中,您可以获取并设置您的页面状态 CController::getPageState()
或者 CController::setPageState()
.
因此,如果您的多页面向导以传统风格实施而没有AJAX请求,那么这些基础知识就可以很好地工作。
但是,如果您想使用AJAX调用来提交步骤数据并显示下一步,则YII的页面状态不可用。
为什么?所有页面状态均在隐藏的输入字段中通过HTTP-POST运输。在所谓的输出处理时,输入字段被YII填充。输出处理开始 后 渲染并将替换输出部分。所以 YII的页面状态功能需要输出处理. 。另一方面,AJAX的响应可能会因其破坏,因为输出处理也可能添加 <link>
或者 <script>
输出开头的标签加载所需的JS和CSS文件。
最后,我实施了自己的状态形式。我能够通过静态功能调用获得我的状态数据 ActiveFormWidget::getRequestMultiStepData()
每次我需要它。
注意:我的实施中有一个缺点:在初始化窗口小部件的表格之前,需要收集所有状态数据。但是直到现在我从来没有遇到过问题。但是,这是代码:
class ActiveFormWidget extends CActiveForm
{
public static $inputNameMultiStepData = '_multiStepData';
public $multiStep = false;
public $multiStepData = array();
public function init()
{
parent::init();
# Hidden-Fields
if ($this->multiStep) {
echo Html::hiddenField(static::$inputNameMultiStepData, static::encodeInputData($this->multiStepData));
}
}
/**
* Gets all multi step data sent.
* @return array|mixed
*/
public static function getRequestMultiStepData()
{
return isset($_REQUEST[static::$inputNameMultiStepData]) ? static::decodeInputData($_REQUEST[static::$inputNameMultiStepData]) : array();
}
/**
* Encodes form data like Yii does for stateful forms.
* @param $data
* @return string
*/
public static function encodeInputData($data)
{
$data = Yii::app()->getSecurityManager()->hashData(serialize($data));
return base64_encode($data);
}
/**
* Decodes form data like Yii does for stateful forms.
* @param $data
* @return bool|mixed
*/
public static function decodeInputData($data)
{
$data = base64_decode($data);
$data = Yii::app()->getSecurityManager()->validateData($data);
if ($data !== false) {
return unserialize($data);
} else {
return false;
}
}
}