【laravel】Eloquent 模型事件和监听方式

所有支持的模型事件

在 Eloquent 模型类上进行查询、插入、更新、删除操作时,会触发相应的模型事件,不管你有没有监听它们。这些事件包括:

retrieved 获取到模型实例后触发
creating 插入到数据库前触发
created 插入到数据库后触发
updating 更新到数据库前触发
updated 更新到数据库后触发
saving 保存到数据库前触发(插入/更新之前,无论插入还是更新都会触发)
saved 保存到数据库后触发(插入/更新之后,无论插入还是更新都会触发)
deleting 从数据库删除记录前触发
deleted 从数据库删除记录后触发
restoring 恢复软删除记录前触发
restored 恢复软删除记录后触发

注:批量更新时不会触发相应事件,因为是直接走查询构建器完成的,绕过了模型方法。

通过监听这些事件,我们可以在 Eloquent 模型实例生命周期的特定阶段执行特定操作。在 Laravel 中我们有多种方式来监听模型事件。

通过静态方法监听模型事件

通过在模型类上调用要监听事件对应的静态方法,一般我们会在某个服务提供者的 boot 方法中完成这项工作,比如 EventServiceProvider。举个例子,假设我们要监听每次获取模型实例的事件并在日志中记录查询到的用户信息,可以这么做:

// app/Providers/EventServiceProvider.php

public function boot()
{
    parent::boot();
    // 监听模型获取事件
    User::retrieved(function ($user) {
        Log::info(‘从模型中获取用户[‘ . $user->id . ‘]:‘ . $user->name);
    });
}

上面这段代码中表示我们在 User 模型上监听 retrieved 事件,然后通过一个闭包函数执行对应的处理逻辑,该闭包函数传入参数是模型实例,在处理逻辑中,我们通过 Log 门面记录日志信息。

通过订阅者监听模型事件

①先创建对应的事件类

以删除模型为例进行演示,分别定义一个删除前事件类和删除后事件类。我们通过 Artisan 命令来完成事件类初始化:

php artisan make:event UserDeleting
php artisan make:event UserDeleted

然后在这两个事件类中都添加 $user 属性并在构造函数中传入:

// app/Events/UserDeleted.php
// app/Events/UserDeleting.php

public $user;
public function __construct(User $user)
{
    $this->user = $user;
}

②建立模型事件与自定义事件类的映射

在 User 模型类中建立模型事件与自定义事件类的映射,这可以通过 $dispatchesEvents 属性来完成:

//建立模型事件与自定义事件类的映射
protected $dispatchesEvents = [
    ‘deleting‘ => UserDeleting::class,
    ‘deleted‘ => UserDeleted::class
];

这样,当我们触发 deleting 和 deleted 事件时,底层会将其转化为触发 UserDeleting 和 UserDeleted 事件。

③创建订阅者监听事件类

我们还要监听上述自定义的事件类,我们可以通过在 EventServiceProvider 的 listen 属性中为每个事件绑定对应的监听器类,也可以通过为某个模型类创建一个事件订阅者类来统一处理该模型中的所有事件。在 app/Listeners 目录下创建一个 UserEventSubscriber.php 文件作为订阅者类,编写代码如下

<?php

namespace App\Listeners;

use App\Events\UserDeleted;
use App\Events\UserDeleting;
use Illuminate\Support\Facades\Log;

class UserEventSubscriber
{
    /**
     * 处理用户删除前事件
     */
    public function onUserDeleting($event)
    {
        Log::info(‘用户即将删除[‘ . $event->user->id . ‘]:‘ . $event->user->name);
    }

    /**
     * 处理用户删除后事件
     */
    public function onUserDeleted($event)
    {
        Log::info(‘用户已经删除[‘ . $event->user->id . ‘]:‘ . $event->user->name);
    }

