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

Yii 框架模型核心概念深度解析:屬性、驗證、場景與最佳實踐

     編輯:PHP 綜合知識

前言

模型是 MVC 架構中代表業務資料、規則與邏輯的核心元件。Yii 透過 yii\base\Model 基類提供豐富功能,支援表單模型與 Active Record 兩大類型。本文深入探討模型屬性管理、驗證機制、場景應用、區塊賦值、資料匯出等核心概念。

模型類型概覽

類型基類用途特點
表單模型yii\base\Model使用者輸入資料處理資料暫時性、經常獲取使用後丟棄
Active Recordyii\db\ActiveRecord資料庫資料物件映射對應資料表列、支援關聯查詢、資料持久化

屬性管理

屬性定義方式

方式一:公開成員變數(預設)

namespace app\models;
use yii\base\Model;

class ContactForm extends Model {
    public $name;
    public $email;
    public $subject;
    public $body;
}

方式二:覆寫 attributes() 方法

// ActiveRecord 自動對應資料表欄位
public function attributes() {
    return ['id', 'username', 'email', 'created_at', 'updated_at'];
}

屬性存取方式

$model = new ContactForm();

// 物件屬性存取
$model->name = 'example';
echo $model->name;

// 陣列存取(支援 ArrayAccess、ArrayIterator)
$model['name'] = 'example';
echo $model['name'];

// 迭代器遍歷
foreach ($model as $name => $value) {
    echo "$name: $value\n";
}

屬性標籤

自動生成規則

駝峰式命名自動轉換:firstName → First Name,username → Username

自訂標籤

public function attributeLabels() {
    return [
        'name' => 'Your name',
        'email' => 'Your email address',
        'subject' => 'Subject',
        'body' => 'Content',
    ];
}

多語系支援

public function attributeLabels() {
    return [
        'name' => \Yii::t('app', 'Your name'),
        'email' => \Yii::t('app', 'Your email address'),
    ];
}

情境式標籤

public function attributeLabels() {
    return [
        'email' => $this->scenario === 'register' ? 'Register Email' : 'Login Email',
    ];
}

場景機制

場景設定

// 方式一:屬性指派
$model = new User;
$model->scenario = 'login';

// 方式二:建構子配置
$model = new User(['scenario' => 'login']);

自訂場景定義

namespace app\models;
use yii\db\ActiveRecord;

class User extends ActiveRecord {
    public function scenarios() {
        return [
            'login' => ['username', 'password'],
            'register' => ['username', 'email', 'password'],
            'profile' => ['username', 'email', 'avatar', 'bio'],
        ];
    }
}

擴充預設場景

public function scenarios() {
    $scenarios = parent::scenarios();
    $scenarios['login'] = ['username', 'password'];
    $scenarios['register'] = ['username', 'email', 'password'];
    return $scenarios;
}

場景應用範圍

  • 驗證規則:不同場景套用不同規則
  • 區塊賦值:僅活動屬性可被大量賦值
  • 屬性標籤:可根據場景回傳不同標籤

驗證規則

基本驗證流程

$model = new ContactForm;
$model->attributes = \Yii::$app->request->post('ContactForm');

if ($model->validate()) {
    // 驗證通過
} else {
    $errors = $model->errors;  // 錯誤訊息陣列
}

規則宣告格式

public function rules() {
    return [
        // 必填驗證
        [['name', 'email', 'subject', 'body'], 'required'],
        
        // Email 格式驗證
        ['email', 'email'],
        
        // 字串長度
        [['name', 'subject'], 'string', 'max' => 100],
        
        // 數值範圍
        ['age', 'integer', 'min' => 18, 'max' => 100],
        
        // 正則表達式
        ['username', 'match', 'pattern' => '/^[a-zA-Z0-9_]+$/'],
        
        // 自訂驗證方法
        ['password', 'validatePassword'],
        
        // 條件式驗證(特定場景)
        [['username', 'email', 'password'], 'required', 'on' => 'register'],
        [['username', 'password'], 'required', 'on' => 'login'],
    ];
}

驗證器分類

