6.1 KiB
事件
模型事件實現 psr/event-dispatcher 接口,默認由 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
declare(strict_types=1);
namespace App\Listener;
use Hyperf\Database\Events\QueryExecuted;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Arr;
use Hyperf\Utils\Str;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
/**
* @Listener
*/
class DbQueryExecutedListener implements ListenerInterface
{
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(ContainerInterface $container)
{
// 輸出到對應名為 sql 的日誌 name,如不存在則需自行添加配置
// 這裏的 sql 日誌 name 不是必須的,只是表達可以將 SQL 執行日誌與普通日誌區分開
$this->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
declare(strict_types=1);
namespace App\Models;
use Hyperf\Database\Model\Events\Saving;
/**
* @property $id
* @property $name
* @property $gender
* @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
*/
protected $fillable = ['id', 'name', 'gender', 'created_at', 'updated_at'];
protected $casts = ['id' => 'integer', 'gender' => 'integer'];
public function saving(Saving $event)
{
$this->setCreatedAt('2019-01-01');
}
}
事件監聽
當您需要監聽所有的模型事件時,可以很方便的自定義對應的 Listener
,比如下方模型緩存的監聽器,當模型修改和刪除後,會刪除對應緩存。
<?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();
}
}
}
}