# 事件监听(后端)

# 事件系统

Laravel 本身带有一套事件系统,因此我们能够方便地实现事件监听来执行某些操作。

在插件的 bootstrap.php 中所返回的函数中,如果您要监听事件,您可以像这样写:

use Illuminate\Contracts\Events\Dispatcher;

return function (Dispatcher $events) {
  // ...
};

# 监听事件

以上面为例,$events 中的 listen 方法可以让您监听事件。listen 方法接收两个参数:第一个是您要监听的事件的类,第二个参数是事件触发后要执行的回调函数。

假设我们现在要监听 RenderingFooter 事件,以便我们往页面添加一些内容。过程如下:

首先要知道要监听的事件的类的所在位置。Blessing Skin 本身所有的事件都位于 App\Events 下,因此 listen 方法的第一个参数为 App\Events\RenderingFooter::class。如果您想要监听来自 Laravel 的事件,请查阅 Laravel 文档。

第二个参数是回调函数。对于用于监听事件的回调函数,都带有一个参数,这个参数是该事件的实例。在我们这个例子中,就是 App\Events\RenderingFooter::class 的实例。

完整的例子如下:

$events->listen(App\Events\RenderingFooter::class, function ($event) {
  // $event-> ...
});

# 编写事件订阅者

除了像前文所述那样通过在 bootstrap.php 中监听事件,您还可以编写事件订阅者。事件订阅者是一个可以在自身内部订阅多个事件的类,即能够在单个类中定义多个事件处理器。

一个事件订阅者的类中必须存在 subscribe 方法,它用于将事件与监听器关联起来。

举个例子,我们要在一个事件订阅者中监听 RenderingHeader 事件和 RenderingFooter 事件,两个使用不同的监听器(即事件触发后执行的代码不相同)。那么我们可以在 src 目录中添加这样的类:

class RenderSubscriber
{
  public function onRenderingHeader($event)
  {
    //
  }

  public function onRenderingFooter($event)
  {
    //
  }

  public function subscribe($events)
  {
    // 假设我们的插件的命名空间是 `Example`

    $events->listen(
      'App\Events\RenderingHeader',
      'Example\RenderSubscriber@onRenderingHeader'
    );

    $events->listen(
      'App\Events\RenderingFooter',
      'Example\RenderSubscriber@onRenderingFooter'
    );
  }
}

接下来要注册这个事件订阅者,在 bootstrap.php 中添加以下代码:

$events->subscribe(Example\RenderSubscriber::class);

# 所有可用的事件

这里列出了 Blessing Skin 中所有定义了的事件。通常事件的实例上会带有一个或多个属性,代表事件触发时涉及的数据。因此,我们约定,我们使用三级标题表示事件的名称,用四级标题列出该事件实例上的属性。

# ConfigureAdminMenu

触发时机

生成管理面板中的侧栏菜单之前。

类型:数组

含义:整个菜单列表

# ConfigureRoutes

触发时机

生成 Laravel 路由之前。

# router

类型:Illuminate\Routing\Router

含义:Laravel 的路由对象,包含一系列可用的方法。

# ConfigureUserMenu

触发时机

生成普通用户界面中的侧栏菜单之前。

类型:数组

含义:整个菜单列表

# PlayerProfileUpdated

触发时机

角色的信息更新之后。

# player

类型:App\Models\Player

含义:角色实例

# PlayerRetrieved

触发时机

从数据库中读取角色信息。

# player

类型:App\Models\Player

含义:角色实例

# PlayerWasAdded

触发时机

角色被添加之后。此时角色已被创建,您可以获取该角色的实例。

# player

类型:App\Models\Player

含义:新创建的角色的实例

# PlayerWasDeleted

触发时机

角色被删除之后。此时角色已被删除,您不能获取该角色的实例。

# playerName

类型:字符串

含义:被删除的角色的名称

# PlayerWillBeAdded

触发时机

角色即将被添加之前。此时角色还没有被创建,您不能获取该角色的实例。

# playerName

类型:字符串

含义:即将被添加的角色的名称

# PlayerWillBeDeleted

触发时机

角色被删除之前。此时角色还没有被删除,您还可以获取该角色的实例。

# player

类型:App\Models\Player

含义:该角色的实例

# PluginWasDeleted

触发时机

插件被删除之前。笔者注:这个事件的命名有误导,尽管名称上是 PluginWasDeleted,但其实此时插件还没有被删除(具体可以阅读 Blessing Skin 源码),否则这个事件也就失去了意义。😅

# plugin

类型:App\Services\Plugin

含义:即将被删除的插件的实例

# PluginWasDisabled

触发时机

插件被禁用之后。

# plugin

类型:App\Services\Plugin

含义:被禁用的插件的实例

# PluginWasEnabled

触发时机

插件被启用之后。

# plugin

类型:App\Services\Plugin

含义:被启用的插件的实例

# RenderingFooter

触发时机

页面在渲染底部的 HTML 之后。此时 Blessing Skin 自己的 JavaScript 文件已经加载完毕,您可以放心地使用来自 Blessing Skin 的前端接口。

# contents

类型:元素类型为字符串的数组

含义:这个数组中的所有元素会被逐个添加到页面底部的 HTML 中。

# addContent

类型:函数

含义:这其实是 RenderingFooter 事件实例上的方法,而不是属性。此方法接收一个字符串作为参数,用于向页面添加内容。

例子:

$event->addContent('<script></script>');

# RenderingHeader

触发时机

页面在渲染顶部的 HTML 之后。注意此时页面的主体内容还没有被渲染。

# contents

类型:元素类型为字符串的数组

含义:这个数组中的所有元素会被逐个添加到页面顶部的 HTML 中。

# addContent

类型:函数

含义:这其实是 RenderingHeader 事件实例上的方法,而不是属性。此方法接收一个字符串作为参数,用于向页面添加内容。

例子:

$event->addContent('<style></style>');

# TextureDeleting

触发时机

材质将被删除。

# contents

类型:App\Models\Texture

含义:正在被删除的材质。

# UserAuthenticated

触发时机

用户认证之后。注意,这不等同于用户登录。具体表现是,不管用户是否已登录,Blessing Skin 都会去检查用户登录状态,如果此时用户已登录(不一定是刚刚登录的,有可能是之前已登录然后访问其它页面,也有可能是用户开启了「记住我」的选项),那么这个事件就会被触发。

# user

类型:App\Models\User

含义:该用户的实例

# UserLoggedIn

触发时机

用户登录之后。

# user

类型:App\Models\User

含义:该用户的实例

# UserProfileUpdated

触发时机

用户的个人资料更新之后。

# type

类型:字符串

含义:表示哪个数据项被更新。目前有以下可用的值:

  • nickname - 表明用户更新了昵称

  • password - 表明用户更新了密码

  • email - 表明用户更新了邮箱地址

# user

类型:App\Models\User

含义:该用户的实例

# UserRegistered

触发时机

用户注册之后。此时该用户已被创建。

# user

类型:App\Models\User

含义:新创建的用户的实例

# UserTryToLogin

触发时机

用户尝试登录时,此时未进行密码验证等操作。

# identification

类型:字符串

含义:用户的标识,可能是用户的邮箱,也可能是用户持有的角色名。具体请看 authType 属性。

# authType

类型:字符串

含义:表示 identification 属性的类型。如果用户以邮箱地址的形式登录,那么这个值为 email;如果用户以他/她持有的角色名登录,那么这个值为 username(您没有看错,是 username 而不是 playerName)。