首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Yii 1.x 模型自訂驗證規則開發技巧:從內建到元件化

     編輯:PHP 相關知識

掌握 Yii 模型驗證擴展:行內方法、獨立驗證器類別、用戶端驗證

Yii 模型的 rules() 內建驗證器已涵蓋大多數場景,但業務邏輯常需查詢資料庫(如檢查標籤是否重複)、跨欄位比對等自訂規則。本文由淺入深介紹三種實作層級:模型內行內方法、獨立 CValidator 衍生類別、支援用戶端驗證的完整元件化方案。

場景:新增標籤時檢查名稱唯一性

視圖片段:

<?php $form=$this->beginWidget('CActiveForm', ['id'=>'tag-form', 'enableAjaxValidation'=>false]); ?>
<div class="row">
    <?php echo $form->labelEx($model,'tagname'); ?>
    <?php echo $form->textField($model,'tagname',['size'=>20,'maxlength'=>32]); ?>
</div>
<div class="row">
    <?php echo $form->labelEx($model,'tagtype'); ?>
    <?php echo $form->radioButtonList($model,'tagtype',[1=>'一般 TAG',2=>'系統預設 TAG'],['separator'=>'','labelOptions'=>['class'=>'tagtypelabel']]); ?>
</div>
<?php echo $form->errorSummary($model); ?>
<div class="row buttons">
    <?php echo CHtml::submitButton($model->isNewRecord ? '新增' : '修改'); ?>
</div>
<?php $this->endWidget(); ?>

層級 1:模型內行內驗證方法

步驟 1:在 rules() 宣告規則

public function rules() {
    return [
        ['tagname, tagtype', 'required'],
        ['tagtype', 'numerical', 'integerOnly' => true],
        ['tagname', 'length', 'max' => 32],
        ['tagname', 'match', 'pattern' => '/^[\x{4e00}-\x{9fa5}A-Za-z0-9]+$/u', 'message' => '標籤只能含中英數字!'],
        ['tagname', 'checkTagName', 'on' => 'create,update'], // 自訂規則
        ['tagid, tagname, tagtype', 'safe', 'on' => 'search'],
    ];
}

步驟 2:實作驗證方法

public function checkTagName($attribute, $params) {
    $existing = Tag::model()->findByAttributes(['tagname' => $this->tagname]);
    if ($existing && $existing->tagid > 0) {
        $this->addError($attribute, '該標籤已存在!');
    }
}

重點:

  • 方法簽名必須為 ($attribute, $params)。
  • $this->addError($attribute, '訊息') 將錯誤掛在對應屬性,視圖自動顯示。
  • 'on' => 'create,update' 限定場景,避免搜尋時誤觸發。

層級 2:密碼強度驗證範例(帶參數)

class User extends CActiveRecord {
    const WEAK = 0;
    const STRONG = 1;

    public function rules() {
        return [
            ['password', 'passwordStrength', 'strength' => self::STRONG],
        ];
    }

    public function passwordStrength($attribute, $params) {
        $pattern = $params['strength'] === self::WEAK
            ? '/^(?=.*[a-zA-Z0-9]).{5,}$/'
            : '/^(?=.*\d(?=.*\d))(?=.*[a-zA-Z](?=.*[a-zA-Z])).{5,}$/';
        if (!preg_match($pattern, $this->$attribute)) {
            $this->addError($attribute, '密碼強度不足!');
        }
    }
}

規則中傳入的參數(strength)會自動放入 $params 陣列。

層級 3:獨立驗證器類別(可重複使用、支援用戶端驗證)

1. 建立檔案:protected/extensions/MyValidators/PasswordStrengthValidator.php

class PasswordStrengthValidator extends CValidator {
    public $strength = 'weak';
    private $weakPattern = '/^(?=.*[a-zA-Z0-9]).{5,}$/';
    private $strongPattern = '/^(?=.*\d(?=.*\d))(?=.*[a-zA-Z](?=.*[a-zA-Z])).{5,}$/';

    protected function validateAttribute($object, $attribute) {
        $pattern = $this->strength === 'strong' ? $this->strongPattern : $this->weakPattern;
        $value = $object->$attribute;
        if (!preg_match($pattern, $value)) {
            $this->addError($object, $attribute, '密碼強度不足!');
        }
    }

    // 選擇性:支援 CActiveForm::enableClientValidation
    public function clientValidateAttribute($object, $attribute) {
        $pattern = $this->strength === 'strong' ? $this->strongPattern : $this->weakPattern;
        return "
if (!value.match({$pattern})) {
    messages.push(" . CJavaScript::encode('密碼強度不足!') . ");
}
";
    }
}

2. 在模型中使用:

public function rules() {
    return [
        ['password', 'ext.MyValidators.PasswordStrengthValidator', 'strength' => 'strong'],
    ];
}

優勢:

  • 跨模型重複使用,符合 DRY 原則。
  • 實作 clientValidateAttribute() 即可產出 JavaScript 驗證碼,配合 CActiveForm::enableClientValidation=true 實現瀏覽器端即時檢查(Yii 1.1.7+)。
  • 可發布為獨立擴充套件分享社群。

最佳實踐建議

  1. 簡單業務邏輯 → 模型內行內方法(checkXxx)。
  2. 需帶參數、多模型共用 → 獨立 CValidator 類別。
  3. 表單重、用戶體驗要求高 → 實作用戶端驗證。
  4. 驗證涉及資料庫查詢 → 僅伺服器端執行,避免洩露資料或造成效能問題。

善用驗證層級,讓 rules() 保持精簡,業務邏輯集中、可測試、可複用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved