CActiveForm講解javascript
CActiveForm提供了一些方法,這些方法可以方便的去建立一個與數據模型相關聯的Form表單。CActiveForm繼承自CWidget,因此他須要實現CWidget的init() 和 run() 方法,同時它也實現了一些本身的封裝方法。CActiveForm很重要的一個特性就是它支持Ajax校驗。咱們能夠設置CActiveForm的enableAjaxValidation屬性爲ture來啓動Ajax校驗。例如,當用戶在input框中輸入一些值後就會觸發Ajax校驗。CActiveForm會向服務器提交Ajax請求,用來校驗用戶當前輸入的值。服務器的校驗通常是調用模型類Model的validate()方法。若是校驗失敗,相對應的錯誤信息將會被返回並顯示給用戶。即便用戶在瀏覽器禁用javascript,他也會經過整個頁面的提交自動回滾到傳統的頁面驗證。php
在客戶端,Yii認爲input框能夠存在四個狀態:初始化,校驗,錯誤和成功。爲了區分這些狀態,CActiveForm自動指定了不一樣的CSS樣式給包含此input框的HTML
element。默認狀況下,這些CSS樣式類的名字爲:validating,error,success。固然咱們可使用CActiveForm的options屬性去自定義他們。html
CActiveForm的提交和校驗是基於Ajax模式的。若是你的Form表單中有很大量的數據須要提交,那麼這種Ajax模式的提交可能就不那麼好了。這種狀況下,你能夠設計本身輕量級的Ajax校驗。使用Yii對JQuery的支持?java
使用CActiveForm來作Ajax校驗,咱們須要使用兩個JS庫:jquery.js和jquery.yiiactiveform.js。他們的位置在工程根目錄下:assets\5ce53e17\文件夾中。不用擔憂,這些JS庫Yii會自動發佈到你的工程中。雖然這些動做Yii會悄悄的作,當你必須知道。jquery
首先咱們來看咱們的模型類,這裏咱們使用CFormModel:ios
1 class LoginForm extends CFormModel 2 { 3 public $username; 4 public $password; 5 public function rules() 6 { 7 return array( 8 array('username, password', 'required'), 9 array('username', 'authenticate'), 10 ); 11 } 12 public function authenticate($attribute,$params) 13 { 14 if($this->username=='admin') 15 $this->addError('username','can not login with admin!'); 16 } 17 }
咱們的模型類很是簡單,只有username和passsword兩個屬性。username的校驗規則是不爲空,且不能是「admin」,而password的校驗規則只是不爲空。注意,當咱們檢查到用戶輸入的username的值爲「admin」時候,校驗失敗,咱們添加錯誤信息爲「can
not login with admin」,這段信息會在頁面中的Yii提供的error元素中輸出。ajax
咱們能夠在rules方法中指定任何一條驗證規則的錯誤信息,咱們須要使用message屬性。例如:array(‘username’, ‘required’,'message’=>’not
null’),當‘username’的內容爲空的時候,咱們會使用message指定的內容在頁面上顯示錯誤信息。固然咱們可使用中文,若是出現亂碼,能夠這樣設置:array(‘username’,
‘required’,'message’=>iconv(「gb2312″,」utf-8″,」不能爲空「))數據庫
你將main.php裏的app配置加上language=>’zh_cn’,系統默認的提示就是中文的了!數組
其餘驗證規則案例:瀏覽器
array(‘title, content,
status’, ‘required’),
array(‘title’, ‘length’,
‘max’=>128),
array(‘status’, ‘in’,
‘range’=>array(0, 1, 2)),
array(‘tags’, ‘match’,
‘pattern’=>’/^[\w\s,]+$/’,'message’=>’Tags can only contain word
characters.’),
咱們的頁面代碼以下:
1 <div class="form"> 2 <?php $form=$this->beginWidget('CActiveForm', 3 array('id'=>'login-form','enableAjaxValidation'=>true,'action'=>array('site/login'))); ?> 4 <div class="row"> 5 <?php echo $form->labelEx($model,'username'); ?> 6 <?php echo $form->textField($model,'username'); ?> 7 <?php echo $form->error($model,'username'); ?> 8 </div> 9 <div class="row"> 10 <?php echo $form->labelEx($model,'password'); ?> 11 <?php echo $form->passwordField($model,'password'); ?> 12 <?php echo $form->error($model,'password'); ?> 13 </div> 14 <div class="row submit"> 15 <?php echo CHtml::submitButton('Login'); ?> 16 </div> 17 <?php $this->endWidget(); ?> 18 </div>
對於每個模型屬性的頁面表示來講,咱們都會有一個Label來講明其屬性名,還有一個input框用來輸入該屬性值,最後有個error元素來顯示校驗失敗時的錯誤信息。Yii對Form及其子元素封裝的太多,咱們將以上php代碼翻譯成靜態頁面爲:
1 <div class="form"> 2 <form id="login-form" action="/validator/index.php?r=site/login" method="post"> 3 <div class="row"> 4 <label for="LoginForm_username" class="required">Username 5 <span class="required">*</span></label> 6 <input name="LoginForm[username]" id="LoginForm_username" type="text" value="" /> 7 <div id="LoginForm_username_em_" class="errorMessage" style="display:none"></div> 8 </div> 9 <div class="row"> 10 <label for="LoginForm_password" class="required">Password 11 <span class="required">*</span></label> 12 <input name="LoginForm[password]" id="LoginForm_password" type="password" value="" /> 13 <div id="LoginForm_password_em_" class="errorMessage" style="display:none"></div> 14 </div> 15 <div class="row submit"> 16 <input type="submit" name="yt0" value="Login" /> 17 </div> 18 </form> 19 </div>
Yii的Ajax的校驗效果是經過CSS來實現的,上文提到一個input框能夠存在四個狀態:初始化,校驗,錯誤和成功。每一個狀態對應不一樣CSS樣式類。初始化和校驗這兩個狀態咱們不須要關心,咱們只注重用戶校驗失敗和成功時,該input框的CSS樣式。此外當校驗失敗的時候,咱們還要定義錯誤信息的樣式,從翻譯過來的靜態文原本來,咱們須要定義errorMessage類。如下是個人CSS類:
/*標籤是否換行*/
.form label {
font-size:12px; display:block; }
/*屬性是否必填項,客戶端根據model的rule方法而定*/
.form span.required {
color:red; }
/*校驗出錯時標籤CSS樣式*/
.form .error label {
color:#FFCC33; }
/*校驗出錯時輸入框的CSS樣式*/
.form .error input {
background:#FEE; border-color:#C00; }
/*校驗出錯時錯誤信息的CSS樣式,咱們能夠設置其display屬性讓其不換行。*/
.form .errorMessage {
display:inline; color:red; font-size:12px; }
/*校驗成功時標籤CSS樣式*/
.form .success label {
color:#000000; }
/*校驗成功時輸入框的CSS樣式*/
.form .success input {
background:#E6EFC2; border-color:#C6D880; }
以上的CSS註釋已經很詳細了,咱們來看看校驗流程,首先咱們須要先渲染咱們的頁面:
$model = new LoginForm;
$this->render(‘index’,array(‘model’=>$model));
注意,這裏咱們必須使用render()方法對其進行渲染。
咱們的actionLogin以下:
public function actionLogin() { $model = new LoginForm; //ajax validate if(isset($_POST['ajax']) && $_POST['ajax']==='login-form') { echo CActiveForm::validate($model); Yii::app()->end(); } //submit handle and validate if(isset($_POST['LoginForm'])) { $model->attributes = $_POST['LoginForm']; if($model->validate()){ //no business logic handle $this->renderPartial('success'); Yii::app()->end(); } } $this->render('index',array('model'=>$model)); }
當input框失去焦點的時候,頁面會向服務器提交Ajax請求,服務器端就會根據模型類LoginForm中定義的校驗規則就其就行驗證。若是校驗成功,則input框會按指定的success樣式類去顯示,若是校驗失敗,則input框會按指定的error樣式類去顯示,同時還會按照errorMessage指定的樣式類顯示錯誤信息。
須要注意的是,若是咱們對用戶輸入的信息進行了校驗,並且有可能校驗失敗,可是用戶在校驗失敗的狀況下,仍然能夠提交Form表單。因此當用戶提交Form表單的處理代碼中,咱們仍須要對用戶的輸入進行校驗。
CActiveForm其餘組件的使用
1. textArea
這個組件沒有太多講的,主要注意行列的屬性配置,使用代碼:
<?php echo
$form->textArea($model,’textArea’,array(‘rows’=>10,’cols’=>50)); ?>
2. fileField
雖然Yii封裝了這個組件,可是它並無作更多的支持,它的上傳須要更多的配置,它也不支持Ajax校驗。使用代碼:
<?php echo $form->fileField($model,’fileField’);
?>
3. radioButtonList
這是一個radio集合組件。使用代碼:
<?php echo
$form->radioButtonList($model,’radioButtonList’,
array(’1′=>’Male’,’0′=>’Female’),
array(‘separator’=>’ ’,'labelOptions’=>array(‘class’=>’radiolabel’))
)?>
Yii框架封裝的元素集合組件大體爲4個參數:
$model,$property,$data,$htmlOptios
前面兩個參數是咱們關聯模型類和指定的屬性。第三個參數是一個數組,他是元素集合組件的數據來源,上面的代碼中配置了兩個數組元素,則會對應生成兩個radio,radio的值爲1或者0,radio的標籤爲Male或者Female。Yii默認將兩個radio之間使用<br/>間隔,即兩個radio不在同一行上,咱們可使用separator屬性更改其間隔方式,這裏咱們使用空格符來間隔兩個radio,這樣他們顯示在同一行上。另外在同一個radio中,其標籤和實體也是換行的,緣由在於標籤<label>會換行,咱們能夠給label標籤添加CSS樣式,改變其display值爲inline將其與radio實體排列在一行。
radioButtonList對應模型類中的屬性值不是數組,只是一個單一數值或者字符而已,雖然他是一個集合組件,可是他是單選的,因此最終只有一個單一值提交服務器端。
另外值得注意的是,Yii封裝的這些組件的初始值不可以在標籤中設置,Yii自動會從模型類中讀取屬性值,而後在組件上顯示出來。因此,若是你想在頁面渲染前初始化一些組件的默認值,那麼你能夠直接初始化模型類就能夠了。
4. checkBoxList
這是一個checkBox集合組件,使用代碼:
<?php echo $form->checkBoxList($model,’checkBoxList’, array(’1′=>’Football’,’2′=>’Music’,’3′=>’Game’,’4′=>’basketball’), array(‘separator’=>’ ’,'labelOptions’=>array(‘class’=>’checkboxlabel’)) )?>
這個組件同上,惟一不一樣的是這個組件是多選的,因此他對應的模型類的屬性應該是一個數組。這個組件將你選中的每一個checkBox的值構形成一個數組提交服務器端。例如咱們選中了Football和Game,那個該組件構造的數組將是array(‘1’,’3’),沒有選中的checkBox不會被構造進這個數組中。反之從服務器段讀取數組,而後顯示該組件也是一樣的道理。
5. listBox
本質上它是一個select,可是它會顯示全部的option。使用代碼以下:
<?php echo $form->listBox($model,’listBox’, array(’1′=>’Football’,’2′=>’Music’,’3′=>’Game’,’4′=>’basketball’), array(‘size’=>8,’multiple’=>false,’class’=>’listbox’) )?>
須要說明的屬性‘size’表示該select的大小,雖然我只定義了4個option,可是我仍然想讓它佔據8個option的高度。屬性multiple爲是否多選。屬性class爲select的CSS樣式類,可是貌似不起做用。在須要說明的一點是,雖然它能夠單選和多選,可是他對應的模型類的屬性始終是一個數組。
6. dropDownList
本質上它是一個真正意義上select,由於他不會顯示全部的option,使用代碼以下:
1 <?php 2 3 $models = 4 person::model()->findAll(array(‘order’=>’age’)); 5 6 $list = CHtml::listData($models,’id’,'username’); 7 8 echo $form->dropDownList($model,’dropDownList’,$list,array(‘empty’=>’Select 9 a user’) 10 11 )?>
這個組件的使用跟select差很少,對應模型層的屬性是一個單一數值或者字符,而不是數組。屬性empty指定了select的第一個option,至關於初始化值。
這裏咱們須要說明的是以上這些集合組件的數據來源。本質上其實咱們就是查詢數據庫,將結果集封裝成一個數組,其實查詢數據結果集原本就是一個數組。這裏咱們使用AR類person按年齡查詢全部的記錄,而後使用CHtml的listData方法將查詢記錄中的id字段和username字段構形成一個簡單的數組$list,而後咱們只須要在dropDownList的標籤配置中應用便可。
最後咱們介紹一下服務器端獲取頁面數據,由於咱們已經將模型類和咱們的頁面標籤相關聯,因此使用標籤顯示模型類屬性或者從顯示標籤中獲取模型類屬性是十分簡單的。在服務器端咱們獲取頁面數據的時候,可使用以下代碼:
$model = new Form; $model->attributes = $_POST['Form'];
以上代碼會將用戶提交的數據自動填充到模型類的屬性中,這個方式稱爲安全特性分配。首先咱們的頁面中必須已經將標籤和模型類Form關聯。須要注意的是$_POST的參數就是模型類的名稱Form,而不是標籤名稱。最重要的問題在於咱們模型類中的屬性必須是安全的,不然咱們的安全特性分配將會失敗。指定模型類中的屬性爲安全的是經過實現模型類中的
Rules方法,即校驗規則方法。咱們能夠直接將模型類的指定屬性指定爲」safe」或者指定其餘校驗規則,由於Yii由於若是一個屬性經過某個校驗後它就能夠被認爲是安全的了。
public function rules() { return array( array(‘property’,'safe’) ); }
CactiveDataProvider講解
CactiveDataProvider是基於ActiveRecord的一個數據提供者,同時它也繼承自CDataProvider。它提供了ActiveRecord對象的集合。咱們可使用「modelClass」屬性指定CactiveDataProvider所要提供的ActiveRecord對象的類型。CactiveDataProvider可使用AR方法CActiveRecord::findAll從數據庫中檢索信息。它還可使用criteria來指定查詢條件,排序以及分頁等等。
CActiveDataProvider的時候方法以下:
$dataProvider=new CActiveDataProvider('Post', array( 'criteria'=>array( 'condition'=>'status=1 AND tags LIKE :tags', 'params'=>array(':tags'=>$_GET['tags']), 'with'=>array('author'), ), 'pagination'=>array( 'pageSize'=>20, 'currentPage'=>0, ), ));
在Yii的blog案例中,很不少地方用到了CactiveDataProvider,尤爲是在讀取不少數據且須要分頁的狀況下,CactiveDataProvider是很出色的。CactiveDataProvider只是一個數據的集合,並非一個顯示組件,因此在blog案例中,它是和CGridView一塊兒使用的,CGridView確切的說是一個使用表格顯示數據的widget。其實包含了不少的封裝,在這裏咱們不是用CGridView,只使用CActiveDataProvider來進行分頁查詢。使用CActiveDataProvider進行分頁查詢最重要的是「currentPage」屬性,默認它是0。
在以上的CActiveDataProvider使用代碼中,咱們配置了它的兩個屬性:criteria和pagination。
Criteria屬性值就是CDbCriteria類的實例,而pagination值並不是一個CPagination類的實例,而是一個數組而已。實例化CPagination類須要表中記錄總數做爲參數。
如下是我action的代碼:
public function actionPage() { $currentPage = 0; $pageSize = 5; if(isset($_GET['id'])){ $currentPage = $_GET['id']; } $criteria = new CDbCriteria(array('order'=>'age desc',)); $pagination = array('currentPage'=>$currentPage,'pageSize'=>$pageSize,); $dataProvider = new CActiveDataProvider('person',array('pagination'=>$pagination,'criteria'=>$criteria,)); $totalItemCount = $dataProvider->getTotalItemCount(); $pageCount = ceil($totalItemCount/$pageSize); $itemCount = $dataProvider->getItemCount(); $page = array('totalItemCount'=>$totalItemCount, 'pageCount'=>$pageCount,'itemCount'=>$itemCount,'currentPage'=>$currentPage,); $data = $dataProvider->getData(); $this->render('all',array('data'=>$data,'page'=>$page,)); }
以上代碼咱們將數據信息data和分頁信息page分開存放,並傳遞到被渲染的頁面。上文提到了「currentPage」,實際上是CPagination類的一個屬性,它默認是從0開始的,即0表明第一頁。在個人代碼中,我將pageSize設置成5,即每頁顯示5條信息。CDbCriteria類能夠幫助咱們進行復雜的數據庫查詢,並且代碼書寫很清晰。這裏我只是查詢個人person表,而後按照年齡排序。pagination值並不是一個CPagination類的實例,而是一個數組而已。因此我將pagination配置成一個數組,數組元素只有currentPage和pageSize兩個。最後咱們即可以實例化CActiveDataProvider,而且按咱們的配置查詢數據庫了。
雖然咱們能夠只向頁面傳遞CActiveDataProvider對象,可是這樣會使得咱們的頁面很繁雜,因此我將數據信息data和頁面信息page分離開來,而後傳遞到被渲染的頁面。CActiveDataProvider類的getData()方法返回檢索數據結果集,類型爲數組。咱們能夠是使用foreach循環讀取data裏面的信息:
<?php foreach($data as $person){ echo "<tr height='30'>"; echo "<td>".$person['id']."</td>"; echo "<td>".$person['username']."</td>"; echo "</tr>"; } ?>
頁面信息page的構建其實很簡單,咱們獲取到總的記錄數,而後每頁顯示5條,天然咱們會獲得總的頁碼數。咱們也能夠獲取該頁下的記錄數,由於最後一頁的記錄數不必定是5。咱們將這些信息封裝成page數組,傳遞到被渲染的頁面上以供使用。固然咱們還能夠封裝更多的信息,固然這取決於你是怎麼顯示分頁信息,以及顯示什麼信息。
CHtml::link()的使用
方法說明:
public static string
link(string $text, mixed $url=’#', array $htmlOptions=array ( ))
例如:
<?php echo
CHtml::link(‘Link Text’,array(‘controller/action’)); ?>
HTML輸出爲:
<a
href=」index.php?r=controller/action」>Link Text</a>
帶參數的:
<?php echo
CHtml::link(‘Link Text’,array(‘controller/action’,'param1′=>’value1′));
?>
HTML輸出爲:
<a
href=」index.php?r=controller/action¶m1=value1″>Link
Text</a>
多參數的:
<?php echo
CHtml::link(‘Link Text’,array(‘controller/action’,
’param1′=>’value1′,’param2′=>’value2′));
?>
HTML輸出爲:
<a
href=」index.php?r=controller/action¶m1=value1¶m2=value2″>Link
Text</a>
額外參數的:
<?php echo
CHtml::link(‘Link Text’,array(‘controller/action’,'param1′=>’value1′),
array(‘target’=>’_blank’); ?>
HTML輸出:
<a
target=」_blank」
href=」index.php?r=controller/action¶m1=value1″>Link
Text</a>
絕對路徑:
<?php echo
CHtml::link(‘Link Text’,array(‘/controller/action’)); ?>
指定模塊下的路徑:
<?php echo
CHtml::link(‘Link Text’,array(‘/module-id/controller/action’)); ?>
<?php echo
CHtml::linkButton(‘LinkName’,
array(‘submit’=>array(‘controller/action’,'param’=>’value’),’confirm’=>」Are
you sure?」,)); ?>
無效連接:
echo CHtml::link(‘LinkName’,」,array(‘href’=>’javascript:void(0)’));
HTNL輸出:
<a href=」javascript:void(0)」>LinkName</a>
URL生成:
$route =
「site/test」;
$params =
array(‘id’=>100);
$url =
$this->createUrl($route,$params);
Widget的使用
繼承 CWidget 以及重載它的init() 和 run() 方法,能夠定義一個新的 widget:
class MyWidget extends
CWidget
{
public function init()
{
// this method is called by
CController::beginWidget()
}
public function run()
{
// this method is called by
CController::endWidget()
}
}
Widget能夠像一個控制器同樣擁有它本身的視圖。默認的, widget 的視圖文件位於包含了widget文件的views 子目錄之下。這些視圖能夠經過調用 CWidget::render() 渲染,這一點和控制器很類似。惟一不一樣的是,widget的視圖沒有佈局文件支持。同時,view 文件中的 $this 指的是 widget 實例而不是 controller 實例。
如今咱們建立一個 PageCode widget(分頁碼):
首先咱們須要在Web應用下的components包下建立自定義的widget:
components/ PageCode.php:
<?php
class PageCode extends
CWidget
{
public $page = array();
public function run()
{
$this->render(‘pagecode’,array(‘page’=>$this->page));
}
}
其次咱們還須要建立該widget所須要的視圖文件pagecode.php:
components/views/pagecode.php:
<?php
echo
CHtml::link(‘ first ’,array(‘site/page’,'id’=>0));
if($page['currentPage']<=0){
echo
CHtml::link(‘ previous ’,」,array(‘href’=>’javascript:void(0)’));
}else{
echo
CHtml::link(‘ previous ’,array(‘site/page’,'id’=>$page['currentPage']-1));
}
echo 「|」;
if($page['currentPage']>=$page['pageCount']-1){
echo
CHtml::link(‘ next ’,」,array(‘href’=>’javascript:void(0)’));
}else{
echo
CHtml::link(‘ next ’,array(‘site/page’,'id’=>$page['currentPage']+1));
}
echo 「|」;
echo
CHtml::link(‘ last ’,array(‘site/page’,'id’=>$page['pageCount']-1));
echo
「 」;
echo
「 」;
echo 「current page
:」.($page['currentPage']+1);
echo
「 」;
echo 「total page
:」.$page['pageCount'];
echo
「 」;
echo 「total record
:」.$page['totalItemCount'];
echo
「 」;
echo
「 」;
如今咱們就能夠在咱們的php頁面上使用該widget了:
<?php
$this->widget(‘application.components.PageCode’,array(‘page’=>$page));
?>
CCaptcha的使用
使用CCaptcha的話,你不得不使用CCaptchaAction,這兩個都是Yii提供的,CCaptcha本質上是一個widget,而CCaptchaAction則是一個action類。
CCaptcha的做用只是顯示校驗碼圖片和註冊Js腳本,而CCaptchaAction纔是核心,它負責生成校驗碼和圖片,而且支持Ajax校驗。在CCaptcha生成的靜態頁面中,咱們能夠看到生成的<img/>標籤請求的地址正是該CCaptchaAction。
實際上,CCaptchaAction將生成的校驗碼是放在Session中的,這樣有利於校驗。咱們使用CCaptcha,通常是將其做爲Model的一個屬性的,並在該Model的rules方法中指定該屬性的校驗規則爲「captcha」。暫時這樣理解。
使用CCaptcha注意:
1. 在Model中聲明一個屬性,其校驗規則爲「captcha」。
2. 在須要渲染CCaptcha的Controller中重寫actions 方法,將CCaptchaAction導入進來,做爲當前Controller的一個action,此action的ID爲「captcha」。由於生成的<img>請求的地址是當前Controller的captcha。
3. 在須要渲染CCaptcha的頁面中,添加input以對應Model中聲明的屬性。
4. 在須要渲染CCaptcha的頁面中,使用<?php $this->widget(‘CCaptcha’); ?>
這樣,當咱們在input輸入框中填完CCaptcha生成的校驗碼的時候,就會觸發Ajax校驗,本質上就是執行CCaptchaAction的validate方法,該方法會獲取用戶輸入的校驗碼,而後從Session中獲取正確的校驗碼,而後比對。
CCaptchaAction是怎麼樣生成校驗碼的?
CCaptchaAction的generateVerifyCode()方法用來生成校驗碼。默認狀況下,校驗碼的長度爲6或者7,固然這個能夠自定義。YII將26個英文字母分紅兩組,一組21個,一組5個。而後按必定的隨機規則從其中一組中選出一個字母。
CCaptchaAction是怎麼樣生成圖片的?
CCaptchaAction的renderImage()方法用來生成圖片。該方法中依次指定圖片的寬度,高度,背景色,背景色是否透明,前景色,字體(字體採用Duality.ttf,在CCaptchaAction同目錄下咱們能夠看到該字體文件)。圖片字體的不規則排列是由字體大小,angle,位置來決定的,這些參數會在必定範圍內隨機生成。
Yii上傳文件
CUploadedFile的使用:
$image =
CUploadedFile::getInstance($model,’image’);
$name =
$image->getName();
$size =
$image->getSize();
$type =
$image->getType();
$file =
「E:/temp.jpg」;
$image->saveAs($file,true);