Yii架構官方指南系列17——使用表單:建立模型

來源:互聯網
上載者:User



在編寫表單所需的 HTML 程式碼之前,我們應該先確定來自終端使用者輸入的資料的類型,以及這些資料應符合什麼樣的規則。 模型類可用於記錄這些資訊。 正如模型章節所定義的, 模型是儲存使用者輸入和驗證這些輸入的中心位置。

取決於使用使用者所輸入資料的方式,我們可以建立兩種類型的模型。 如果使用者輸入被收集、使用然後丟棄,我們應該建立一個 表單模型; 如果使用者的輸入被收集後要儲存到資料庫,我們應使用一個 Active Record 。 兩種類型的模型共用同樣的基類 CModel ,它定義了表單所需的通用介面。

注意: 我們在這一節的樣本中主要使用了表單模型 。然而,同樣的操作也可應用於 Active Record 模型。

1. 定義模型類

下面我們建立了一個 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','錯誤的使用者名稱或密碼。');    }}

上述代碼指定:usernamepassword 為必填項, 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: CDefaultValueValidator 的別名,指定特性的預設值。

  • exist: CExistValidator 的別名,確保特性值可以在指定表的列中可以找到。

  • file: CFileValidator 的別名,確保特性含有一個上傳檔案的名字。

  • filter: CFilterValidator 的別名,通過一個過濾器改變此特性。

  • in: CRangeValidator 的別名,確保資料在一個預先指定的值的範圍之內。

  • length: CStringValidator 的別名,確保資料的長度在一個指定的範圍之內。

  • match: CRegularExpressionValidator 的別名,確保資料可以匹配一個Regex。

  • 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'),

如上所示, usernamepassword 特性在 login 情境中是必填項。而 username, passwordemail 特性在register 情境中是必填項。 於是,如果我們在 login 情境中執行塊賦值,就只有 usernamepassword 會被塊賦值。 因為只有它們出現在 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 情境.裡,我們只能使用 usernamepassword 特性.我們可以按照如下來指定這一限制 :


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情境中,我們只想驗證使用者模型中的 usernamepassword 輸入; 而在 register 情境中,我們需要驗證更多的輸入,例如 email, address, 等。 下面的例子示範了如何在 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——使用表單:建立模型的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.