3分钟短文 | Laravel模型关联删除表记录,用观察者还是事件钩子

2020-07-27 22:09:18 浏览数 (1)

引言

说一个场景需求,假如有一个user模型,用户的上传图片存在另外一张表photo内。当删除该用户时,想要同时删除关联的photo表的相关记录。应该用什么办法呢?

本文就来说说 Laravel ORM 操作中的事件钩子。

学习时间

如果想要实现上一节所说的需求,代码写起来可能是这样的。

代码语言:javascript复制
$user->delete();

当该事件发生时,我们接着执行关联的删除。

代码语言:javascript复制
$this->photo()->delete();

如果程序中每个地方逻辑上进行了删除操作,岂不是都要手动这么重复写,这些重复代码真的是无用功。

那么Laravel中是怎么写的呢,如何自动在触发了 user 的删除时间,自动进行 photo 的删除操作?我们可以借助于 Eloquent ORM 提供的 deleting 事件,做删除动作。

代码如下:

只用在 Model 模型类中继承并实现 boot 方法,然后调用模型的 deleting 事件,使用回调声明执行的动作即可。

这样在删除动作上只用维护一处代码,程序内所有的 delete 事件都会自动触发该动作,复用率大大地提升了。

再进一步

实现同样的需求,往往有很多种方式。你还可以换用一种事件钩子方式,就是 Laravel 提供的 观察者(Observers)方式。

首先,在 AppServiceProvider 内注册某模型的观察者:

代码语言:javascript复制
public function boot()
{
    User::observe(UserObserver::class);
}

然后添加观察者类 UserObserver:

代码语言:javascript复制
class UserObserver
{
    public function deleting(User $user)
    {
         $user->photos()->delete();
    }
}

这样就用观察者盯着 User 模型的动作,如果发现,立即执行 UserObserver 内对应的动作。

这样把程序功能单独摘开,调试的时候非常方便。而且对于后期有修改,或者复杂的动作,处理起来就会游刃有余,不会把代码逻辑写的一堆又一堆,在事件方法内,你只需集中处理一次就够了!

这才是有弹性的代码!鲁棒性非常好的代码!

不推荐的方法

还有一种方法,我们本不打算推荐,但是考虑到有的初学者容易犯此类错误,就拿出来最为参照。

程序功能应该单一。比如,尽量避免把数据关联操作放到数据库执行。MySQL提供了外键约束,并且可以定义触发器用于批次动作处理。

那么使用 Laravel migrations 时,创建photo表的外键关联事件:

代码语言:javascript复制
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

这样做,就是把动作交给了MySQL处理。

非常不利于程序调试,和数据全程追溯!不推荐使用!

写在最后

本文通过3种方式,实现了Laravel中关联删除表记录的功能。推荐写法是第一种,直接在模型内声明事件钩子,处理起来较为方便;

第二种会造成虽然整洁,但是如果注册的观察者过多,不易于模型与观察者之间的关联调试;

第三种方式,完全不推荐,我们不应该把数据有效性和完整性的操作交给MySQL。

Happy coding :-)

0 人点赞