thinkphp5.0中的模型初始化事件
在Thinkphp5.0中, 模型初始化事件(Model Initialization Events)是模型生命週期中的關鍵機制,用於在模型實例化、數據操作(新增、更新、刪除等)的特定階段觸發自定義邏輯,實現數據校驗、字段處理、日誌記錄等功能。這些事件通過 “鈎子” 方式嵌入模型的核心流程,無需修改框架源碼即可擴展功能。
1. 模型初始化事件的基本概念
模型事件分為"模型初始化事件"和"數據操作事件"兩類:
- 模型初始化事件: 在模型類加載或實例化時觸發(如 init 事件)
-
數據操作事件: 在執行新增、更新、刪除等數據庫操作時觸發(如 beforeInsert、afterUpdate 等)
所有事件均通過模型的靜態方法註冊, 通常在模型的 init() 方法中定義.2. 常用的模型事件以及觸發時機
ThinkPHP 5.0 提供了豐富的模型事件,覆蓋數據操作的全生命週期,常用事件如下:
結合實際案例講解如何使用
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(...))。