# 事件 模型事件實現 [psr/event-dispatcher](https://github.com/php-fig/event-dispatcher) 介面,預設由 [hyperf/event](https://github.com/hyperf/event) 元件提供功能支援。 ## 執行事件 在 ORM 的執行期間,會對應觸發以下事件,您可以進行對這些事件進行監聽以滿足您的需求。 | 事件 | 描述 | | :--------: | :----: | | Hyperf\Database\Events\QueryExecuted| Query 語句執行後 | | Hyperf\Database\Events\StatementPrepared| SQL 語句 prepared 後 | | Hyperf\Database\Events\TransactionBeginning| 事務開啟後 | | Hyperf\Database\Events\TransactionCommitted| 事務提交後 | | Hyperf\Database\Events\TransactionRolledBack| 事務回滾後 | ### SQL 執行監聽器 根據上述的 ORM 執行事件,接下來我們來實現一個記錄 SQL 的監聽器,達到在每次執行 SQL 時記錄下來並輸出到日誌上。 首先我們定義好 `DbQueryExecutedListener` ,實現 `Hyperf\Event\Contract\ListenerInterface` 介面並對類定義 `Hyperf\Event\Annotation\Listener` 註解,這樣 Hyperf 就會在應用啟動時自動把該監聽器註冊到事件排程器中,並在事件觸發時執行監聽邏輯,示例程式碼如下: ```php logger = $container->get(LoggerFactory::class)->get('sql'); } public function listen(): array { return [ QueryExecuted::class, ]; } /** * @param QueryExecuted $event */ public function process(object $event) { if ($event instanceof QueryExecuted) { $sql = $event->sql; if (! Arr::isAssoc($event->bindings)) { foreach ($event->bindings as $key => $value) { $sql = Str::replaceFirst('?', "'{$value}'", $sql); } } $this->logger->info(sprintf('[%s] %s', $event->time, $sql)); } } } ``` ## 模型事件 模型事件與 `Eloquent ORM` 不太一致,`Eloquent ORM` 使用 `Observer` 監聽模型事件。`Hyperf` 提供 `鉤子函式` 和 `事件監聽` 兩種形式來處理對應的事件。 ### 鉤子函式 | 事件名 | 觸發實際 | 是否阻斷 | 備註 | |:------------:|:----------------:|:--------:|:-------------------------- --:| | booting | 模型首次載入前 | 否 | 程序生命週期中只會觸發一次 | | booted | 模型首次載入後 | 否 | 程序生命週期中只會觸發一次 | | retrieved | 填充資料後 | 否 | 每當模型從 DB 或快取查詢出來後觸發 | | creating | 資料建立時 | 是 | | | created | 資料建立後 | 否 | | | updating | 資料更新時 | 是 | | | updated | 資料更新後 | 否 | | | saving | 資料建立或更新時 | 是 | | | saved | 資料建立或更新後 | 否 | | | restoring | 軟刪除資料恢復時 | 是 | | | restored | 軟刪除資料恢復後 | 否 | | | deleting | 資料刪除時 | 是 | | | deleted | 資料刪除後 | 否 | | | forceDeleted | 資料強制刪除後 | 否 | | 針對某個模型的事件使用十分簡單,只需要在模型中增加對應的方法即可。例如下方儲存資料時,觸發 `saving` 事件,主動覆寫 `created_at` 欄位。 ```php 'integer', 'gender' => 'integer']; public function saving(Saving $event) { $this->setCreatedAt('2019-01-01'); } } ``` ### 事件監聽 當您需要監聽所有的模型事件時,可以很方便的自定義對應的 `Listener`,比如下方模型快取的監聽器,當模型修改和刪除後,會刪除對應快取。 ```php getModel(); if ($model instanceof CacheableInterface) { $model->deleteCache(); } } } } ```