ホームページ  >  記事  >  バックエンド開発  >  Yii でのフォームの使用例

Yii でのフォームの使用例

不言
不言オリジナル
2018-06-15 11:47:131474ブラウズ

この記事では主に Yii でのフォームの使用法をより詳細な分析と例を組み合わせて紹介し、Yii でのフォームの一般的な操作テクニックをまとめています。必要な方は参考にしてください。

この記事の例では、Yii でのフォームの使用法について説明します。参考のために皆さんと共有してください。詳細は次のとおりです。

Yii でフォームを処理する場合、通常は次の手順が必要です。

1. データ フィールドを表すモデル クラスを作成します。収集される。

2. フォームの送信に応答するコントローラー アクションを作成します。
3. ビュースクリプト内にコントローラーアクションに関連するフォームを作成します。

1. モデルを作成する

フォームに必要な HTML コードを記述する前に、まずエンド ユーザーからのデータ入力の種類と、これらのデータ入力の方法を決定する必要があります。データはどのようなルールに従う必要がありますか。モデル クラスを使用して、この情報を記録できます。 「モデル」の章で定義されているように、モデルはユーザー入力を保存し、それらの入力を検証するための中心的な場所です。

ユーザーが入力したデータの使用方法に応じて、2 種類のモデルを作成できます。ユーザー入力を収集して使用し、その後破棄する場合は、フォーム モデルを作成する必要があります。

ユーザー入力を収集してデータベースに保存する場合は、アクティブ レコードを使用する必要があります。どちらのタイプのモデルも、フォームに必要な共通インターフェイスを定義する同じ基本クラス CModel を共有します。

1. モデル クラスを定義します。

たとえば、フォーム モデルを作成します:

class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
}

LoginForm $username、$password、$rememberMe の 3 つの属性が定義されています。これらは、ユーザーが入力したユーザー名とパスワードを保存するために使用され、ユーザーがログインを覚えておきたい場合のオプションもあります。 $rememberMe のデフォルト値は false であるため、ログイン フォームに最初に表示されるとき、対応するオプションはオフになります。

これらのメンバー変数を、通常のプロパティ (プロパティ) と区別するために、プロパティ (プロパティ) ではなく属性 (属性) と呼びます。属性は、主にユーザー入力またはデータベースからのデータを保存するために使用されるプロパティです。

2. 検証ルールの宣言

ユーザーが入力を送信し、モデルにデータが入力されたら、使用する前にユーザーの入力が有効であることを確認する必要があります。これは、ユーザーの入力を一連のルールに照らして検証することによって実現されます。これらの検証ルールを rules() メソッドで指定すると、ルール設定の配列が返されます。

class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
private $_identity;
public function rules()
{
return array(
array('username, password', 'required'), //username 和 password 为必填项
array('rememberMe', 'boolean'), //rememberMe 应该是一个布尔值
array('password', 'authenticate'), //password 应被验证(authenticated)
);
}
public function authenticate($attribute,$params)
{
$this->_identity=new UserIdentity($this->username,$this->password);
if(!$this->_identity->authenticate())
$this->addError('password','错误的用户名或密码。');
}
}

rules() 返される各ルールは次の形式である必要があります:

array('AttributeList', 'Validator', 'on'=>'ScenarioList', ...附加选项)

Where:

AttributeList(Attribute List) は、このルールで検証する必要がある属性のリスト文字列です。各属性名はカンマで区切られます。

Validator (バリデーター) は、実行する検証の種類を指定します。
on パラメーターはオプションです。そして、ルールを適用する必要があるシナリオのリストを指定します。

追加オプションは、対応するバリデーターの属性値を初期化するために使用される名前と値のペアの配列です。

検証ルールで Validator を指定する方法は 3 つあります。

まず、Validator は、上の例のauthenticate のように、モデル クラスのメソッドの名前にすることができます。検証メソッドは次の構造である必要があります。

public function 验证器名称($attribute,$params) { ... }

次に、Validator はバリデータ クラスの名前にすることができます。このルールが適用されると、実際の検証を実行するためにバリデータ クラスのインスタンスが作成されます。ルールの追加オプションは、インスタンスの属性値を初期化するために使用されます。 Validator クラスは CValidator から継承する必要があります。

3 番目に、Validator は、事前定義されたバリデーター クラスのエイリアスにすることができます。上の例では、必須の名前は CRequiredValidator のエイリアスであり、検証されるプロパティ値が null でないことを確認するために使用されます。事前定義されたバリデーター エイリアスの完全なリストは次のとおりです。

