模型事件的触发时机
模型事件:
模型事件:retrieved、creating、created、updating、updated、saving、saved、deleting、deleted、restoring、restored。
L02中的使用场景:
- SEO 友好的 URL:
- TopicObserver::saving();
- 入库前对 slug 字段进行赋值。
- 实现对评论的计数:
- ReplyObserver::created();
- 每增加一条评论,就需要重新对评论数统计。
- 对评论进行过滤。(防御 XSS 攻击)
- ReplyObserver::creating();
- 过滤评论中的 JS 脚本。
- 用户回复主题后,通知到主题作者。
- ReplyObserver::created();
- 当用户回复发布成功后,就通知主题的作者。
- 实现对评论的计数
- ReplyObserver::deleted();
- 用户删除回复后,需要重新统计回复数。
- 话题连带删除
- TopicObserver::deleted();
- 当删除了话题时,需要将该话题下的所有评论都删除。
问题
模型事件有11个,分为 ed 和 ing 两种。跟着教程敲代码的时候感觉不难,但是如果要自己在特定的场景下使用正确的模型事件很难。因为我并没有找到背后的规律,只是知道了几种特例。今天看了一天的文章,码源也看了不少,但是感觉迷迷糊糊的。看累了,躺在床上思考了一下,发现自己的目的不明确。
今天我主要想解决:
如何正确的使用模型事件来达到自己的目的。而不是模型事件的实现原理。而我今天看的码源大多数和模型事件的实现原理有关,所以感觉摸不着边。而且现在自己的道行太浅,看码源有点吃力,模型事件的实现原理以后再说吧。
save 方法
明确了自己的目的,看文章就能抓住重点了。在laravel Eloquent save 触发了哪些事件一文中,找到了线索。正确使用模型事件的关键就在于需要知道模型事件的触发时机。
由laravel Eloquent save 触发了哪些事件一文可知,调用 Model::save() 方法时,就会触发大多数常见的模型事件。因为在调用 Model::update() 方法时,最终还是会调用 Model::save()。
Model::update()码源如下:
<?php
...
abstract class Model ...
...
public function update(array $attributes = [], array $options = [])
{
if (! $this->exists) {
return false;
}
// 这里调用了 save 方法。
return $this->fill($attributes)->save($options);
}
...
所以只要把 Model::save() 方法理清了,就能把大多数事件模型的触发时机搞清楚。但是laravel Eloquent save 触发了哪些事件一文讲的很清楚,就不再赘述了(炒冷饭也没意思)。直接上结论:
- 触发顺序
- 新创建的对象,save 依次触发
saving
=>creating
=>created
=>saved
; - 已存在的对象,save 依次触发
saving
=>updating
=>updated
=>saved
;
- 新创建的对象,save 依次触发
- 触发时机:
saving
模型事件触发于 Model::save() 方法被调用后。- 如果模型还未创建:
creating
模型事件触发于入库前。created
模型事件触发于入库后。
- 如果模型已经存在:
updating
模型事件触发于更新前。updated
模型事件触发于更新后。
delete 方法
当调用 delete 方法时,如果一切正常,就会触发 deleting 和 deleted 模型事件。Model::delete() 方法码源如下:
<?php
...
abstract class Model ...
...
public function delete()
{
$this->mergeAttributesFromCachedCasts();
if (is_null($this->getKeyName())) {
throw new LogicException('No primary key defined on model.');
}
// If the model doesn't exist, there is nothing to delete so we'll just return
// immediately and not do anything else. Otherwise, we will continue with a
// deletion process on the model, firing the proper events, and so forth.
if (! $this->exists) {
return;
}
if ($this->fireModelEvent('deleting') === false) {
return false;
}
// Here, we'll touch the owning models, verifying these timestamps get updated
// for the models. This will allow any caching to get broken on the parents
// by the timestamp. Then we will go ahead and delete the model instance.
$this->touchOwners();
$this->performDeleteOnModel();
// Once the model has been deleted, we will fire off the deleted event so that
// the developers may hook into post-delete operations. We will then return
// a boolean true as the delete is presumably successful on the database.
$this->fireModelEvent('deleted', false);
return true;
}
...
跟着注释理一遍过程:
- 如果模型存在,就会触发 deleting 模型事件。
- 一旦模型被删除了,就会触发 deleted 模型事件。
小节: - 触发顺序:
deleting
=>deleted
;
- 触发时机:
- deleting 模型事件触发在模型被删除之前。
- deleted 模型事件触发在模型删除之后。
教训
在学习的时候,一定要把目的搞清楚了,不然学了半天都不知道自己在干啥。
参考
本作品采用《CC 协议》,转载必须注明作者和本文链接