類別驗證器用途
基本required, safe, filter, trim必填、安全屬性、過濾、修剪
型別string, number, integer, boolean, date資料型別驗證
格式email, url, ip, match特定格式驗證
比較compare, exist, unique比較、存在性、唯一性
範圍in, range, between值域驗證
檔案file, image上傳檔案驗證
進階captcha, captchaAction驗證碼

區塊賦值與安全屬性

區塊賦值優勢

// 區塊賦值 - 簡潔安全
$model->attributes = \Yii::$app->request->post('ContactForm');

// 手動賦值 - 複雜易錯
$data = \Yii::$app->request->post('ContactForm', []);
$model->name = isset($data['name']) ? $data['name'] : null;
$model->email = isset($data['email']) ? $data['email'] : null;
// ...

安全屬性機制

  • 僅 scenarios() 定義的活動屬性可被區塊賦值
  • 預設所有出現在驗證規則中的屬性皆為安全屬性
  • 使用 safe 驗證器明確宣告無需驗證但可賦值的屬性
public function rules() {
    return [
        [['title', 'description'], 'safe'],  // 宣告為安全屬性
    ];
}

非安全屬性

需驗證但不允許區塊賦值,在屬性名前加 !:

public function scenarios() {
    return [
        'login' => ['username', 'password', '!secret'],
    ];
}

// 僅能明確賦值
$model->secret = $secretValue;

資料匯出

基本匯出

$post = Post::findOne(100);
$array = $post->attributes;  // 所有屬性值

進階匯出:toArray() 方法

// 指定欄位
$array = $model->toArray();                    // 預設欄位
$array = $model->toArray([], ['prettyName']);  // 含額外欄位

自訂匯出欄位

public function fields() {
    return [
        'id',                                    // 同名屬性
        'email' => 'email_address',              // 重新命名
        'name' => function () {                  // 計算欄位
            return $this->first_name . ' ' . $this->last_name;
        },
    ];
}

public function extraFields() {
    return [
        'fullAddress' => function () {
            return $this->address . ', ' . $this->city;
        },
    ];
}

// 使用方式
$array = $model->toArray([], ['fullAddress']);

過濾敏感欄位

public function fields() {
    $fields = parent::fields();
    unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']);
    return $fields;
}

最佳實踐

模型設計原則

  • 包含業務資料屬性與驗證規則
  • 封裝業務邏輯方法
  • 不直接存取請求、Session 等環境資料(由控制器傳入)
  • 避免內嵌 HTML 或表現層程式碼
  • 單一模型避免過多場景

大型系統模型架構策略

// 共用基礎模型層
namespace common\models;
class Post extends \yii\db\ActiveRecord {
    // 通用規則、關聯、方法
}

// 前台應用專用模型
namespace frontend\models;
class Post extends \common\models\Post {
    // 前台特定規則、邏輯
}

// 後台應用專用模型
namespace backend\models;
class Post extends \common\models\Post {
    // 後台特定規則、邏輯
}

優勢

  • 修改前台模型不影響後台
  • 共用核心邏輯減少重複
  • 各應用獨立演進
  • 團隊平行開發無衝突

常見陷阱與解決方案

陷阱 1:忘記宣告 safe 屬性導致無法賦值

解決:在 rules() 中加入 [['attr'], 'safe'] 或確保屬性出現在驗證規則中。

陷阱 2:驗證規則未指定 on 導致所有場景生效

解決:明確指定 'on' => 'scenarioName' 限制適用場景。

陷阱 3:toArray() 洩露敏感資料

解決:覆寫 fields() 移除敏感欄位,或使用 DTO/Resource 類別控制輸出。

總結

Yii 模型系統提供完整的資料封裝、驗證與轉換機制。核心掌握點包括:

  1. 屬性與標籤:靈活定義、多語系支援、情境式調整
  2. 場景機制:區隔不同業務情境的驗證與賦值規則
  3. 驗證規則:豐富內建驗證器、自訂驗證、條件式應用
  4. 區塊賦值:安全層機制防止大量指派攻擊
  5. 資料匯出:fields/extraFields 精確控制 API 輸出

遵循最佳實踐原則,建立清晰的模型層次架構,能讓應用程式在規模增長時保持可維護性與擴充性。

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