属性,这样,相应场景的验证规则就会被应用。 验证是基于场景执行的。 scenario 属性指定了模型当前用于的场景和当前使用的验证规则集。例如,在 login 场景中, 我们只想验证用户模型中的 username 和 password 输入;而在 register 场景中,我们需要验证更多的输入,例如 email, address, 等。下面的例子演示了如何在 register 场景中执行验证: // 在注册场景中创建一个 User 模型。等价于: //$model=new User; //$model->scenario='register'; $model=newUser('register'); //给模型类添加参数,该参数就是要触发的验证场景 // 将输入的值填充到模型 $model->attributes=$_POST['User']; // 执行验证 if($model->validate()) // 如果输入有效 ... else ... 规则关联的场景可以通过规则中的 on 选项指定。如果 on 选项未设置,则此规则会应用于所有场景。例如: public functionrules() { returnarray( array('username, password', 'required'), array('password_repeat', 'required', 'on'=>'register'), array('password', 'compare', 'on'=>'register'), );
} 第一个规则将应用于所有场景,而第二个将只会应用于 register 场景。
5 5 5 5、提取验证错误
验证 完成后 ,任何可 能产生 的错误将 被存储 在模型对 象中。 我们可以 通过调 用 CModel::getErrors() 和 CModel::getError() 提取这些错误信息。这两个方法的不同点在于第一个方法将返回 所有 模型特性的错误信息,而 第二个将只返回 第一个 错误信息。
6 6 6 6、特性标签
当设计表单时,我们通常需要为每个表单域显示一个标签。标签告诉用户他应该在此表单域中填写什么样的信息。虽 然我们可以在视图中硬编码一个标签,但如果我们在相应的模型中指定(标签),则会更加灵活方便。 默认情况下 CModel 将简单的返回特性的名字作为其标签。这可以通过覆盖 attributeLabels() 方法自定义。正如在接 下来的小节中我们将看到的,在模型中指定标签会使我们能够更快的创建出更强大的表单。
二、创建动作 二、创建动作 二、创建动作 二、创建动作
有了模型,我们就可以开始编写用于操作此模型的逻辑了。我们将此逻辑放在一个控制器的动作中。对登录表单的例 子来讲,相应的代码就是: public functionactionLogin() { $model=new LoginForm; if(isset($_POST['LoginForm'])) { // 收集用户输入的数据 $model->attributes=$_POST['LoginForm']; // 验证用户输入,并在判断输入正确后重定向到前一页 if($model->validate()) $this->redirect(Yii::app()->user->returnUrl); //重定向到之前需要身份验证的页面 URL } // 显示登录表单 $this->render('login',array('model'=>$model)); }
如上所示,我们首先创建了一个 LoginForm 模型示例;如果请求是一个 POST 请求(意味着这个登录表单被提交了)
, 我们则使用提交的数据 $_POST['LoginForm'] 填充 $model ;然后我们验证此输入,如果验证成功,重定向用户浏览 器到之前需要身份验证的页面。如果验证失败,或者此动作被初次访问,我们则渲染 login 视图,此视图的内容我们 在下一节中讲解。 提示: 在 login 动作中,我们使用 Yii::app()->user->returnUrl 获取之前需要身份验证的页面 URL。 组件 Yii::app()->user 是一种 CWebUser (或其子类) ,它表示用户会话信息(例如 用户名,状态) 。 让我们特别留意一下 login 动作中出现的下面的 PHP 语句: $model->attributes=$_POST['LoginForm']; 正如我们在 安全的特性赋值 中所讲的,这行代码使用用户提交的数据填充模型。 attributes 属性由 CModel 定义, 它接受一个名值对数组并将其中的每个值赋给相应的模型特性。因此如果 $_POST['LoginForm'] 给了我们这样的一个 数组,上面的那段代码也就等同于下面冗长的这段 (假设数组中存在所有所需的特性): $model->username=$_POST['LoginForm']['username'];
$model->password=$_POST['LoginForm']['password']; $model->rememberMe=$_POST['LoginForm']['rememberMe']; 注意: 为了使 $_POST['LoginForm'] 传递给我们的是一个数组而不是字符串, 我们需要在命名表单域时遵守一个规 范。具体的,对应于模型类 C 中的特性 a 的表单域,我们将其命名为 C[a] 。例如,我们可使用 LoginForm[username] 命名 username 特性相应的表单域。 现在剩下的工作就是创建 login 视图了,它应该包含一个带有所需输入项的 HTML 表单。
三、创建表单 三、创建表单 三、创建表单 三、创建表单
编写 login 视图是很简单的,我们以一个 form 标记开始,它的 action 属性应该是前面讲述的 login 动作的 URL。然 后我们需要为 LoginForm 类中声明的属性插入标签和表单域。最后,我们插入一个可由用户点击提交此表单的提交按 钮。所有这些都可以用纯 HTML 代码完成。 Yii 提供了几个助手(helper)类简化视图编写。例如,要创建一个文本输入域,我们可以调用 CHtml::textField();要 创建一个下拉列表,则调用 CHtml::dropDownList()。 例如, 如下代码将生成一个文本输入域,它可以在用户修改了其值时触发表单提交动作。 CHtml::textField($name,$value,array('submit'=>'')); 下面,我们使用 CHtml 创建一个登录表单。我们假设变量 $model 是 LoginForm 的实例。 <div class="form"> <?phpecho CHtml::beginForm();?>
<?php echo CHtml::errorSummary($model); ?>
<divclass="row"> <?php echoCHtml::activeLabel($model,'username'); ?> <?php echoCHtml::activeTextField($model,'username')?> </div>
<divclass="row"> <?php echoCHtml::activeLabel($model,'password'); ?> <?php echoCHtml::activePasswordField($model,'password') ?> </div>
<divclass="row rememberMe"> <?php echoCHtml::activeCheckBox($model,'rememberMe'); ?> <?php echoCHtml::activeLabel($model,'rememberMe'); ?> </div>
<divclass="row submit"> <?php echoCHtml::submitButton('Login'); ?> </div>
<?phpecho CHtml::endForm();?> </div><!-- form -->
上述代码生成了一个更加动态的表单,例如, CHtml::activeLabel() 生成一个与指定模型的特性相关的标签。如果此特 性 有一 个输 入 错误 ,此 标签 的 CSS class 将 变为 error, 通过 CSS 样 式改 变了 标 签的 外观 。相 似 的, CHtml::activeTextField() 为指定模型的特性生成一个文本输入域,并会在错误发生时改变它的 CSS class。 我们还可以使用一个新的小物件 CActiveForm 以简化表单创建。这个小物件可同时提供客户端及服务器端无缝的、
一致的验证。使用 CActiveForm, 上面的代码可重写为: <div class="form"> <?php$form=$this->beginWidget('CActiveForm'); ?>
<?php echo $form->errorSummary($model); ?>
<divclass="row"> <?php echo$form->label($model,'username'); ?> <?php echo$form->textField($model,'username') ?> </div>
<divclass="row"> <?php echo$form->label($model,'password'); ?> <?php echo$form->passwordField($model,'password') ?> </div>
<divclass="row rememberMe"> <?php echo$form->checkBox($model,'rememberMe');?> <?php echo$form->label($model,'rememberMe');?> </div>
<divclass="row submit"> <?php echoCHtml::submitButton('Login'); ?> </div>
<?php$this->endWidget(); ?> </div><!-- form -->
四、收集表格输入 四、收集表格输入 四、收集表格输入 四、收集表格输入
有时我们想通过批量模式收集用户输入。也就是说,用户可以为多个模型实例输入信息并将它们一次性提交。我们将 此称为 表格输入(tabular input) ,因为这些输入项通常以 HTML 表格的形式呈现。 要使用表格输入,我们首先需要创建或填充一个模型实例数组,取决于我们是想插入还是更新数据。然后我们从 $_POST 变量中提取用户输入的数据并将其赋值到每个模型。和单模型输入稍有不同的一点就是:我们要使用 $_POST['ModelClass'][$i] 提取输入的数据而不是使用 $_POST['ModelClass']。 public functionactionBatchUpdate() { // 假设每一项(item)是一个 'Item' 类的实例, // 提取要通过批量模式更新的项 $items=$this->getItemsToUpdate(); if(isset($_POST['Item'])) { $valid=true; foreach($items as $i=>$item) { if(isset($_POST['Item'][$i])) $item->attributes=$_POST['Item'][$i]; $valid=$valid&&$item->validate();
} if($valid) // 如果所有项目有效 //...则在此处做一些操作
} // 显示视图收集表格输入 $this->render('batchUpdate',array('items'=>$items));
}
准备好了这个动作,我们需要继续 batchUpdate 视图的工作以在一个 HTML 表格中显示输入项。 <div class="form"> <?phpecho CHtml::beginForm();?> <table> <tr><th>Name</th><th>Price</th><th>Count</th><th>Description</th></tr> <?phpforeach($items as $i=>$item): ?> <tr> <td><?php echoCHtml::activeTextField($item,"[$i]name"); ?></td> <td><?php echoCHtml::activeTextField($item,"[$i]price"); ?></td> <td><?php echoCHtml::activeTextField($item,"[$i]count"); ?></td> <td><?php echoCHtml::activeTextArea($item,"[$i]description"); ?></td> </tr> <?phpendforeach; ?> </table> <?phpecho CHtml::submitButton('Save'); ?> <?phpecho CHtml::endForm();?> </div><!-- form --> 注意,在上面的代码中我们使用了 "[$i]name" 而不是 "name" 作为调用 CHtml::activeTextField 时的第二个参数。 如果有任何验证错误,相应的输入项将会自动高亮显示,就像前面我们讲解的单模型输入一样。 |