boolean: CBool​​eanValidator のエイリアス。属性に CBool​​eanValidator::trueeva lue または CBool​​eanValidator::falseva lue 値があることを確認します。

captcha: CCaptchaValidator のエイリアス。属性値が CAPTCHA に表示される検証コードと等しいことを確認します。
compare: CCompareva リデーターのエイリアス。プロパティが別のプロパティまたは定数と等しいことを確認します。
email: CEmailValidator のエイリアス。属性が有効な電子メール アドレスであることを確認します。
default: CDefaultValueva lidator のエイリアス。属性のデフォルト値を指定します。
exist: CExistValidator のエイリアス。指定されたテーブルの列で属性値が見つかることを保証します。
file: CFileva lidator のエイリアス。属性にアップロードされたファイルの名前が含まれていることを確認してください。
filter: CFilterValidator のエイリアス。フィルターを通じてこのプロパティを変更します。
in: CRangeva lidator のエイリアス。データが事前に指定された値の範囲内にあることを確認します。
length: CStringValidator のエイリアス。データの長さが指定された範囲内にあることを保証します。
match: C RegularExpressionValidator のエイリアス。データが正規表現と一致することを確認します。
numerical: CNumberValidator のエイリアス。データが有効な数値であることを確認します。
required: CRequiredValidator のエイリアス。属性が空でないことを確認します。
type: CTypeva リデーターのエイリアス。属性が指定されたデータ型であることを確認します。
unique: CUniqueva lidator の別名。データ テーブル内の列間でデータが一意であることを保証します。
url: CUrlValidator のエイリアス。データが有効な URL であることを確認します。

下面我们列出了几个只用这些预定义验证器的示例:

// 用户名为必填项
array('username', 'required'),
// 用户名必须在 3 到 12 个字符之间
array('username', 'length', 'min'=>3, 'max'=>12),
// 在注册场景中,密码password必须和password2一致。
array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
// 在登录场景中,密码必须接受验证。
array('password', 'authenticate', 'on'=>'login'),

3、安全的特性赋值

在一个类的实例被创建后,我们通常需要用最终用户提交的数据填充它的特性。这可以通过如下块赋值(massive assignment)方式轻松实现:

$model=new LoginForm;
if(isset($_POST['LoginForm']))
$model->attributes=$_POST['LoginForm'];

最后的表达式被称作 块赋值(massive assignment) ,它将 $_POST['LoginForm'] 中的每一项复制到相应的模型特性中。这相当于如下赋值方法:

foreach($_POST['LoginForm'] as $name=>$value)
{
if($name 是一个安全的特性)
$model->$name=$value;
}

检测特性的安全非常重要,例如,如果我们以为一个表的主键是安全的而暴露了它,那么攻击者可能就获得了一个修改记录的主键的机会,从而篡改未授权给他的内容。

特性如果出现在相应场景的一个验证规则中,即被认为是安全的。例如:

array('username, password', 'required', 'on'=>'login, register'),
array('email', 'required', 'on'=>'register'),

如上所示, username 和 password 特性在 login 场景中是必填项。而 username, password 和 email特性在 register 场景中是必填项。于是,如果我们在 login 场景中执行块赋值,就只有 username 和 password会被块赋值。因为只有它们出现在 login 的验证规则中。另一方面,如果场景是 register ,这三个特性就都可以被块赋值。

// 在登录场景中
$model=new User('login');
if(isset($_POST['User']))
$model->attributes=$_POST['User'];
// 在注册场景中
$model=new User('register');
if(isset($_POST['User']))
$model->attributes=$_POST['User'];

那么为什么我们使用这样一种策略来检测特性是否安全呢?背后的基本原理就是:如果一个特性已经有了一个或多个可检测有效性的验证规则,那我们还担心什么呢?

请记住,验证规则是用于检查用户输入的数据,而不是检查我们在代码中生成的数据(例如时间戳,自动产生的主键)。因此,不要为那些不接受最终用户输入的特性添加验证规则。

有时候,我们想声明一个特性是安全的,即使我们没有为它指定任何规则。例如,一篇文章的内容可以接受用户的任何输入。我们可以使用特殊的 safe 规则实现此目的:

array('content', 'safe')

还有一个用于声明一个属性为不安全的 unsafe 规则:

array('permission', 'unsafe')

unsafe 规则并不常用,它是我们之前定义的安全特性的一个例外。

4、触发验证

