模型事件的触发时机

模型事件:#

模型事件:retrieved、creating、created、updating、updated、saving、saved、deleting、deleted、restoring、restored。

L02 中的使用场景:#

  1. SEO 友好的 URL:
  • TopicObserver::saving();
  • 入库前对 slug 字段进行赋值。
  1. 实现对评论的计数:
  • ReplyObserver::created();
  • 每增加一条评论,就需要重新对评论数统计。
  1. 对评论进行过滤。(防御 XSS 攻击)
  • ReplyObserver::creating();
  • 过滤评论中的 JS 脚本。
  1. 用户回复主题后,通知到主题作者。
  • ReplyObserver::created();
  • 当用户回复发布成功后,就通知主题的作者。
  1. 实现对评论的计数
  • ReplyObserver::deleted();
  • 用户删除回复后,需要重新统计回复数。
  1. 话题连带删除
  • 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 触发了哪些事件一文讲的很清楚,就不再赘述了(炒冷饭也没意思)。直接上结论:

  1. 触发顺序
    • 新创建的对象,save 依次触发 saving=>creating=>created=>saved;
    • 已存在的对象,save 依次触发 saving=>updating=>updated=>saved;
  2. 触发时机:
    • 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;
}
...

跟着注释理一遍过程:

  1. 如果模型存在,就会触发 deleting 模型事件。
  2. 一旦模型被删除了,就会触发 deleted 模型事件。
    小节:
  3. 触发顺序:
    • deleting=>deleted;
  4. 触发时机:
    • deleting 模型事件触发在模型被删除之前。
    • deleted 模型事件触发在模型删除之后。

教训#

在学习的时候,一定要把目的搞清楚了,不然学了半天都不知道自己在干啥。

参考#

  1. Laravel 模型事件入门
  2. Laravel 中的模型事件与 Observer
  3. laravel Eloquent save 触发了哪些事件
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。