目录

Backend Events

优质
小牛编辑
146浏览
2023-12-01

Often, an extension will want to react to some events occuring elsewhere in Flarum. For instance, we might want to increment a counter when a new discussion is posted, send a welcome email when a user logs in for the first time, or add tags to a discussion before saving it to the database. These events are known as domain events, and are broadcasted across the framework through Laravel's event system.

For a full list of backend events, see our API documentation. Domain events classes are organized by namespace, usually Flarum\TYPE\Event.

Flarum CLI

You can use the CLI to automatically generate event listeners:


$ flarum-cli make backend event-listener

You can attach a listener to an event using the Event extender:


use Flarum\Extend;
use Flarum\Post\Event\Deleted;
use Symfony\Contracts\Translation\TranslatorInterface;




return [
    (new Extend\Event)
        ->listen(Deleted::class, function($event) {
            // do something here
        })
        ->listen(Deleted::class, PostDeletedListener::class)
];

class PostDeletedListener
{
    protected $translator;


    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }


    public function handle(Deleted $event)
    {
        // Your logic here
    }
}

As shown above, a listener class can be used instead of a callback. This allows you to inject dependencies into your listener class via constructor parameters. In this example we resolve a translator instance, but we can inject anything we want/need.

You can also listen to multiple events at once via an event subscriber. This is useful for grouping common functionality; for instance, if you want to update some metadata on changes to posts:


use Flarum\Extend;
use Flarum\Post\Event\Deleted;
use Flarum\Post\Event\Saving;
use Symfony\Contracts\Translation\TranslatorInterface;




return [
    (new Extend\Event)
        ->subscribe(PostEventSubscriber::class),
];

class PostEventSubscriber
{
    protected $translator;
  
    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }
  
    public function subscribe($events)
    {
        $events->listen(Deleted::class, [$this, 'handleDeleted']);
        $events->listen(Saving::class, [$this, 'handleSaving']);
    }
  
    public function handleDeleted(Deleted $event)
    {
        // Your logic here
    }
  
    public function handleSaving(Saving $event)
    {
        // Your logic here
    }
}

Dispatching events is very simple. All you need to do is inject Illuminate\Contracts\Events\Dispatcher into your class, and then call its dispatch method. For instance:


use Flarum\Post\Event\Deleted;
use Illuminate\Contracts\Events\Dispatcher;




class SomeClass
{
    /**
      * @var Dispatcher
      */
    protected $events;


    /**
      * @param Dispatcher $events
      */
    public function __construct(Dispatcher $events)
    {
        $this->events = $events;
    }


    public function someMethod()
    {
        // Logic
        $this->events->dispatch(
            new Deleted($somePost, $someActor)
        );
        // More Logic
    }
}

As an extension developer you can define your own events to allow yourself (or other extensions) to react to events in your extension. Events are generally instances of simple classes (no need to extend anything). When defining a new event, you'll typically want to use public properties, and maybe some methods for convenience of users. For example, if we take a look at Flarum\Post\Event\Deleted, it's just a wrapping around some data:


<?php


/*
 * This file is part of Flarum.
 *
 * For detailed copyright and license information, please view the
 * LICENSE file that was distributed with this source code.
 */


namespace Flarum\Post\Event;


use Flarum\Post\Post;
use Flarum\User\User;


class Deleted
{
    /**
     * @var Post
     */
    public $post;


    /**
     * @var User
     */
    public $actor;


    /**
     * @param Post $post
     * @param User $user
     */
    public function __construct(Post $post, User $actor = null)
    {
        $this->post = $post;
        $this->actor = $actor;
    }
}