關於yii驗證和yii錯誤處理


YII 驗證和消息

<div class="yiiForm">
<?php echo CHtml::form(); ?>
<table>
<tr><th>名稱</th><th>價格</th><th>數量</th><th>描述</th></tr>
<?php foreach($items as $i=>$item): ?>
<tr>
<td><?php echo CHtml::activeTextField($item,"name[$i]"); ?></td>
<td><?php echo CHtml::activeTextField($item,"price[$i]"); ?></td>
<td><?php echo CHtml::activeTextField($item,"count[$i]"); ?></td>
<td><?php echo CHtml::activeTextArea($item,"description[$i]"); ?></td>
</tr>
<?php endforeach; ?>
</table>
 
<?php echo CHtml::submitButton('Save'); ?>
<?php echo CHtml::endForm(); ?>
</div>

setFlash(), getFlash()可以完成驗證成功后提示

<?php
# 成功信息提示
Yii::app()->user->setFlash('success', "Thinks saved success!");
# 錯誤信息提示
Yii::app()->user->setFlash('error', "here has an Error, Please check that!");
# 一般消息信息提示
Yii::app()->user->setFlash('notice', "messge here");
?>

2.errorSummary驗證不通過的錯誤提示

rules()方法中定義的規則會在模型實例調用其 validate() 或 save() 方法時逐一執行。normalizeTags驗證器是一個基於方法的驗證器,Models/xx.php中的rules()的驗證規則是對數據庫表進行的,Models/xxForm.php中的rules()的驗證規則是對表單進行的,和數據庫表沒有關系,類名和文件名要相同 。

如果我們使用一個validator(驗證器)類,則這個類必須繼承CValidator。其實有三種方法可以指定validator(驗證器),包括前面提到的一種格式:
1.第一種是在模型類中定義驗證方法
2.第二種是指定一個單獨的驗證器類(這個類繼承validators/CValidator )。
3.第三種是你可以使用Yii框架中現有的驗證器,指定預定義的驗證器別名即可。

Yii為你提供了很多預定義的驗證器類,同時也指定了別名,用在定義規則時。Yii1.1版本,預定義的驗證器別名的完整列表如下:
* captcha:它是CCaptchaValidator類的別名,驗證屬性的值等於一個顯示的CAPTCHA(驗證碼)的值。
* compare:它是CCompareValidator類的別名'=','==','!=','>','>='。
* default:它是CDefaultValidator類的別名,驗證屬性的值為分配的默認值。
exist:它是CExistValidator類的別名,驗證屬性的值在表中的對應列中存在。 
* filter:它是CFilterValidator類的別名,用過濾器轉換屬性的值。
* in:它是CRangeValidator類的別名,驗證屬性值在一個預定義列表中。
* length:它是CStringValidator類的別名,驗證屬性值的長度在一個范圍內。
* match:它是CRegularExpressionValidator類的別名,驗證屬性值匹配一個正則表達式。
* numerical:它是CNumberValidator類的別名,驗證屬性值是數字。
* type:它是CTypedValidator類的別名,驗證屬性值是一個指定的數據類型。
* unique:它是CUniquedValidator類的別名,驗證屬性值在表中的對應列中是唯一的。
* url:它是CUrlValidator類的別名,驗證屬性值是一個有效的URL。

 

2.單獨的驗證器類 方便重用

首先要做的是創建類文件.最好的方法時類的文件名和類名相同,可以使用yii的延遲加載(lazy loading)功能。
讓我們在應用(application)的擴展(extensiions)目錄(在 protected 文件夾下)下新建一個文件夾.
將目錄命名為: MyValidators然后創建文件: passwordStrength.php

class passwordStrength extends CValidator{
	public $strength;

	private $weak_pattern = '/^(?=.*[a-zA-Z0-9]).{5,}$/';
	private $strong_pattern = '/^(?=.*\d(?=.*\d))(?=.*[a-zA-Z](?=.*[a-zA-Z])).{5,}$/';
	protected function validateAttribute($object,$attribute)
	{
		// check the strength parameter used in the validation rule of our model
		if ($this->strength == 'weak')
		$pattern = $this->weak_pattern;
		elseif ($this->strength == 'strong')
		$pattern = $this->strong_pattern;

		// extract the attribute value from it's model object
		$value=$object->$attribute;
		if(!preg_match($pattern, $value))
		{
			$this->addError($object,$attribute,'your password is too weak!');
		}
	}

