Stories

Detail Return Return

Fastadmin通過模型初始化事件解決實際項目問題 - Stories Detail

thinkphp5.0中的模型初始化事件

在Thinkphp5.0中, 模型初始化事件(Model Initialization Events)是模型生命週期中的關鍵機制,用於在模型實例化、數據操作(新增、更新、刪除等)的特定階段觸發自定義邏輯,實現數據校驗、字段處理、日誌記錄等功能。這些事件通過 “鈎子” 方式嵌入模型的核心流程,無需修改框架源碼即可擴展功能。

1. 模型初始化事件的基本概念

模型事件分為"模型初始化事件""數據操作事件"兩類:

  • 模型初始化事件: 在模型類加載或實例化時觸發(如 init 事件)
  • 數據操作事件: 在執行新增、更新、刪除等數據庫操作時觸發(如 beforeInsert、afterUpdate 等)
    所有事件均通過模型的靜態方法註冊, 通常在模型的 init() 方法中定義.

    2. 常用的模型事件以及觸發時機

    ThinkPHP 5.0 提供了豐富的模型事件,覆蓋數據操作的全生命週期,常用事件如下:
    image.png

結合實際案例講解如何使用

fastadmin後台的設備管理中有個屬性是設備分組(group_id), 現在需要記錄下設備與分組綁定時間(group_bind_time), 之前的後台Device控制器中只是自定義了index方法, 並沒有修改fastadmin默認的add跟edit方法, 之前碰到這種情況是通過修改默認的add跟edit方法來實現
現在知道了上面的模型操作事件後就可以結合模型操作事件(beforeInsert,beforeUpdate )在寫入數據跟修改數據的時候做一下處理就可以了, 這樣就不用修改後台默認的add跟edit方法了
<?php
namespace app\device\model;

use think\Model;
use think\Db;

class DeviceModel extends Model
{
    //配置連接參數 對應config.php中的devicedb配置
    protected $connection = 'devicedb';

    //對應數據表名
    protected $name = 'device_lists';

    //設置查詢結果返回think\collection對象, 支持鏈式操作
    protected $resultSetType = 'collection';

    // 模型初始化(註冊事件的入口)
    protected static function init()
    {
        // 1. 註冊 beforeInsert 事件:新增前自動填充創建時間
        self::beforeInsert(function ($row) {
            if ($row['group_id']) {
                $row['group_bind_time'] = time();
            }
        });

        // 2. 註冊 beforeUpdate 事件:更新前自動填充更新時間
        self::beforeUpdate(function ($row) {
            //先通過id獲取舊數據(因為這裏是修改前)
            $oldData = self::get($row['id']);
            //如果設備分組發生改變
            if ($row['group_id'] && $oldData['group_id'] != $row['group_id']) {
                $row['group_bind_time'] = time();
            } elseif (!$row['group_id']) {
                $row['group_bind_time'] = '';
            }

        });

        // 3. 註冊 afterInsert 事件:可以在新增後增加記錄日誌
        self::afterInsert(function ($row) {
           
        });

        // 4. 註冊 beforeSelect 事件:查詢時增加額外的篩選條件
        self::beforeSelect(function ($query) {
            // 可以在這裏面定義全局篩選條件條件(如下示例)
            //$query->where('status', 1); 
        });
    }
}

注意事項

1. 事件的觸發條件

  • 數據操作事件(如 beforeInsert、beforeUpdate)僅在調用模型的 save()、delete() 等方法時觸發,批量操作(如 where()->update())不會觸發(需循環處理單實例)
  • beforeSelect、beforeFind 等查詢事件,在調用模型的 select()、find()、get() 等查詢方法時觸發,使用 Db 類原生查詢(如 Db::name()->select())不會觸發。

2. 事件回調的中斷機制

在 beforeInsert、beforeUpdate、beforeDelete 等 “前置事件” 中,返回 false 或拋出異常可中斷後續操作(阻止數據寫入 / 刪除):

self::beforeDelete(function ($row) {
    if ($row->is_admin == 1) {
        // 管理員不允許刪除,中斷操作
        return false; //或者是拋出異常
    }
});

3. 事件的覆蓋與追加

註冊事件時,可通過第二個參數控制事件是否覆蓋(默認追加):

// 第二個參數為 true 表示覆蓋已註冊的同名事件
self::beforeUpdate(function ($row) { ... }, true);

4. 靜態與實例的區別

  • 事件回調中,beforeInsert、beforeUpdate 等操作事件的參數為模型實例(可直接操作字段屬性)。
  • beforeSelect、beforeFind 等查詢事件的參數為查詢對象(Query),用於修改查詢條件(如 $query->where(...))。
user avatar big_cat Avatar werbenhu Avatar phpercode Avatar
Favorites 3 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.