ホームページ  >  記事  >  バックエンド開発  >  Yii Framework 公式ガイド シリーズ 17 - フォームの使用: モデルの作成

Yii Framework 公式ガイド シリーズ 17 - フォームの使用: モデルの作成

黄舟
黄舟オリジナル
2017-02-13 09:10:581278ブラウズ



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

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

注: このセクションの例では主にフォーム モデルを使用します。ただし、同じ操作はアクティブレコードモデルにも適用できます。

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

以下では、ログイン ページでユーザー入力を収集するための LoginForm モデル クラスを作成します。 ログイン情報はユーザーの認証にのみ使用され、保存する必要がないため、フォーム モデルとして LoginForm を作成します。 LoginForm 模型类用于在一个登录页中收集用户的输入。 由于登录信息只被用于验证用户,并不需要保存,因此我们将 LoginForm 创建为一个 表单模型。


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

LoginForm 中定义了三个属性: $username$password 和 $rememberMe。他们用于保存用户输入的用户名和密码,还有用户是否想记住他的登录的选项。 由于 $rememberMe 有一个默认的值 false,相应的选项在初始化显示在登录表单中时将是未勾选状态。

信息: 我们将这些成员变量称为 特性(attributes) 而不是 属性(properties),以区别于普通的属性(properties)。 特性(attribute)是一个主要用于存储来自用户输入或数据库数据的属性(propertiy)。

2. 声明验证规则

一旦用户提交了他的输入,模型被填充,我们就需要在使用前确保用户的输入是有效的。 这是通过将用户的输入和一系列规则执行验证实现的。我们在 rules() 方法中指定这些验证规则, 此方法应返回一个规则配置数组。


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

    private $_identity;

    public function rules()
    {
        return array(
            array('username, password', 'required'),
            array('rememberMe', 'boolean'),
            array('password', 'authenticate'),
        );
    }

    public function authenticate($attribute,$params)
    {
        $this->_identity=new UserIdentity($this->username,$this->password);
        if(!$this->_identity->authenticate())
            $this->addError('password','错误的用户名或密码。');
    }
}

上述代码指定:username 和 password 为必填项, password 应被验证(authenticated),rememberMe 应该是一个布尔值。

rules() 返回的每个规则必须是以下格式:


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

其中 AttributeList(特性列表) 是需要通过此规则验证的特性列表字符串,每个特性名字由逗号分隔;Validator(验证器) 指定要执行验证的种类;on 参数是可选的,它指定此规则应被应用到的场景列表; 附加选项是一个名值对数组,用于初始化相应验证器的属性值。

有三种方式可在验证规则中指定 Validator 。

第一, Validator 可以是模型类中一个方法的名字,就像上面示例中的 authenticate 。验证方法必须是下面的结构:


/**
 * @param string 所要验证的特性的名字
 * @param array 验证规则中指定的选项
 */
public function ValidatorName($attribute,$params) { ... }

第二,Validator 可以是一个验证器类的名字,当此规则被应用时, 一个验证器类的实例将被创建以执行实际验证。规则中的附加选项用于初始化实例的属性值。 验证器类必须继承自 CValidator

