Eloquent ORM Events
Laravel 的 Eloquent ORM 有几种不同的事件:
retrieved
, creating
, created
, updating
, updated
, saving
, saved
, deleting
, deleted
, restoring
, restored
根据这些事件,可以快速在特定情景下,执行一些对应的逻辑操作。比如:在订单的保存事件中,减掉相应的库存。
需求一:快速对入库数据格式化处理
在日程的创建事件中格式化时间戳,项目中包含 web
服务 和 api
服务,之前的开发人员将代码写的比较杂乱,并且未对时间进行统一的格式化。添加日历视图后,日程未按照预期进行显示,在此情况下优先考虑通过事件进行统一处理通过 events
快速处理。
创建观察器 php artisan make:observer CalendarObserver
<?php
namespace App\Observers;
use App\Models\Calendar;
class CalendarObserver
{
public function saved(Calendar $calendar)
{
if ($calendar->start_at != strtotime($calendar->start_at) || $calendar->stop_at != strtotime($calendar->stop_at)) {
$calendar->start_at = strtotime($calendar->start_at);
$calendar->stop_at = strtotime($calendar->stop_at);
// 处理后进行保存
$calendar->save();
}
}
}
需求二:对模型添加操作日志
后续对系统添加操作日志,又监听了 created
,updated
,deleted
事件
<?php
namespace App\Observers;
use App\Models\Calendar;
class CalendarObserver
{
public function created(Calendar $calendar)
{
if (count($calendar->getDirty()) > 0) {
// 记录新增日志
}
}
public function updated(Calendar $calendar)
{
if (count($calendar->getDirty()) > 0) {
// 记录修改日志
}
}
public function deleted(Calendar $calendar)
{
// 记录修改日志
}
public function saved(Calendar $calendar)
{
if ($calendar->start_at != strtotime($calendar->start_at) || $calendar->stop_at != strtotime($calendar->stop_at)) {
$calendar->start_at = strtotime($calendar->start_at);
$calendar->stop_at = strtotime($calendar->stop_at);
// 处理后进行保存
$calendar->save();
}
}
}
预期应该触发一次新增日志,而后触发一次编辑日志:
- 新增日志记录所有的保存字段值
- 编辑日志应该只记录
start_at
和stop_at
两个字段值的变动
实际执行时,新增日志记录为预期效果,但是编辑日志却将新增日志的结果完整的重写了一遍,同时修改了 start_at
和 stop_at
两个字段的值。
对观察器进行分析:
- 新增依次执行了
created
->saved
- 在
saved
事件中又调用了save()
方法, save()
时又触发了updated
->saved
事件,
updated
中获得到的 getDirty()
与 created
中的 getDirty()
仅有 saved
中修改的两个字段不同,所以产生与预期不同的结果。
对事件进行调整,首先明确事件的依次执行顺序:
新增时:
saving
-> creating
-> created
-> saved
编辑时:
saving
-> updating
-> updated
-> saved
其中的任何一个事件中 return false;
后续的事件都不会再执行。
最初使用 saved
的事件,是因为在 created
和 udpated
的时候都会执行,所以这里将事件考虑放到同样都会执行的 saving
事件中。
因为 saving
事件是最先调用的,created
和 updated
均在其后,所以只需在其中正常处理逻辑即可,不需要像 saved
中的实现一样,需要再次调用 save()
才能保存。
<?php
namespace App\Observers;
use App\Models\Calendar;
class CalendarObserver
{
public function created(Calendar $calendar)
{
if (count($calendar->getDirty()) > 0) {
// 记录新增日志
}
}
public function updated(Calendar $calendar)
{
if (count($calendar->getDirty()) > 0) {
// 记录修改日志
}
}
public function deleted(Calendar $calendar)
{
// 记录删除日志
}
public function saving(Calendar $calendar)
{
if ($calendar->start_at != strtotime($calendar->start_at) || $calendar->stop_at != strtotime($calendar->stop_at)) {
$calendar->start_at = strtotime($calendar->start_at);
$calendar->stop_at = strtotime($calendar->stop_at);
}
}
}
最后记录的日志,新增只会触发一次 created
日志,不再是最初预期的一个新增日志,同时跟一个编辑的日志,更加完美。