Yii2 yii\base\Model::rules() 支援閉包、方法名、獨立驗證器類三種自定義方式。本文以「條件必填」為核心場景,演示如何實現「字段 A 為 1 時,字段 B 必填;A 為 2 時,B 可選」的業務邏輯。
type (A):下拉選擇,值 1|2content (B):文本域type === 1 → content 必填;type === 2 → content 可選<?php
namespace app\models;
use yii\base\Model;
class ArticleForm extends Model
{
public $type;
public $content;
public function rules()
{
return [
['type', 'required'],
['type', 'in', 'range' => [1, 2]],
['content', 'validateContentByType'], // 方法名驗證器
];
}
/**
* 自定義驗證方法
* @param string $attribute 當前驗證屬性名 (content)
* @param mixed $params 規則中額外參數
*/
public function validateContentByType($attribute, $params)
{
if ($this->type == 1 && empty($this->$attribute)) {
$this->addError($attribute, '當類型為 1 時,內容不能為空。');
}
}
}
public function rules()
{
return [
['type', 'required'],
['type', 'in', 'range' => [1, 2]],
['content', function ($attribute, $params) {
if ($this->type == 1 && empty($this->$attribute)) {
$this->addError($attribute, '類型 1 必填內容。');
}
}],
];
}
<?php
namespace app\validators;
use yii\validators\Validator;
class RequiredWhenValidator extends Validator
{
public $whenProperty; // 觸發條件屬性名
public $whenValue; // 觸發條件值
public $message = '{attribute} 在條件滿足時必填。';
public function validateAttribute($model, $attribute)
{
if ($model->{$this->whenProperty} == $this->whenValue && empty($model->$attribute)) {
$this->addError($model, $attribute, $this->message);
}
}
}
// 模型中使用
use app\validators\RequiredWhenValidator;
public function rules()
{
return [
['type', 'required'],
['type', 'in', 'range' => [1, 2]],
['content', RequiredWhenValidator::class, 'whenProperty' => 'type', 'whenValue' => 1],
];
}
['content', 'validateContentByType', 'on' => 'publish'] 僅在 $model->validate('publish') 時觸發。['content, images', 'validateMedia'] 同時驗證多欄位。clientValidateAttribute() 返回 JS 代碼,實現前端即時校驗(需載入 yii.activeForm.js)。$this->type === null 視為條件不滿足,跳過驗證。<?php
use yii\widgets\ActiveForm;
use yii\helpers\Html;
$form = ActiveForm::begin(['id' => 'article-form']);
echo $form->field($model, 'type')->dropDownList([1 => '類型一(必填內容)', 2 => '類型二(可選)']);
echo $form->field($model, 'content')->textarea(['rows' => 6]);
echo Html::submitButton('提交', ['class' => 'btn btn-primary']);
ActiveForm::end();
| 現象 | 原因 | 修正 |
|---|---|---|
| 驗證不生效 | 方法名拼寫錯誤 / 未返回 rules() | 檢查拼寫、確保 return |
| addError 不顯示 | 屬性名不匹配 / 視圖未輸出 $form->field() | 確保 $attribute 與 field 名一致 |
| 條件屬性未載入 | $this->type 為 null (未在 rules 中聲明) | 條件屬性也需在 rules 中聲明 (如 required/in) |
Yii2 自定義驗證三板斧:內聯方法(項目內單一邏輯)、閉包(極簡臨時邏輯)、獨立類(跨項目復用/測試)。善用 addError()、scenarios()、clientValidateAttribute() 構建健壯、用戶友好的表單驗證體系。