    /**
     * 为订阅者注册监听器
     *
     * @param  Illuminate\Events\Dispatcher $events
     */
    public function subscribe($events)
    {
        $events->listen(
            UserDeleting::class,
            UserEventSubscriber::class . ‘@onUserDeleting‘
        );

        $events->listen(
            UserDeleted::class,
            UserEventSubscriber::class . ‘@onUserDeleted‘
        );
    }
}

④在 EventServiceProvider 中注册这个订阅者

// app/Providers/EventServiceProvider.php

protected $subscribe = [
    UserEventSubscriber::class
];

通过观察者监听模型事件

针对模型事件这种特殊的事件类型,Laravel 还为我们提供了观察者类来处理模型事件的监听。观察者可以看作是上述订阅者处理模型事件的简化版本,我们不需要自定义事件类,不需要建立映射关系,只需要在观察者类中将需要监听的事件定义为同名方法,并在相应方法中编写业务处理代码即可。当某个模型事件触发时,Eloquent 底层会去该模型上注册的观察者类中通过反射查找是否定义了对应的方法,如果定义了则执行相应的逻辑,否则忽略。

下面以 saving 和 saved 事件为例演示如何通过观察者监听模型事件。

①通过 Artisan 命令创建针对 User 模型的观察者

php artisan make:observer UserObserver --model=Model/User

默认生成的 UserObserver 会为 created、 updateddeletedrestoredforceDeleted(强制删除) 事件定义一个空方法:

<?php

namespace App\Observers;

use App\User;