一旦模型被用户提交的数据填充,我们就可以调用 CModel::validate() 触发数据验证进程。此方法返回一个指示验证是否成功的值。对CActiveRecord  模型来说,验证也可以在我们调用其 CActiveRecord::save() 方法时自动触发。

我们可以通过设置scenario属性来设置场景属性,这样,相应场景的验证规则就会被应用。

验证是基于场景执行的。 scenario属性指定了模型当前用于的场景和当前使用的验证规则集。例如,在 login 场景中,我们只想验证用户模型中的username 和 password 输入;而在 register 场景中,我们需要验证更多的输入,例如 email, address,等。下面的例子演示了如何在 register 场景中执行验证:

// 在注册场景中创建一个 User 模型。等价于:
// $model=new User;
// $model->scenario='register';
$model=new User('register'); //给模型类添加参数,该参数就是要触发的验证场景
// 将输入的值填充到模型
$model->attributes=$_POST['User'];
// 执行验证
if($model->validate())  // 如果输入有效
...
else
...

规则关联的场景可以通过规则中的 on 选项指定。如果 on 选项未设置,则此规则会应用于所有场景。例如:

public function rules()
{
return array(
array('username, password', 'required'),
array('password_repeat', 'required', 'on'=>'register'),
array('password', 'compare', 'on'=>'register'),
);
}

第一个规则将应用于所有场景,而第二个将只会应用于 register 场景。

5、提取验证错误

验证完成后,任何可能产生的错误将被存储在模型对象中。我们可以通过调用 CModel::getErrors()和CModel::getError()  提取这些错误信息。这两个方法的不同点在于第一个方法将返回所有 模型特性的错误信息,而第二个将只返回第一个 错误信息。

6、特性标签

当设计表单时,我们通常需要为每个表单域显示一个标签。标签告诉用户他应该在此表单域中填写什么样的信息。虽然我们可以在视图中硬编码一个标签,但如果我们在相应的模型中指定(标签),则会更加灵活方便。

默认情况下 CModel 将简单的返回特性的名字作为其标签。这可以通过覆盖 attributeLabels() 方法自定义。正如在接下来的小节中我们将看到的,在模型中指定标签会使我们能够更快的创建出更强大的表单。

二、创建动作

有了模型,我们就可以开始编写用于操作此模型的逻辑了。我们将此逻辑放在一个控制器的动作中。对登录表单的例子来讲,相应的代码就是:

public function actionLogin()
{
$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 的实例。

上述代码生成了一个更加动态的表单,例如, CHtml::activeLabel()生成一个与指定模型的特性相关的标签。如果此特性有一个输入错误,此标签的CSS class 将变为 error,通过 CSS样式改变了标签的外观。相似的, CHtml::activeTextField() 为指定模型的特性生成一个文本输入域,并会在错误发生时改变它的CSS class。

我们还可以使用一个新的小物件 CActiveForm  以简化表单创建。这个小物件可同时提供客户端及服务器端无缝的、一致的验证。使用 CActiveForm, 上面的代码可重写为:

beginWidget('CActiveForm'); ?>
errorSummary($model); ?>
label($model,'username'); ?>
textField($model,'username') ?>
label($model,'password'); ?>
passwordField($model,'password') ?>
checkBox($model,'rememberMe'); ?>
label($model,'rememberMe'); ?>
endWidget(); ?>

四、收集表格输入

有时我们想通过批量模式收集用户输入。也就是说,用户可以为多个模型实例输入信息并将它们一次性提交。我们将此称为 表格输入(tabular input) ,因为这些输入项通常以 HTML 表格的形式呈现。

要使用表格输入,我们首先需要创建或填充一个模型实例数组,取决于我们是想插入还是更新数据。然后我们从 $_POST变量中提取用户输入的数据并将其赋值到每个模型。和单模型输入稍有不同的一点就是:我们要使用 $_POST['ModelClass'][$i]提取输入的数据而不是使用 $_POST['ModelClass']。

public function actionBatchUpdate()
{
// 假设每一项(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 表格中显示输入项。

NamePriceCount
Description
$item): ?>

注意,在上面的代码中我们使用了 "[$i]name" 而不是 "name" 作为调用 CHtml::activeTextField 时的第二个参数。

如果有任何验证错误,相应的输入项将会自动高亮显示,就像前面我们讲解的单模型输入一样。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

如何通过Yii统计不同类型邮箱数量

Yii和CKEditor实现图片上传的功能

Bootbox プラグインを使用して Yii2 にカスタム ポップアップ ウィンドウを実装する方法

##

以上がYii でのフォームの使用例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。