2019-03-19 14:03:48 +08:00
|
|
|
|
# 事件
|
|
|
|
|
|
2020-04-01 00:30:04 +08:00
|
|
|
|
模型事件實現 [psr/event-dispatcher](https://github.com/php-fig/event-dispatcher) 介面,預設由 [hyperf/event](https://github.com/hyperf/event) 元件提供功能支援。
|
2019-05-22 13:24:23 +08:00
|
|
|
|
|
2020-04-01 00:30:04 +08:00
|
|
|
|
## 執行事件
|
|
|
|
|
|
|
|
|
|
在 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 就會在應用啟動時自動把該監聽器註冊到事件排程器中,並在事件觸發時執行監聽邏輯,示例程式碼如下:
|
2019-03-19 14:03:48 +08:00
|
|
|
|
|
2019-03-19 14:52:21 +08:00
|
|
|
|
```php
|
2019-03-19 14:03:48 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
2020-01-16 14:33:32 +08:00
|
|
|
|
namespace App\Listener;
|
2019-03-19 14:03:48 +08:00
|
|
|
|
|
2019-03-21 16:22:34 +08:00
|
|
|
|
use Hyperf\Database\Events\QueryExecuted;
|
|
|
|
|
use Hyperf\Event\Annotation\Listener;
|
|
|
|
|
use Hyperf\Event\Contract\ListenerInterface;
|
|
|
|
|
use Hyperf\Logger\LoggerFactory;
|
2019-03-19 14:03:48 +08:00
|
|
|
|
use Hyperf\Utils\Arr;
|
|
|
|
|
use Hyperf\Utils\Str;
|
|
|
|
|
use Psr\Container\ContainerInterface;
|
2019-03-21 16:22:34 +08:00
|
|
|
|
use Psr\Log\LoggerInterface;
|
2019-03-19 14:03:48 +08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @Listener
|
|
|
|
|
*/
|
|
|
|
|
class DbQueryExecutedListener implements ListenerInterface
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* @var LoggerInterface
|
|
|
|
|
*/
|
|
|
|
|
private $logger;
|
|
|
|
|
|
2020-04-01 00:30:04 +08:00
|
|
|
|
public function __construct(ContainerInterface $container)
|
2019-03-19 14:03:48 +08:00
|
|
|
|
{
|
2020-04-01 00:30:04 +08:00
|
|
|
|
// 輸出到對應名為 sql 的日誌 name,如不存在則需自行新增配置
|
|
|
|
|
// 這裡的 sql 日誌 name 不是必須的,只是表達可以將 SQL 執行日誌與普通日誌區分開
|
|
|
|
|
$this->logger = $container->get(LoggerFactory::class)->get('sql');
|
2019-03-19 14:03:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 14:52:21 +08:00
|
|
|
|
```
|
2019-03-19 14:03:48 +08:00
|
|
|
|
|
|
|
|
|
## 模型事件
|
2019-03-21 13:17:51 +08:00
|
|
|
|
|
2020-04-01 00:30:04 +08:00
|
|
|
|
模型事件與 `Eloquent ORM` 不太一致,`Eloquent ORM` 使用 `Observer` 監聽模型事件。`Hyperf` 提供 `鉤子函式` 和 `事件監聽` 兩種形式來處理對應的事件。
|
2019-05-22 13:24:23 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
### 鉤子函式
|
2019-05-22 13:24:23 +08:00
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
| 事件名 | 觸發實際 | 是否阻斷 | 備註 |
|
2019-03-25 19:00:55 +08:00
|
|
|
|
|:------------:|:----------------:|:--------:|:-------------------------- --:|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
| booting | 模型首次載入前 | 否 | 程序生命週期中只會觸發一次 |
|
|
|
|
|
| booted | 模型首次載入後 | 否 | 程序生命週期中只會觸發一次 |
|
|
|
|
|
| retrieved | 填充資料後 | 否 | 每當模型從 DB 或快取查詢出來後觸發 |
|
|
|
|
|
| creating | 資料建立時 | 是 | |
|
|
|
|
|
| created | 資料建立後 | 否 | |
|
|
|
|
|
| updating | 資料更新時 | 是 | |
|
|
|
|
|
| updated | 資料更新後 | 否 | |
|
|
|
|
|
| saving | 資料建立或更新時 | 是 | |
|
|
|
|
|
| saved | 資料建立或更新後 | 否 | |
|
2021-02-19 12:53:50 +08:00
|
|
|
|
| restoring | 軟刪除資料恢復時 | 是 | |
|
|
|
|
|
| restored | 軟刪除資料恢復後 | 否 | |
|
2019-12-12 16:24:04 +08:00
|
|
|
|
| deleting | 資料刪除時 | 是 | |
|
|
|
|
|
| deleted | 資料刪除後 | 否 | |
|
|
|
|
|
| forceDeleted | 資料強制刪除後 | 否 | |
|
|
|
|
|
|
|
|
|
|
針對某個模型的事件使用十分簡單,只需要在模型中增加對應的方法即可。例如下方儲存資料時,觸發 `saving` 事件,主動覆寫 `created_at` 欄位。
|
2019-03-21 13:17:51 +08:00
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Models;
|
|
|
|
|
|
|
|
|
|
use Hyperf\Database\Model\Events\Saving;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @property $id
|
|
|
|
|
* @property $name
|
2019-03-21 16:22:34 +08:00
|
|
|
|
* @property $gender
|
2019-03-21 13:17:51 +08:00
|
|
|
|
* @property $created_at
|
|
|
|
|
* @property $updated_at
|
|
|
|
|
*/
|
|
|
|
|
class User extends Model
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* The table associated with the model.
|
|
|
|
|
*
|
|
|
|
|
* @var string
|
|
|
|
|
*/
|
|
|
|
|
protected $table = 'user';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The attributes that are mass assignable.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2019-03-21 16:22:34 +08:00
|
|
|
|
protected $fillable = ['id', 'name', 'gender', 'created_at', 'updated_at'];
|
2019-03-21 13:17:51 +08:00
|
|
|
|
|
2019-03-21 16:22:34 +08:00
|
|
|
|
protected $casts = ['id' => 'integer', 'gender' => 'integer'];
|
2019-03-21 13:17:51 +08:00
|
|
|
|
|
|
|
|
|
public function saving(Saving $event)
|
|
|
|
|
{
|
|
|
|
|
$this->setCreatedAt('2019-01-01');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-22 13:24:23 +08:00
|
|
|
|
```
|
|
|
|
|
|
2019-12-12 16:24:04 +08:00
|
|
|
|
### 事件監聽
|
2019-05-22 13:24:23 +08:00
|
|
|
|
|
2020-04-01 00:30:04 +08:00
|
|
|
|
當您需要監聽所有的模型事件時,可以很方便的自定義對應的 `Listener`,比如下方模型快取的監聽器,當模型修改和刪除後,會刪除對應快取。
|
2019-05-22 13:24:23 +08:00
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace Hyperf\ModelCache\Listener;
|
|
|
|
|
|
|
|
|
|
use Hyperf\Database\Model\Events\Deleted;
|
|
|
|
|
use Hyperf\Database\Model\Events\Event;
|
|
|
|
|
use Hyperf\Database\Model\Events\Saved;
|
|
|
|
|
use Hyperf\Event\Annotation\Listener;
|
|
|
|
|
use Hyperf\Event\Contract\ListenerInterface;
|
|
|
|
|
use Hyperf\ModelCache\CacheableInterface;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @Listener
|
|
|
|
|
*/
|
|
|
|
|
class DeleteCacheListener implements ListenerInterface
|
|
|
|
|
{
|
|
|
|
|
public function listen(): array
|
|
|
|
|
{
|
|
|
|
|
return [
|
|
|
|
|
Deleted::class,
|
|
|
|
|
Saved::class,
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function process(object $event)
|
|
|
|
|
{
|
|
|
|
|
if ($event instanceof Event) {
|
|
|
|
|
$model = $event->getModel();
|
|
|
|
|
if ($model instanceof CacheableInterface) {
|
|
|
|
|
$model->deleteCache();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-16 14:33:32 +08:00
|
|
|
|
```
|