 然后在模型(model)的:

/**
 * @return array validation rules for model attributes.
 */
public function rules()
{
    return array(
       array('password', 'ext.MyValidators.passwordStrength', 'strength'=>self::STRONG),
    );
}

由於我們直接在User AR類中添加了$repassword屬性,並且它與底層數據庫表之間沒有對應關系,我們需要告訴模型類允許這個屬性在setAttributes()被調用時被設置。 保存時不能入庫需要添加rules驗證驗證器 。我們的做法是將其添加到User模型類的安全屬性列表中。向User::rules()數組添加下列代碼:

array('repassword', 'safe'),

我們新建的$repassword不存在對應的tbl_user表中的列,需要將其直接添加到安全屬性列表。

setAttributes:

$model->attributes=$_POST['User'];

添加了$repassword屬性

class User extends CActiveRecord
{
	public $repassword; //不能是private會報錯

以注冊驗證為例.controller

public function actionRegister()  
{  
	$model=new User;    	
	if(isset($_POST['User']))
	{    	
		$model->attributes=$_POST['User'];
        if($model->save()){  
            Yii::app()->user->setFlash('register','Thank you for your register.');//驗證通過提示  
            $this->refresh(); 
        }  
    }  
  
    $this->render('register',array(  
        'model'=>$model,  
    ));  
}  

register.php

<h1>注冊用戶</h1>
<?php if(Yii::app()->user->hasFlash('register')): ?>

<div class="flash-success">
	<?php echo Yii::app()->user->getFlash('register'); ?>
</div>

<?php else: ?>

<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
	'id'=>'user-form',
	'enableAjaxValidation'=>false,
)); 
?>
	<p class="note">Fields with <span class="required">*</span> are required.</p>

	<?php echo $form->errorSummary($model); ?>

	<div class="row">
		<?php echo $form->labelEx($model,'password'); ?>
		<?php echo $form->passwordField($model,'password',array('size'=>60,'maxlength'=>128, 'autocomplete'=>'off','value'=>'')); ?>
		<?php echo $form->error($model,'password'); ?>
	</div>

	<div class="row">
		<?php echo $form->labelEx($model,'repassword'); ?>
		<?php echo $form->passwordField($model,'repassword',array('size'=>60,'maxlength'=>128, 'autocomplete'=>'off','value'=>'')); ?>
		<?php echo $form->error($model,'repassword'); ?>
	</div>

	<div class="row buttons">
		<?php echo CHtml::submitButton('注冊'); ?>
	</div>

<?php $this->endWidget(); ?>
</div>

<?php endif; ?>

ajax動態驗證 
第一步:在_form中最上面改成