第三,Validator 可以是一个预定义的验证器类的别名。在上面的例子中, required 名字是CRequiredValidator 的别名,它用于确保所验证的特性值不为空。 下面是预定义的验证器别名的完整列表:

  • boolean: CBooleanValidator 的别名, 确保特性有一个 CBooleanValidator::trueValue 或CBooleanValidator::falseValue 值。

  • captcha: CCaptchaValidator 的别名,确保特性值等于 CAPTCHA 中显示的验证码。

  • compare: CCompareValidator 的别名,确保特性等于另一个特性或常量。

  • email: CEmailValidator 的别名,确保特性是一个有效的Email地址。

  • default

    🎜🎜🎜🎜
    // 用户名为必填项
    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'),
    🎜🎜🎜LoginForm は、$username$password、および $rememberMe の 3 つの属性を定義します。 >。これらは、ユーザーが入力したユーザー名とパスワード、およびユーザーがログインを記憶するかどうかのオプションを保存するために使用されます。 $rememberMe のデフォルト値は false であるため、ログイン フォームに最初に表示されるとき、対応するオプションはオフになります。 🎜🎜🎜🎜情報:🎜 通常のプロパティと区別するために、これらのメンバー変数をプロパティではなく属性と呼びます。 属性は、主にユーザー入力またはデータベースからのデータを保存するために使用されるプロパティです。 🎜🎜🎜2. 検証ルールを宣言する🎜🎜 ユーザーが入力を送信し、モデルが設定されたら、使用する前にユーザーの入力が有効であることを確認する必要があります。 これは、ユーザーの入力を一連のルールに照らして検証することによって実現されます。これらの検証ルールを rules() メソッドで指定すると、ルール設定の配列が返されます。 🎜🎜🎜🎜🎜🎜
    $model=new LoginForm;
    if(isset($_POST['LoginForm']))
        $model->attributes=$_POST['LoginForm'];
    🎜🎜🎜上記のコードは、 usernamepassword が必須であり、 password は認証 (認証) される必要があることを指定します。 rememberMe はブール値である必要があります。 🎜🎜rules() 返される各ルールは次の形式である必要があります: 🎜🎜🎜🎜🎜🎜
    foreach($_POST['LoginForm'] as $name=>$value)
    {
        if($name 是一个安全的特性)
            $model->$name=$value;
    }
    🎜🎜🎜 ここで、これを渡すには AttributeList (属性リスト) が必要です。ルール 検証された機能リストの文字列。各機能名はカンマで区切られます。Validator (validator) は、実行する検証のタイプを指定します。on パラメータはオプションであり、シナリオのリストを指定します。このルールを適用する必要がある; 追加オプションは、対応するバリデーターのプロパティ値を初期化するために使用される名前と値のペアの配列です。 🎜🎜検証ルールで Validator を指定するには 3 つの方法があります。 🎜🎜まず、Validator は、例の authenticate。 /code> の上。検証メソッドは次の構造を持つ必要があります: 🎜🎜🎜🎜🎜🎜<pre class="brush:php;toolbar:false">array('username, password', 'required', 'on'=&gt;'login, register'), array('email', 'required', 'on'=&gt;'register'),</pre>🎜🎜🎜 2 番目に、<span style="color: #ff0000;"><code>Validator はバリデータ クラスの名前にすることができます、このルールが適用されると、実際の検証を実行するためにバリデーター クラスのインスタンスが作成されます。ルールの追加オプションは、インスタンスのプロパティ値を初期化するために使用されます。 バリデーター クラスは CValidator から継承する必要があります。 🎜🎜 3 番目に、Validator は、事前定義されたバリデータ クラス のエイリアスにすることができます。上の例では、required 名は CRequiredValidator のエイリアスであり、検証されるプロパティが空でないことを確認するために使用されます。 事前定義されたバリデーター エイリアスの完全なリストは次のとおりです: 🎜
    • 🎜boolean: CBool​​eanValidator のエイリアス。属性に CBool​​eanValidator があることを確認してください。 :trueValue または CBool​​eanValidator::falseValue 値。 🎜
    • 🎜captcha: CCaptchaValidator のエイリアス。特性値が CAPTCHA に表示される検証コードと等しいことを確認します。 🎜
    • 🎜compare: CCompareValidator のエイリアス。プロパティが別のプロパティまたは定数と等しいことを確認します。 🎜
    • 🎜email: 属性が有効な電子メール アドレスであることを確認するための CEmailValidator のエイリアス。 🎜
    • 🎜default: CDefaultValueValidator のエイリアス。機能のデフォルト値を指定します。 🎜
    • exist: CExistValidator 的别名,确保特性值可以在指定表的列中可以找到。

    • file: CFileValidator 的别名,确保特性含有一个上传文件的名字。

    • filter: CFilterValidator 的别名,通过一个过滤器改变此特性。

    • in: CRangeValidator 的别名,确保数据在一个预先指定的值的范围之内。

    • length: CStringValidator 的别名,确保数据的长度在一个指定的范围之内。

    • match: CRegularExpressionValidator 的别名,确保数据可以匹配一个正则表达式。

    • numerical: CNumberValidator 的别名,确保数据是一个有效的数字。

    • required: CRequiredValidator 的别名,确保特性不为空。

    • type: CTypeValidator 的别名,确保特性是指定的数据类型。

    • unique: CUniqueValidator 的别名,确保数据在数据表的列中是唯一的。

    • 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;
    }

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

    检测特性安全的策略在版本 1.0 和 1.1 中是不同的,下面我们将分别讲解:

    1.1 中的安全特性

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


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

    如上所示, username 和 password 特性在 login 场景中是必填项。而 usernamepassword 和 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 规则并不常用,它是我们之前定义的安全特性的一个例外。

    1.0 中的安全特性

    在版本1.0中,决定一个数据项是否是安全的,基于一个名为 safeAttributes 方法的返回值和数据项被指定的场景. 默认的,这个方法返回所有公共成员变量作为 CFormModel 的安全特性,而它也返回了除了主键外, 表中所有字段名作为 CActiveRecord的安全特性.我们可以根据场景重写这个方法来限制安全特性 .例如, 一个用户模型可以包含很多特性,但是在 login 场景.里,我们只能使用 username 和 password 特性.我们可以按照如下来指定这一限制 :


    public function safeAttributes()
    {
        return array(
            parent::safeAttributes(),
            'login' => 'username, password',
        );
    }

    safeAttributes 方法更准确的返回值应该是如下结构的 :


    array(
       // these attributes can be massively assigned in any scenario
       // that is not explicitly specified below
       'attr1, attr2, ...',
         *
       // these attributes can be massively assigned only in scenario 1
       'scenario1' => 'attr2, attr3, ...',
         *
       // these attributes can be massively assigned only in scenario 2
       'scenario2' => 'attr1, attr3, ...',
    )

    如果模型不是场景敏感的(比如,它只在一个场景中使用,或者所有场景共享了一套同样的安全特性),返 回值可以是如下那样简单的字符串.


    'attr1, attr2, ...'

    而那些不安全的数据项,我们需要使用独立的赋值语句来分配它们到相应的特性.如下所示:


    $model->permission='admin';
    $model->id=1;

    4. 触发验证

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

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

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


    // 在注册场景中创建一个  User 模型。等价于:
    // $model=new User;
    // $model->scenario='register';
    $model=new User('register');
    
    // 将输入的值填充到模型
    $model->attributes=$_POST['User'];
    
    // 执行验证
    if($model->validate())   // if the inputs are valid
        ...
    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() 方法自定义。 正如在接下来的小节中我们将看到的,在模型中指定标签会使我们能够更快的创建出更强大的表单。

    以上就是Yii框架官方指南系列17——使用表单:创建模型的内容,更多相关内容请关注PHP中文网(www.php.cn)!

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