翻了兩篇,突然想起來,忘了提個醒。各位看官,我所翻的這個yii 指引手冊早有中文版的,可以去找來看看。本人是閒來無聊,自己翻。
對於一個web工程來說,最主要的工作就是通過HTML表單來蒐集用戶的輸入數據。除了設計表單,程序員還需要設置已有數據或者是默認值,驗證用戶輸入,正確並人性化的輸出錯誤提示信息,保存數據到存儲設備。Yii通過MVC架構,非常輕鬆的完成以上所述的工作流。
以下是用Yii處理form時的經典步驟:
1、爲要蒐集的數據創建一個模型。
2、創建一個控制器的動作,用來相應表單提交信息。
3、在視圖文件中,創建一個表單,用來關聯控制器的動作。
接下來,我們詳細的描述以上的每個步驟。
1、創建模型
在寫表單的HTML代碼前,我們先要弄明白的一點:我們希望終端用戶提供什麼樣的數據,以及這些數據必須符合什麼規則。模型類就可以用來記錄這些信息的,他就是用來保存用戶輸入信息,並且驗證信息的。
基於我們想讓用戶以何種方式輸入,我們可以創建兩種類型的模型。如果用戶數據採集使用之後,是要丟棄的,那麼我們就可以創建一個form model;如果用戶數據採集之後是要保存到數據庫的,我們就創建一個active record。這兩種模型都是繼承於相同的基類CModel的,這個基類定義了一些表單常用的接口。
1.1 定義模型類
下面我們創建一個LoginForm的模型類來採集用戶在登錄時的信息。因爲用戶登錄只是驗證用戶信息,不需要保存,所以採用form model。(本人認爲,實際應用中,用戶登錄信息除了校驗用戶的信息,一般都還是需要記錄一些信息的,具體依不同項目而定)
class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
}
以上的代碼,聲明瞭LoginForm的3個屬性:$username, $password and $rememberMe. 具體幹嘛用的不需要翻譯了,一目瞭然。這些屬性就是用來保存用戶輸入的數據或者是數據庫的數據。
1.2 聲明驗證規則
一旦用戶提交了數據,模型獲取到了輸入信息,我們要驗證這些輸入的合法性。這個工作是由一堆的規則來驗證輸入的信息。我們在方法rules()中來配置這一些驗證規則。
class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
private $ identity;3.2CreatingModel55
public function rules()
{
return array(
array('username,password', 'required'), //表明用戶名,密碼是必填項
array('rememberMe', 'boolean'),//布爾型
array('password', 'authenticate'),//需到authenticate驗證
);
}
public function authenticate($attribute,$params)
{
$this-> identity=new UserIdentity($this->username,$this->password);
if(!$this-> identity->authenticate())
$this->addError('password','Incorrectusernameorpassword.');
}
}
所有的規則,都必須符合以下的格式:
array('AttributeList', 'Validator', 'on'=>'ScenarioList',...additional options)
AttributeList:需要用這條規則來校驗的屬性列表,如果是多個屬性,中間用, 隔開。
Validator:驗證器。也就是指定的這些屬性列表,需要用哪個校驗器來檢驗。
on:可選項,用來指明在什麼場景需要啓用該規則。
有三種方式來選擇規則中的驗證器。首先,驗證器可以是自身模型類的一個方法,如上例中的authenticate。驗證器必須符合以下格式:public function ValidatorName($attribute,$params) {...}。第二,這個驗證器可以是某個驗證器類的類名稱。當規則啓用的時候,這個驗證器類就會創建一個實例並運行起來,執行他的驗證功能。規則中的addtional options就是用來初始化這個實例屬性的。第三,這個驗證器也可以是某個驗證器的別名。上例的規則中,'required'就是CRequiredValidator的別名,用來校驗所有的屬性值不爲空。以下列出一份完整的別名名單,能背下來最後,目前我是還沒背下來:
boolean, captcha, email, date, default, exist, file, filter, in, length, match, numerical, required, type, unique, url
樣例示範:
// username is required
array('username', 'required'),
// username must be between 3 and 12 characters
array('username', 'length', 'min'=>3, 'max'=>12),
// when in register scenario, password must match password2
array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
// when in login scenario, password must be authenticated
array('password', 'authenticate', 'on'=>'login'),
1.3 安全的給屬性賦值
在模型實例化以後,我們通常都需要由終端用戶來填充數據。可以簡單的由以下代碼實現集體賦值(massive assignment):
$model=new LoginForm;
if(isset($ POST['LoginForm']))
$model->attributes=$ POST['LoginForm'];
上例中的最後一行就是集體賦值,把從$_POST['LoginFom']的數據賦值到相對應的模型屬性中。作用等同於:
foreach($ POST['LoginForm'] as $name=>$value)
{
if($name is a safe attribute)
$model->$name=$value;
}
他的關鍵之處在於指定哪些屬性是安全的。假設我們把某個表的主鍵設置爲安全類型,那麼當***有機會修改該記錄的主鍵值,並篡改數據,這些都是不合法的。
聲明安全的屬性
一個屬性,如果在給定的場景下,符合驗證規則,那麼我們就認爲這個屬性是安全的。例如
array('username, password', 'required', 'on'=>'login, register'),
array('email', 'required', 'on'=>'register'),
在login, register的時候,用戶名,密碼是必填項,在register的時候,用戶名,密碼,email都是必填項。
所以,在用戶登錄的時候,只有用戶名,密碼這兩個屬性會被集體賦值(massive assignment), 因爲在登錄的時候,規則只有這兩個屬性;同樣的,在註冊新用戶的時候,以上的三個屬性都會被集體賦值。
// in login scenario
$model=new User('login');
if(isset($ POST['User']))
$model->attributes=$ POST['User'];
// in register scenario
$model=new User('register');
if(isset($ POST['User']))
$model->attributes=$ POST['User'];
好了,現在的問題,我們爲什麼要用這樣的策略來決定一個屬性是否是安全的呢?想想看,如果一個屬性,已經被一條或者是N條的驗證規則驗證過了,那麼我們還有什麼好擔心的呢?
必須謹記的一點,驗證規則主要是用來驗證用戶的提交數據,而不是代碼所生成的數據(例如時間戳,自動生成的主鍵ID)。所以,千萬記住,不要爲那些不是從終端用戶提交的數據進行規則校驗。
有時候,我們想把某些屬性設置爲安全屬性,即使我們並沒有規則來校驗他。例如一篇文章的內容,可以允許任何的內容輸入。這時候我們就可以使用安全規則,來強制說明這個屬性是安全的:
array('content', 'safe')
有強制說明安全,那就會有強制說明不安全的了:
array('permission', 'unsafe')
這個被註明爲不安全的屬性有什麼用呢?他很有用,是之前所提到的安全屬性的一個例外。
對於這些不安全的屬性,我們必須親自一一爲他們賦值,例如:
$model->permission='admin';
$model->id=1;
1.4 觸發式校驗
一個模型在用戶提交數據之後,我們可以調用CModel::validate()的方法來觸發數據校驗的線程。這個方法返回一個校驗的結果,通過或者不通過。對於CActiveRecord的模型來說,在我們調用CActiveRecord::save()的時候,也會自動觸發該方法。
我們可以設置一個場景的屬性,以及一些驗證規則來校驗。
校驗器是在一個基礎的場景使用的,這個場景的屬性確定了場景是用哪個模型,以及那些校驗規則會被啓用。例如,在用戶登錄(Login)的時候,我們只想校驗用戶名,密碼;在註冊新用戶的場景時,我們需要驗證更多的信息,例如emai,地址等。
// creates a User model in register scenario. It is equivalent to:
// $model=new User;
// $model->scenario='register';
$model=new User('register');
// populates the input values into the model
$model->attributes=$ POST['User'];
// performs the validation
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'),
);
}
第一條規則適用於任何場景,而第二條規則只有在regster的場景時適用。
1.5 捕獲校驗器錯誤
在驗證完成之後,任何錯誤都可能存在於模型的對象中。怎麼才能獲取這些錯誤信息呢?我們可以通過調用CModel::getErrors() 以及CModel::getError()。這兩個的區別在於第一個方法會返回校驗後所有的錯誤信息,而後者只返回第一個錯誤。
1.6 屬性標籤
在設計的時候,我們通常需要爲要輸入的屬性設置一個標籤,用來告訴終端用戶,輸入的是什麼項目。當然,最原始的方法,我們可以自己在視圖裏用代碼編寫一個標籤,但是,有更好的方法了。最好是在當前的模型中,提供一個標籤,這樣既方便又容易維護。
默認情況下,CModel只是簡單的用該屬性的名稱來作爲標籤。這可以通過重載attributeLabels()這個方法來設置。在後續的章節中,我們會看到在模型中設置標籤,會使我們的開發更快速,也更健壯。