概述
在 laravel 通过 model 与数据库的连接操作中,会触发一些事件。事件允许模型在变动的时候通过构造器传送模型的实例。为此可以通过该特性以观察者的方式来做一些功能模块解耦的工作。通过文档不能直观的看到事件的触发顺序,故而整理一篇文章。
本文基于 laravel 8.x 讲解与整理相关的功能点
生命周期
事件 | 触发条件(必须通过 ORM) |
---|
retrieved | 执行查询 sql 后触发 |
creating | 执行插入 sql 前触发 |
created | 执行插入 sql 后触发 |
updating | 执行修改 sql 前触发 |
updated | 执行修改 sql 后触发 |
saving | 执行插入或修改 sql 前触发 |
saved | 执行插入或修改 sql 后触发 |
deleting | 执行删除 sql 前触发(软删除也会触发) |
deleted | 执行删除 sql 后触发(软删除也会触发) |
restoring | 恢复软删除前触发 |
restored | 恢复软删除后触发 |
replicating | 模型执行 replicate() 函数触发 |
配置测试代码
表结构
1
2
3
4
5
6
7
8
9
10
11
| CREATE TABLE `t_users` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
`age` tinyint unsigned NOT NULL DEFAULT '0',
`sex` tinyint NOT NULL DEFAULT '0' COMMENT '1:男 2:女',
`created_ymd` int NOT NULL DEFAULT '0',
`created_at` int NOT NULL DEFAULT '0',
`updated_at` int NOT NULL DEFAULT '0',
`deleted_at` int NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
模型
为了更直观这里使用闭包方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| <?php
namespace App\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Log;
class TUser extends BaseModel
{
use SoftDeletes;
protected $fillable = [
'name',
'age',
'sex',
];
protected $hidden = [
'deleted_at',
];
protected static function booted()
{
static::retrieved(function (TUser $user) {
Log::info('retrieved');
});
static::creating(function (TUser $user) {
Log::info('creating');
});
static::created(function (TUser $user) {
Log::info('created');
});
static::updating(function (TUser $user) {
Log::info('updating');
});
static::updated(function (TUser $user) {
Log::info('updated');
});
static::saving(function (TUser $user) {
Log::info('saving');
});
static::saved(function (TUser $user) {
Log::info('saved');
});
static::deleting(function (TUser $user) {
Log::info('deleting');
});
static::deleted(function (TUser $user) {
Log::info('deleted');
});
static::restoring(function (TUser $user) {
Log::info('restoring');
});
static::restored(function (TUser $user) {
Log::info('restored');
});
static::replicating(function (TUser $user) {
Log::info('replicating');
});
}
}
|
测试生命周期
创建记录
1
2
3
4
5
6
| TUser::query()
->create([
'name' => 'test',
'age' => '20',
'sex' => '1',
]);
|
1
2
3
4
5
| local.INFO: saving
local.INFO: creating
local.INFO: insert into `t_users` (`name`, `age`, `sex`, `updated_at`, `created_ymd`, `created_at`) values ('test', '20', '30', '1651049606', '20220427', '1651049606')
local.INFO: created
local.INFO: saved
|
查询记录
1
| TUser::query()->find(1);
|
1
2
| local.INFO: select * from `t_users` where `t_users`.`id` = '1' and `t_users`.`deleted_at` is null limit 1
local.INFO: retrieved
|
修改记录
注意:通过 Eloquent 进行批量更新时,被更新模型的 saved
和 updated
, deleting
和 deleted
事件不会被触发。这是因为批量更新时,并没有真的获取模型。
1
2
3
4
| // 修改记录需要先获取到模型才会触发事件
// 例如这样不会触发模型事件:TUser::query()->where('id', '=', 1)->update(['age' => 21]);
$user = TUser::query()->find(1);
$user->update(['age' => 21]);
|
1
2
3
4
5
6
7
8
| local.INFO: select * from `t_users` where `t_users`.`id` = '1' and `t_users`.`deleted_at` is null limit 1
local.INFO: retrieved
local.INFO: saving
local.INFO: updating
local.INFO: update `t_users` set `age` = '21', `t_users`.`updated_at` = '1651050127' where `id` = '1'
local.INFO: updated
local.INFO: saved
|
删除记录
注意:destroy
方法会分别加载每个模型,并在其上调用 delete
方法,以便触发 deleting
和 deleted
事件。
1
2
| // 删除同理,需要先获取到模型才能触发事件,laravel 提供 destroy
TUser::destroy(1);
|
1
2
3
4
5
6
| local.INFO: select * from `t_users` where `id` in ('1') and `t_users`.`deleted_at` is null
local.INFO: retrieved
local.INFO: deleting
local.INFO: update `t_users` set `deleted_at` = '1651050766', `t_users`.`updated_at` = '1651050766' where `id` = '1'
local.INFO: deleted
|
恢复软删除
1
2
| // 同样恢复软删除需要先把模型查询出来
TUser::onlyTrashed()->find(1)->restore();
|
1
2
3
4
5
6
7
8
9
10
| local.INFO: select * from `t_users` where `t_users`.`deleted_at` is not null and `t_users`.`id` = '1' limit 1
local.INFO: retrieved
local.INFO: restoring
local.INFO: saving
local.INFO: updating
local.INFO: update `t_users` set `deleted_at` = '', `t_users`.`updated_at` = '1651051392' where `id` = '1'
local.INFO: updated
local.INFO: saved
local.INFO: restored
|
复制模型
1
2
3
4
5
6
7
8
9
10
| $user = TUser::query()
->create([
'name' => 'test',
'age' => '20',
'sex' => '1',
]);
$newUser = $user->replicate()->fill([
'age' => 21
]);
$newUser->save(); // 即使最后不 save 也会触发 replicating 事件
|
1
2
3
4
5
6
7
8
9
10
11
12
| local.INFO: saving
local.INFO: creating
local.INFO: insert into `t_users` (`name`, `age`, `sex`, `updated_at`, `created_ymd`, `created_at`) values ('test', '20', '1', '1651051834', '20220427', '1651051834')
local.INFO: created
local.INFO: saved
local.INFO: replicating
local.INFO: saving
local.INFO: creating
local.INFO: insert into `t_users` (`name`, `age`, `sex`, `created_ymd`, `updated_at`, `created_at`) values ('test', '21', '1', '20220427', '1651051834', '1651051834')
local.INFO: created
local.INFO: saved
|