Yii中表單用法實(shí)例詳解
本文實(shí)例講述了Yii中表單用法。分享給大家供大家參考,具體如下:
在 Yii 中處理表單時(shí),通常需要以下步驟:
1. 創(chuàng)建用于表現(xiàn)所要收集數(shù)據(jù)字段的模型類。
2. 創(chuàng)建一個(gè)控制器動(dòng)作,響應(yīng)表單提交。
3. 在視圖腳本中創(chuàng)建與控制器動(dòng)作相關(guān)的表單。
一、創(chuàng)建模型
在編寫表單所需的 HTML 代碼之前,我們應(yīng)該先確定來(lái)自最終用戶輸入的數(shù)據(jù)的類型,以及這些數(shù)據(jù)應(yīng)符合什么樣的規(guī)則。模型類可用于記錄這些信息。正如模型章節(jié)所定義的,模型是保存用戶輸入和驗(yàn)證這些輸入的中心位置。
取決于使用用戶所輸入數(shù)據(jù)的方式,我們可以創(chuàng)建兩種類型的模型。如果用戶輸入被收集、使用然后丟棄,我們應(yīng)該創(chuàng)建一個(gè)表單模型;
如果用戶的輸入被收集后要保存到數(shù)據(jù)庫(kù),我們應(yīng)使用一個(gè)Active Record。兩種類型的模型共享同樣的基類 CModel,它定義了表單所需的通用接口。
1、定義模型類
例如創(chuàng)建為一個(gè)表單模型:
class LoginForm extends CFormModel { public $username; public $password; public $rememberMe=false; }
LoginForm中定義了三個(gè)屬性: $username, $password 和$rememberMe。他們用于保存用戶輸入的用戶名和密碼,還有用戶是否想記住他的登錄的選項(xiàng)。由于 $rememberMe 有一個(gè)默認(rèn)的值false,相應(yīng)的選項(xiàng)在初始化顯示在登錄表單中時(shí)將是未勾選狀態(tài)。
我們將這些成員變量稱為特性(attributes)而不是屬性(properties),以區(qū)別于普通的屬性(properties)。特性(attribute)是一個(gè)主要用于存儲(chǔ)來(lái)自用戶輸入或數(shù)據(jù)庫(kù)數(shù)據(jù)的屬性(propertiy)。
2、聲明驗(yàn)證規(guī)則
一旦用戶提交了他的輸入,模型被填充,我們就需要在使用前確保用戶的輸入是有效的。這是通過(guò)將用戶的輸入和一系列規(guī)則執(zhí)行驗(yàn)證實(shí)現(xiàn)的。我們?cè)?rules() 方法中指定這些驗(yàn)證規(guī)則,此方法應(yīng)返回一個(gè)規(guī)則配置數(shù)組。
class LoginForm extends CFormModel { public $username; public $password; public $rememberMe=false; private $_identity; public function rules() { return array( array('username, password', 'required'), //username 和 password 為必填項(xiàng) array('rememberMe', 'boolean'), //rememberMe 應(yīng)該是一個(gè)布爾值 array('password', 'authenticate'), //password 應(yīng)被驗(yàn)證(authenticated) ); } public function authenticate($attribute,$params) { $this->_identity=new UserIdentity($this->username,$this->password); if(!$this->_identity->authenticate()) $this->addError('password','錯(cuò)誤的用戶名或密碼。'); } }
rules() 返回的每個(gè)規(guī)則必須是以下格式:
其中:
AttributeList(特性列表)是需要通過(guò)此規(guī)則驗(yàn)證的特性列表字符串,每個(gè)特性名字由逗號(hào)分隔;
Validator(驗(yàn)證器) 指定要執(zhí)行驗(yàn)證的種類;
on 參數(shù)是可選的,它指定此規(guī)則應(yīng)被應(yīng)用到的場(chǎng)景列表;
附加選項(xiàng) 是一個(gè)名值對(duì)數(shù)組,用于初始化相應(yīng)驗(yàn)證器的屬性值。
有三種方式可在驗(yàn)證規(guī)則中指定 Validator:
第一, Validator 可以是模型類中一個(gè)方法的名字,就像上面示例中的 authenticate 。驗(yàn)證方法必須是下面的結(jié)構(gòu):
第二,Validator可以是一個(gè)驗(yàn)證器類的名字,當(dāng)此規(guī)則被應(yīng)用時(shí),一個(gè)驗(yàn)證器類的實(shí)例將被創(chuàng)建以執(zhí)行實(shí)際驗(yàn)證。規(guī)則中的附加選項(xiàng)用于初始化實(shí)例的屬性值。驗(yàn)證器類必須繼承自 CValidator。
第三,Validator 可以是一個(gè)預(yù)定義的驗(yàn)證器類的別名。在上面的例子中,required 名字是 CRequiredValidator 的別名,它用于確保所驗(yàn)證的特性值不為空。下面是預(yù)定義的驗(yàn)證器別名的完整列表:
boolean: CBooleanValidator 的別名,確保特性有一個(gè) CBooleanValidator::trueva lue 或 CBooleanValidator::falseva lue 值。
captcha: CCaptchaValidator 的別名,確保特性值等于 CAPTCHA 中顯示的驗(yàn)證碼。
compare: CCompareva lidator 的別名,確保特性等于另一個(gè)特性或常量。
email: CEmailValidator 的別名,確保特性是一個(gè)有效的Email地址。
default: CDefaultValueva lidator 的別名,指定特性的默認(rèn)值。
exist: CExistValidator 的別名,確保特性值可以在指定表的列中可以找到。
file: CFileva lidator 的別名,確保特性含有一個(gè)上傳文件的名字。
filter: CFilterValidator 的別名,通過(guò)一個(gè)過(guò)濾器改變此特性。
in: CRangeva lidator 的別名,確保數(shù)據(jù)在一個(gè)預(yù)先指定的值的范圍之內(nèi)。
length: CStringValidator 的別名,確保數(shù)據(jù)的長(zhǎng)度在一個(gè)指定的范圍之內(nèi)。
match: CRegularExpressionValidator 的別名,確保數(shù)據(jù)可以匹配一個(gè)正則表達(dá)式。
numerical: CNumberValidator 的別名,確保數(shù)據(jù)是一個(gè)有效的數(shù)字。
required: CRequiredValidator 的別名,確保特性不為空。
type: CTypeva lidator 的別名,確保特性是指定的數(shù)據(jù)類型。
unique: CUniqueva lidator 的別名,確保數(shù)據(jù)在數(shù)據(jù)表的列中是唯一的。
url: CUrlValidator 的別名,確保數(shù)據(jù)是一個(gè)有效的 URL。
下面我們列出了幾個(gè)只用這些預(yù)定義驗(yàn)證器的示例:
// 用戶名為必填項(xiàng) array('username', 'required'), // 用戶名必須在 3 到 12 個(gè)字符之間 array('username', 'length', 'min'=>3, 'max'=>12), // 在注冊(cè)場(chǎng)景中,密碼password必須和password2一致。 array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'), // 在登錄場(chǎng)景中,密碼必須接受驗(yàn)證。 array('password', 'authenticate', 'on'=>'login'),
3、安全的特性賦值
在一個(gè)類的實(shí)例被創(chuàng)建后,我們通常需要用最終用戶提交的數(shù)據(jù)填充它的特性。這可以通過(guò)如下塊賦值(massive assignment)方式輕松實(shí)現(xiàn):
$model=new LoginForm; if(isset($_POST['LoginForm'])) $model->attributes=$_POST['LoginForm'];
最后的表達(dá)式被稱作 塊賦值(massive assignment) ,它將 $_POST['LoginForm'] 中的每一項(xiàng)復(fù)制到相應(yīng)的模型特性中。這相當(dāng)于如下賦值方法:
foreach($_POST['LoginForm'] as $name=>$value) { if($name 是一個(gè)安全的特性) $model->$name=$value; }
檢測(cè)特性的安全非常重要,例如,如果我們以為一個(gè)表的主鍵是安全的而暴露了它,那么攻擊者可能就獲得了一個(gè)修改記錄的主鍵的機(jī)會(huì),從而篡改未授權(quán)給他的內(nèi)容。
特性如果出現(xiàn)在相應(yīng)場(chǎng)景的一個(gè)驗(yàn)證規(guī)則中,即被認(rèn)為是安全的。例如:
array('username, password', 'required', 'on'=>'login, register'), array('email', 'required', 'on'=>'register'),
如上所示, username 和 password 特性在 login 場(chǎng)景中是必填項(xiàng)。而 username, password 和 email特性在 register 場(chǎng)景中是必填項(xiàng)。于是,如果我們?cè)?login 場(chǎng)景中執(zhí)行塊賦值,就只有 username 和 password會(huì)被塊賦值。因?yàn)橹挥兴鼈兂霈F(xiàn)在 login 的驗(yàn)證規(guī)則中。另一方面,如果場(chǎng)景是 register ,這三個(gè)特性就都可以被塊賦值。
// 在登錄場(chǎng)景中 $model=new User('login'); if(isset($_POST['User'])) $model->attributes=$_POST['User']; // 在注冊(cè)場(chǎng)景中 $model=new User('register'); if(isset($_POST['User'])) $model->attributes=$_POST['User'];
那么為什么我們使用這樣一種策略來(lái)檢測(cè)特性是否安全呢?背后的基本原理就是:如果一個(gè)特性已經(jīng)有了一個(gè)或多個(gè)可檢測(cè)有效性的驗(yàn)證規(guī)則,那我們還擔(dān)心什么呢?
請(qǐng)記住,驗(yàn)證規(guī)則是用于檢查用戶輸入的數(shù)據(jù),而不是檢查我們?cè)诖a中生成的數(shù)據(jù)(例如時(shí)間戳,自動(dòng)產(chǎn)生的主鍵)。因此,不要為那些不接受最終用戶輸入的特性添加驗(yàn)證規(guī)則。
有時(shí)候,我們想聲明一個(gè)特性是安全的,即使我們沒(méi)有為它指定任何規(guī)則。例如,一篇文章的內(nèi)容可以接受用戶的任何輸入。我們可以使用特殊的 safe 規(guī)則實(shí)現(xiàn)此目的:
還有一個(gè)用于聲明一個(gè)屬性為不安全的 unsafe 規(guī)則:
unsafe 規(guī)則并不常用,它是我們之前定義的安全特性的一個(gè)例外。
4、觸發(fā)驗(yàn)證
一旦模型被用戶提交的數(shù)據(jù)填充,我們就可以調(diào)用 CModel::validate() 觸發(fā)數(shù)據(jù)驗(yàn)證進(jìn)程。此方法返回一個(gè)指示驗(yàn)證是否成功的值。對(duì)CActiveRecord 模型來(lái)說(shuō),驗(yàn)證也可以在我們調(diào)用其 CActiveRecord::save() 方法時(shí)自動(dòng)觸發(fā)。
我們可以通過(guò)設(shè)置scenario屬性來(lái)設(shè)置場(chǎng)景屬性,這樣,相應(yīng)場(chǎng)景的驗(yàn)證規(guī)則就會(huì)被應(yīng)用。
驗(yàn)證是基于場(chǎng)景執(zhí)行的。 scenario屬性指定了模型當(dāng)前用于的場(chǎng)景和當(dāng)前使用的驗(yàn)證規(guī)則集。例如,在 login 場(chǎng)景中,我們只想驗(yàn)證用戶模型中的username 和 password 輸入;而在 register 場(chǎng)景中,我們需要驗(yàn)證更多的輸入,例如 email, address,等。下面的例子演示了如何在 register 場(chǎng)景中執(zhí)行驗(yàn)證:
// 在注冊(cè)場(chǎng)景中創(chuàng)建一個(gè) User 模型。等價(jià)于: // $model=new User; // $model->scenario='register'; $model=new User('register'); //給模型類添加參數(shù),該參數(shù)就是要觸發(fā)的驗(yàn)證場(chǎng)景 // 將輸入的值填充到模型 $model->attributes=$_POST['User']; // 執(zhí)行驗(yàn)證 if($model->validate()) // 如果輸入有效 ... else ...
規(guī)則關(guān)聯(lián)的場(chǎng)景可以通過(guò)規(guī)則中的 on 選項(xiàng)指定。如果 on 選項(xiàng)未設(shè)置,則此規(guī)則會(huì)應(yīng)用于所有場(chǎng)景。例如:
public function rules() { return array( array('username, password', 'required'), array('password_repeat', 'required', 'on'=>'register'), array('password', 'compare', 'on'=>'register'), ); }
第一個(gè)規(guī)則將應(yīng)用于所有場(chǎng)景,而第二個(gè)將只會(huì)應(yīng)用于 register 場(chǎng)景。
5、提取驗(yàn)證錯(cuò)誤
驗(yàn)證完成后,任何可能產(chǎn)生的錯(cuò)誤將被存儲(chǔ)在模型對(duì)象中。我們可以通過(guò)調(diào)用 CModel::getErrors()和CModel::getError() 提取這些錯(cuò)誤信息。這兩個(gè)方法的不同點(diǎn)在于第一個(gè)方法將返回所有 模型特性的錯(cuò)誤信息,而第二個(gè)將只返回第一個(gè) 錯(cuò)誤信息。
6、特性標(biāo)簽
當(dāng)設(shè)計(jì)表單時(shí),我們通常需要為每個(gè)表單域顯示一個(gè)標(biāo)簽。標(biāo)簽告訴用戶他應(yīng)該在此表單域中填寫什么樣的信息。雖然我們可以在視圖中硬編碼一個(gè)標(biāo)簽,但如果我們?cè)谙鄳?yīng)的模型中指定(標(biāo)簽),則會(huì)更加靈活方便。
默認(rèn)情況下 CModel 將簡(jiǎn)單的返回特性的名字作為其標(biāo)簽。這可以通過(guò)覆蓋 attributeLabels() 方法自定義。正如在接下來(lái)的小節(jié)中我們將看到的,在模型中指定標(biāo)簽會(huì)使我們能夠更快的創(chuàng)建出更強(qiáng)大的表單。
二、創(chuàng)建動(dòng)作
有了模型,我們就可以開始編寫用于操作此模型的邏輯了。我們將此邏輯放在一個(gè)控制器的動(dòng)作中。對(duì)登錄表單的例子來(lái)講,相應(yīng)的代碼就是:
public function actionLogin() { $model=new LoginForm; if(isset($_POST['LoginForm'])) { // 收集用戶輸入的數(shù)據(jù) $model->attributes=$_POST['LoginForm']; // 驗(yàn)證用戶輸入,并在判斷輸入正確后重定向到前一頁(yè) if($model->validate()) $this->redirect(Yii::app()->user->returnUrl); //重定向到之前需要身份驗(yàn)證的頁(yè)面URL } // 顯示登錄表單 $this->render('login',array('model'=>$model)); }
如上所示,我們首先創(chuàng)建了一個(gè) LoginForm 模型示例;如果請(qǐng)求是一個(gè) POST 請(qǐng)求(意味著這個(gè)登錄表單被提交了),我們則使用提交的數(shù)據(jù)$_POST['LoginForm'] 填充 $model;然后我們驗(yàn)證此輸入,如果驗(yàn)證成功,重定向用戶瀏覽器到之前需要身份驗(yàn)證的頁(yè)面。如果驗(yàn)證失敗,或者此動(dòng)作被初次訪問(wèn),我們則渲染 login視圖,此視圖的內(nèi)容將在后續(xù)章節(jié)中講解。
提示: 在 login 動(dòng)作中,我們使用Yii::app()->user->returnUrl 獲取之前需要身份驗(yàn)證的頁(yè)面URL。 組件Yii::app()->user 是一種 CWebUser (或其子類) ,它表示用戶會(huì)話信息(例如用戶名,狀態(tài))。
讓我們特別留意一下 login 動(dòng)作中出現(xiàn)的下面的 PHP 語(yǔ)句:
正如我們?cè)?安全的特性賦值 中所講的,這行代碼使用用戶提交的數(shù)據(jù)填充模型。 attributes 屬性由 CModel定義,它接受一個(gè)名值對(duì)數(shù)組并將其中的每個(gè)值賦給相應(yīng)的模型特性。因此如果 $_POST['LoginForm']給了我們這樣的一個(gè)數(shù)組,上面的那段代碼也就等同于下面冗長(zhǎng)的這段 (假設(shè)數(shù)組中存在所有所需的特性):
$model->username=$_POST['LoginForm']['username']; $model->password=$_POST['LoginForm']['password']; $model->rememberMe=$_POST['LoginForm']['rememberMe'];
注意: 為了使 $_POST['LoginForm'] 傳遞給我們的是一個(gè)數(shù)組而不是字符串,我們需要在命名表單域時(shí)遵守一個(gè)規(guī)范。具體的,對(duì)應(yīng)于模型類 C 中的特性 a 的表單域,我們將其命名為 C[a] 。例如,我們可使用LoginForm[username] 命名 username 特性相應(yīng)的表單域。
現(xiàn)在剩下的工作就是創(chuàng)建 login 視圖了,它應(yīng)該包含一個(gè)帶有所需輸入項(xiàng)的 HTML 表單。
三、創(chuàng)建表單
編寫 login 視圖是很簡(jiǎn)單的,我們以一個(gè) form 標(biāo)記開始,它的 action 屬性應(yīng)該是前面講述的 login動(dòng)作的URL。然后我們需要為 LoginForm類中聲明的屬性插入標(biāo)簽和表單域。最后,我們插入一個(gè)可由用戶點(diǎn)擊提交此表單的提交按鈕。所有這些都可以用純HTML代碼完成。
Yii 提供了幾個(gè)助手(helper)類簡(jiǎn)化視圖編寫。例如,要?jiǎng)?chuàng)建一個(gè)文本輸入域,我們可以調(diào)用 CHtml::textField();要?jiǎng)?chuàng)建一個(gè)下拉列表,則調(diào)用 CHtml::dropDownList()。
例如, 如下代碼將生成一個(gè)文本輸入域,它可以在用戶修改了其值時(shí)觸發(fā)表單提交動(dòng)作。
下面,我們使用 CHtml 創(chuàng)建一個(gè)登錄表單。我們假設(shè)變量 $model 是 LoginForm 的實(shí)例。
上述代碼生成了一個(gè)更加動(dòng)態(tài)的表單,例如, CHtml::activeLabel()生成一個(gè)與指定模型的特性相關(guān)的標(biāo)簽。如果此特性有一個(gè)輸入錯(cuò)誤,此標(biāo)簽的CSS class 將變?yōu)?error,通過(guò) CSS樣式改變了標(biāo)簽的外觀。相似的, CHtml::activeTextField() 為指定模型的特性生成一個(gè)文本輸入域,并會(huì)在錯(cuò)誤發(fā)生時(shí)改變它的CSS class。
我們還可以使用一個(gè)新的小物件 CActiveForm 以簡(jiǎn)化表單創(chuàng)建。這個(gè)小物件可同時(shí)提供客戶端及服務(wù)器端無(wú)縫的、一致的驗(yàn)證。使用 CActiveForm, 上面的代碼可重寫為:
beginWidget('CActiveForm'); ?> errorSummary($model); ?> label($model,'username'); ?> textField($model,'username') ?> label($model,'password'); ?> passwordField($model,'password') ?> checkBox($model,'rememberMe'); ?> label($model,'rememberMe'); ?> endWidget(); ?>
四、收集表格輸入
有時(shí)我們想通過(guò)批量模式收集用戶輸入。也就是說(shuō),用戶可以為多個(gè)模型實(shí)例輸入信息并將它們一次性提交。我們將此稱為 表格輸入(tabular input) ,因?yàn)檫@些輸入項(xiàng)通常以 HTML 表格的形式呈現(xiàn)。
要使用表格輸入,我們首先需要?jiǎng)?chuàng)建或填充一個(gè)模型實(shí)例數(shù)組,取決于我們是想插入還是更新數(shù)據(jù)。然后我們從 $_POST變量中提取用戶輸入的數(shù)據(jù)并將其賦值到每個(gè)模型。和單模型輸入稍有不同的一點(diǎn)就是:我們要使用 $_POST['ModelClass'][$i]提取輸入的數(shù)據(jù)而不是使用 $_POST['ModelClass']。
public function actionBatchUpdate() { // 假設(shè)每一項(xiàng)(item)是一個(gè) 'Item' 類的實(shí)例, // 提取要通過(guò)批量模式更新的項(xiàng) $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) // 如果所有項(xiàng)目有效 // ...則在此處做一些操作 } // 顯示視圖收集表格輸入 $this->render('batchUpdate',array('items'=>$items)); }
準(zhǔn)備好了這個(gè)動(dòng)作,我們需要繼續(xù) batchUpdate 視圖的工作以在一個(gè) HTML 表格中顯示輸入項(xiàng)。
NamePriceCount Description $item): ?>
注意,在上面的代碼中我們使用了 "[$i]name" 而不是 "name" 作為調(diào)用 CHtml::activeTextField 時(shí)的第二個(gè)參數(shù)。
如果有任何驗(yàn)證錯(cuò)誤,相應(yīng)的輸入項(xiàng)將會(huì)自動(dòng)高亮顯示,就像前面我們講解的單模型輸入一樣。
希望本文所述對(duì)大家基于Yii框架的PHP程序設(shè)計(jì)有所幫助。
相關(guān)文章
PHP文件上傳、客戶端和服務(wù)器端加限制、抓取錯(cuò)誤信息、完整步驟解析
文件上傳分為兩個(gè)部分,HTML顯示部分和PHP處理部分。這篇文章主要介紹了PHP文件上傳、客戶端和服務(wù)器端加限制、抓取錯(cuò)誤信息、完整步驟解析,需要的朋友參考下吧2017-01-01php實(shí)現(xiàn)當(dāng)前頁(yè)面點(diǎn)擊下載文件的實(shí)例代碼
下面小編就為大家?guī)?lái)一篇php實(shí)現(xiàn)當(dāng)前頁(yè)面點(diǎn)擊下載文件的實(shí)例代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11thinkPHP框架對(duì)接支付寶即時(shí)到賬接口回調(diào)操作示例
這篇文章主要介紹了thinkPHP框架對(duì)接支付寶即時(shí)到賬接口回調(diào)操作,結(jié)合實(shí)例形式分析了thinkPHP針對(duì)支付寶接口回調(diào)操作的原理與具體操作步驟,需要的朋友可以參考下2016-11-11php中文驗(yàn)證碼實(shí)現(xiàn)示例分享
這篇文章主要介紹了使用php實(shí)現(xiàn)中文驗(yàn)證碼,代碼簡(jiǎn)單,大家可以直接使用2014-01-01php中的雙引號(hào)與單引號(hào)的基本使用及區(qū)別
字符串是一個(gè)非常要的知識(shí),在開發(fā)中,有的使用單引號(hào),有的使用雙引號(hào),這個(gè)是有區(qū)別的,這篇文章主要介紹了php中的雙引號(hào)與單引號(hào)的基本使用,需要的朋友可以參考下2023-06-06Laravel創(chuàng)建數(shù)據(jù)庫(kù)表結(jié)構(gòu)的例子
今天小編就為大家分享一篇Laravel創(chuàng)建數(shù)據(jù)庫(kù)表結(jié)構(gòu)的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-10-10PHP 中提示undefined index如何解決(多種方法)
這篇文章主要介紹了PHP 中提示undefined index如何解決(多種方法)的相關(guān)資料,需要的朋友可以參考下2016-03-03