class UserObserver
{
    /**
     * Handle the user "created" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function created(User $user)
    {
        //
    }

    /**
     * Handle the user "updated" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function updated(User $user)
    {
        //
    }

    /**
     * Handle the user "deleted" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function deleted(User $user)
    {
        //
    }

    /**
     * Handle the user "restored" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function restored(User $user)
    {
        //
    }

    /**
     * Handle the user "force deleted" event.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function forceDeleted(User $user)
    {
        //
    }
}

可以把前面定义的 retriveddeletingdeleted 事件监听代码迁移过来,也可以将不需监听的事件方法移除,这里我们将编写保存模型时涉及的模型事件,包括 savingcreatingupdatingupdatedcreatedsaved

<?php

namespace App\Observers;

use App\Model\User;
use Log;

class UserObserver
{
    public function saving(User $user)
    {
        Log::info(‘即将保存用户到数据库[‘ . $user->id . ‘]‘ . $user->name);
    }

    public function creating(User $user)
    {
        Log::info(‘即将插入用户到数据库[‘ . $user->id . ‘]‘ . $user->name);
    }

    public function updating(User $user)
    {
        Log::info(‘即将更新用户到数据库[‘ . $user->id . ‘]‘ . $user->name);
    }

    public function updated(User $user)
    {
        Log::info(‘已经更新用户到数据库[‘ . $user->id . ‘]‘ . $user->name);
    }

    public function created(User $user)
    {
        Log::info(‘已经插入用户到数据库[‘ . $user->id . ‘]‘ . $user->name);
    }

    public function saved(User $user)
    {
        Log::info(‘已经保存用户到数据库[‘ . $user->id . ‘]‘ . $user->name);
    }
}

②注册相应观察者

编写好观察者后,需要将其注册到 User 模型上才能生效,我们可以在 EventServiceProvider 的 boot 方法中完成该工作:

public function boot()
{
    parent::boot();

    //注册User模型的观察者
    User::observe(UserObserver::class);
}

结语

关于三种监听 Eloquent 模型事件的方式,如何选择,视情况而定。如果只是监听一两个模型事件,第一种方式比较合适;如果仅仅监听系统支持的模型事件,并且要监听多个模型的多个事件,观察者是最佳选择;如果还要在模型类上监听更多系统模型事件之外的自定义事件,则使用订阅者来监听比较合适。

原文地址:https://www.cnblogs.com/jxl1996/p/10339563.html

时间: 2024-10-13 22:46:13

【laravel】Eloquent 模型事件和监听方式的相关文章

自己定义对象的监听方式

问题描写叙述: 当一个事件的触发不定期的时候,即我们不知道这个触发何时来到,可是我们却要对这个触发运行某些方法,怎样实现? 可能的解决方式: 我当时就想到了,这个问题类似与Android的部件监听(我没有去看Android的源代码,太懒了...).因为如今还在研读Thinking in Java这样的入门书籍,突然来了想法,罗列例如以下,能够通过接口. 以下是我写的一个測试的样例 首先是一个类似Button的部件 package com.example.androidtest2.service;

自定义对象的监听方式

问题描述: 当一个事件的触发不定期的时候,即我们不知道这个触发何时来到,但是我们却要对这个触发执行某些方法,如何实现? 可能的解决方案: 我当时就想到了,这个问题类似与Android的部件监听(我没有去看Android的源码,太懒了...).由于现在还在研读Thinking in Java这种入门书籍,突然来了想法,罗列如下,可以通过接口. 下面是我写的一个测试的例子 首先是一个类似Button的部件 package com.example.androidtest2.service; /** *

Android 四种点击监听方式

Android点击监听事件经常用到,经常用到的有以下几种 第一种:最常用到的,通过实现OnClickListen,实现OnClick方法去实现 public class MainActivity extends Activity implements OnClickListener // 用实现接口的方式实现点击 button1 = (Button) findViewById(R.id.button1); button1.setOnClickListener(this); @Override p

深入理解Spring的容器内事件发布监听机制

目录 1. 什么是事件监听机制 2. JDK中对事件监听机制的支持 2.1 基于JDK实现对任务执行结果的监听 3.Spring容器对事件监听机制的支持 3.1 基于Spring实现对任务执行结果的监听 4.Spring事件监听源码解析 4.1 初始化事件发布器流程 4.2 注册事件监听器流程 4.3 容器事件发布流程 5.总结 1. 什么是事件监听机制 在讲解事件监听机制前,我们先回顾下设计模式中的观察者模式,因为事件监听机制可以说是在典型观察者模式基础上的进一步抽象和改进.我们可以在JDK或

鼠标滚轮事件的监听

鼠标滚轮事件的监听原理:判断鼠标滚轮的滚动获取一个值,根据这个值判断滚动的方向.分析:首先,判断滚轮方向.Firefox:detail,取值为-/+3(负值向上,正值向下):其他:wheelDelta,取值为+/-120(正值向上,负值向下).兼容所有浏览器的的封装: ? 1 2 3 4 5 6 7 8 9 10 function scrollEvent(ev){     ev = ev || window.event;     var data = '';     if(ev.wheelDel

Java Swing界面编程(24)---事件处理:键盘事件及监听处理

在Swing的事件处理中也可以对键盘的操作进行监听,直接使用KeyListener接口即可. package com.beyole.util; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax

Java Swing界面编程(25)---事件处理:鼠标事件及监听处理

如果想对一个鼠标的操作进行监听,如果鼠标按下.松开等,则可以使用MouseListener接口. package com.beyole.util; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import

Java Swing界面编程(22)---事件处理:动作事件及监听处理

要想让一个按钮变得有意义,就必须使用事件处理.在swing的事件处理中,可以使用ActionListener接口处理按钮的动作事件. package com.beyole.util; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter

Android开发之PullToRefresh的Click点击事件的监听实现长按删除Item

本文为原创博客,出自http://blog.csdn.net/minimicall 到今天为止,搜芽的卖家版本应该来说已经基本完成,攻坚克难的一路过来.速度也控制的比较好. 项目过程进度 从任务分配量上来看,基本还是我个人英雄主义.接下来这样不行.但暂时也没办法,师弟还需要一个学习的过程.智质不错,而且态度端正.相信搜芽买家,他就可以承担更多的开发任务了. 接下来进入正题,说我们的PullToRefresh的点击事件.其实,我是想做长按进入删除的. 见效果图.当然这个是我做出来之后的了,但做出来