$form=$this->beginWidget('CActiveForm', array(
    'id'=>'user-form',
    'enableAjaxValidation'=>true,
)

第二步:controller中添加,對應 'id'=>'user-form'

$this->performAjaxValidation($model);

protected function performAjaxValidation($model)
{
	if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
	{
		echo CActiveForm::validate($model);
		Yii::app()->end();
	}
}

第三步:在models層中加入checkemai方法

public function rules()
{
	// NOTE: 可以用exist驗證器替換
	return array(
		array('email', 'checkUser','message'=>'Test message for email validation'),
		array('user_id', 'checkUser','message'=>'Test message for {attribute} validation'),
	);
}
public function checkUser($attribute,$params) //attribute用法
{
	switch($attribute){
		case "email": //rules email
			$models = ServiceReviews::model()->findAllByAttributes(array('email' =>$this->email,'service_id'=>$this->service_id));
			if(count($models)>0){
				 $this->addError($attribute, $params['message']);
			}
		break;
		case "user_id":
			if(Yii::app()->user->isGuest){
				$models = ServiceReviews::model()->findAllByAttributes(array('user_id' =>Yii::app()->user->id,'service_id'=>$this->service_id));
				if(count($models)>0){
					 $this->addError($attribute, $params['message']);
				}
			}
		break;
	}
}

最后在models層的驗證規則中(rules)加入以下驗證規則{attribute}

array('email', 'checkUser','message'=>'已經存在{attribute}'),

剛才創建的方法需要兩個參數:
* $attribute 需要驗證的屬性
* $params 在規則中自定義的參數
在模型的 rules 方法中我們驗證的是email屬性,所以在驗證規則中需要驗證的屬性值應該是 email.

在 rules 方法中我們還設置了自定義的參數 message,它的值將會放到 $params 數組中.

三.非表單驗證錯誤處理 :

你會發現在方法中我們使用了 CModel::addError().添加錯誤接受兩個參數:第一個參數是在表單中顯示錯誤的屬性名,第二個參數時顯示的錯誤信息 。
用戶提交表單時,可能除表單驗證之外還有與表單各輸入項無關的其他錯誤產生,例如后台數據庫出錯、接口調用失敗等。
這種情況下可以在Model中相應的位置使用如下代碼記錄錯誤:

$this->addError('info', '發送不明錯誤,請重試'); // info 只是一個自定義的名字,不需要真正有這個字段或屬性。

然后在視圖文件中這樣輸出錯誤:

echo $form->error($model, 'info'); //$form 是 CActiveForm 的實例。$form->getErrors();

當我們調用 CModel::validate() 方法, 我們可以指定一個場景參數. 只有在特定的場景下校驗規則才會生效.校驗規則會在那些 on 選項沒有被設置或者包含了指定的場景名稱的場景中生效.如果我們沒有指定場景,而調用了 CModel::validate() 方法,只有那些 on 選項沒有設置的規則才會被執行 .

$model = new model('register');
// or $model=new User;
// $model->scenario='register';

例如,在注冊一個用戶時,我們運行以下腳本來執行校驗 :

 array('password', 'compare', 'compareAttribute'=>'repassword', 'on'=>'register,edit'), 

  Email驗證器

array('email','email'), //驗證email這個字段必須符合email格式

 Compare驗證器

array('password2','compare','compareAttribute'=>'password1'),//驗證password1和password2必須一致
array('end_date','compare', 'compareAttribute' => 'start_date', 'operator' => '>', 'message' => '錯誤的開始結束日期'),

Unique驗證器

array('username,email','unique','className'=>'User'),//User為Model,username,email在user中不允許重復

如果被驗證屬性為空,就認為完全合法,立刻返回,但是如果allowEmpty為false的話,就要通過函數后續的所有驗證條件 。那么對於一個傳入的空值來說,allowEmpty無論是true還是false,極有可能都不會報錯,上面節選的驗證器是StringValidator,如果我沒有設定min的值,那么一個空串在allowEmpty為false的情況下,還是不會報任何錯誤的。
如果希望一個屬性值不能為空,最好還是用RequiredValidator來驗證,allowEmpty是不靠譜的,建議一般就采取allowEmpty的默認值true,可以節省幾次判斷。

array('verifyCode', 'captcha', 'allowEmpty'=>!CCaptcha::checkRequirements()),

布爾驗證器

array('rememberMe', 'boolean'),

數字驗證器

array('id', 'numerical', 'min'=>1, 'max'=>10, 'integerOnly'=>true),

default驗證器

array('created','default','value'=>new CDbExpression('NOW()'),'setOnEmpty'=>false)

fiter驗證器

array('moduleID', 'filter', 'filter'=>'trim'),

正則驗證器

array('name','match','pattern'=>'/^[a-z0-9\-_]+$/'),

in驗證器

array('superuser', 'in', 'range' => array(0, 1)),

length驗證器

array('password','length','min'=>'6','max'=>'16','message'=>'{attribute}長度必須在{min}到{max}之間'), 

類型驗證 integer,float,string,array,date,time,datetime

array('created', 'type', 'datetime'),

日期格式驗證

array('created', 'date', 'format'=>'yyyy/MM/dd/ HH:mm:ss'),

文件驗證

array('filename', 'file', 'allowEmpty'=>true, 'types'=>'zip, rar, xls, pdf, ppt'),


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM