這篇文章主要介紹了Yii中表單用法,結合執行個體形式較為詳細的分析總結了Yii針對錶單的各種常用操作技巧,具有一定參考借鑒價值,需要的朋友可以參考下
本文執行個體講述了Yii中表單用法。分享給大家供大家參考,具體如下:
在 Yii 中處理表單時,通常需要以下步驟:
1. 建立用於表現所要收集資料欄位的模型類。
2. 建立一個控制器動作,響應表單提交。
3. 在視圖指令碼中建立與控制器動作相關的表單。
一、建立模型
在編寫表單所需的 HTML 程式碼之前,我們應該先確定來自終端使用者輸入的資料的類型,以及這些資料應符合什麼樣的規則。模型類可用於記錄這些資訊。正如模型章節所定義的,模型是儲存使用者輸入和驗證這些輸入的中心位置。
取決於使用使用者所輸入資料的方式,我們可以建立兩種類型的模型。如果使用者輸入被收集、使用然後丟棄,我們應該建立一個表單模型;
如果使用者的輸入被收集後要儲存到資料庫,我們應使用一個Active Record。兩種類型的模型共用同樣的基類 CModel,它定義了表單所需的通用介面。
1、定義模型類
例如建立為一個表單模型:
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'), //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', ...附加選項)
其中:
AttributeList(特性列表)是需要通過此規則驗證的特性列表字串,每個特性名字由逗號分隔;
Validator(驗證器) 指定要執行驗證的種類;
on 參數是可選的,它指定此規則應被應用到的情境列表;
附加選項 是一個名值對數組,用於初始化相應驗證器的屬性值。
有三種方式可在驗證規則中指定 Validator:
第一, Validator 可以是模型類中一個方法的名字,就像上面樣本中的 authenticate 。驗證方法必須是下面的結構:
public function 驗證器名稱($attribute,$params) { ... }
第二,Validator可以是一個驗證器類的名字,當此規則被應用時,一個驗證器類的執行個體將被建立以執行實際驗證。規則中的附加選項用於初始化執行個體的屬性值。驗證器類必須繼承自 CValidator。
第三,Validator 可以是一個預定義的驗證器類的別名。在上面的例子中,required 名字是 CRequiredValidator 的別名,它用於確保所驗證的特性值不為空白。下面是預定義的驗證器別名的完整列表:
boolean: CBooleanValidator 的別名,確保特性有一個 CBooleanValidator::trueva lue 或 CBooleanValidator::falseva lue 值。
captcha: CCaptchaValidator 的別名,確保特性值等於 CAPTCHA 中顯示的驗證碼。
compare: CCompareva lidator 的別名,確保特性等於另一個特性或常量。
email: CEmailValidator 的別名,確保特性是一個有效Email地址。
default: CDefaultValueva lidator 的別名,指定特性的預設值。
exist: CExistValidator 的別名,確保特性值可以在指定表的列中可以找到。
file: CFileva lidator 的別名,確保特性含有一個上傳檔案的名字。
filter: CFilterValidator 的別名,通過一個過濾器改變此特性。
in: CRangeva lidator 的別名,確保資料在一個預先指定的值的範圍之內。
length: CStringValidator 的別名,確保資料的長度在一個指定的範圍之內。
match: CRegularExpressionValidator 的別名,確保資料可以匹配一個Regex。
numerical: CNumberValidator 的別名,確保資料是一個有效數字。
required: CRequiredValidator 的別名,確保特性不為空白。
type: CTypeva lidator 的別名,確保特性是指定的資料類型。
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 表格中顯示輸入項。
NamePriceCountDescription$item): ?>
注意,在上面的代碼中我們使用了 "[$i]name" 而不是 "name" 作為調用 CHtml::activeTextField 時的第二個參數。
如果有任何驗證錯誤,相應的輸入項將會自動高亮顯示,就像前面我們講解的單模型輸入一樣。
以上就是本文的全部內容,希望對大家的學習有所協助,更多相關內容請關注topic.alibabacloud.com!