Yii 表單模型 CFormModel 專為非持久化資料驗證設計,核心流程:屬性批量賦值 → 收集驗證器 → 執行驗證 → 錯誤收集。本文以登入表單為例,完整解析 rules() 定義、CValidator::createValidator() 工廠模式、內建與內聯驗證器區別、驗證執行流程與錯誤提取。
class LoginForm extends CFormModel {
public $username;
public $password;
public $rememberMe;
public function rules() {
return [
['username, password', 'required'],
['rememberMe', 'boolean'],
['password', 'authenticate'], // 內聯驗證器
];
}
public function authenticate($attribute, $params) {
// 自定義驗證邏輯,失敗時 $this->addError($attribute, '訊息');
}
}
$model = new LoginForm();
$model->attributes = $_POST['LoginForm']; // 批量賦值(觸發 setter)
if ($model->validate()) {
// 驗證通過,處理登入
} else {
$errors = $model->getErrors(); // 所有錯誤
$firstError = $model->getError('username'); // 單一欄位首個錯誤
}
public static function createValidator($name, $object, $attributes, $params = []) {
// 1. 正規化屬性陣列
if (is_string($attributes)) $attributes = preg_split('/[\s,]+/', $attributes, -1, PREG_SPLIT_NO_EMPTY);
// 2. 正規化場景 on
if (isset($params['on'])) { /* ... */ }
// 3. 判斷是內聯驗證器(模型有同名方法)還是獨立驗證器類別
if (method_exists($object, $name)) {
$validator = new CInlineValidator;
$validator->attributes = $attributes;
$validator->method = $name;
$validator->params = $params;
// clientValidate, skipOnError 等參數處理
} else {
// 4. 解析類別名:內建對照表 或 完整類別路徑
if (isset(self::$builtInValidators[$name]))
$className = Yii::import(self::$builtInValidators[$name], true);
else
$className = Yii::import($name, true);
$validator = new $className;
foreach ($params as $k => $v) $validator->$k = $v;
}
$validator->on = empty($on) ? [] : array_combine($on, $on);
return $validator;
}
| 規則名稱 | 對應類別 | 說明 |
|---|---|---|
| required | CRequiredValidator | 必填 |
| CEmailValidator | Email 格式 | |
| url | CUrlValidator | URL 格式 |
| match | CRegularExpressionValidator | 正則匹配 |
| compare | CCompareValidator | 比較(相等、大小等) |
| numerical | CNumberValidator | 數值型別 |
| length | CStringValidator | 字串長度 |
| boolean | CBooleanValidator | 布林值 |
| date | CDateValidator | 日期格式 |
| type | CTypeValidator | 型別轉換驗證 |
| unique | CUniqueValidator | 資料庫唯一性(AR 專用) |
| exist | CExistValidator | 資料庫存在性(AR 專用) |
$model->validate():執行所有屬於當前 scenario 的驗證器。$model->validate(['username']):僅驗證指定屬性。rules() 陣列可加 'on' => 'scenarioName',模型 $model->scenario = 'scenarioName' 切換。skipOnError:同屬性多驗證器,前一個失敗是否跳過後續(預設 true)。內建驗證器實作 clientValidateAttribute() 產生 JS 代碼,配合 CHtml::activeForm() enableClientValidation=true 實現前端即時驗證,減少伺服器負載。
attributes 批量賦值只能設定 safe 屬性(出現在 rules 中),未宣告屬性會被忽略。$this->addError() 標記失敗。['attr', 'validator', 'param1' => 'val'] 從第 3 元素起進入 $params。use ($model) 或改用獨立驗證器類別。Yii 表單驗證核心在於 rules() 宣告式定義 + CValidator 工廠建立 + validate() 統一執行。掌握內建/內聯/自訂驗證器三種形式、場景控制、客戶端驗證整合,即能構建健壯且可維護的表單驗證體系。