Eventsregistered

  1. How does the framework load registered events at startup?
  1. How does the framework trigger events?

1. Register in the container firsteventsGlobal object of.

The events code is registered in the Application constructor

protected function registerBaseServiceProviders()
{
    $this->register(new EventServiceProvider($this));
    $this->register(new LogServiceProvider($this));
    $this->register(new RoutingServiceProvider($this));
}
Copy the code

A $this – > register (new EventServiceProvider ($this));

$this-> Register () = $this-> Register () = $this-> Register () = $this-> Register (

class EventServiceProvider extends ServiceProvider
{
       public function register()
    {
        $this->app->singleton('events'.function ($app) {
            return (new Dispatcher($app)) - >setQueueResolver(function () use ($app) {
                return $app->make(QueueFactoryContract::class); }); }); }}Copy the code

2. Register user-defined events

This section covers the Provider startup process, which we covered in Chapter 8, and we’ll jump right to how to start EventServiceProvider.

App. Providers configures the service provider to load.

'providers'=> [ ... App\Providers\EventServiceProvider::class, ... ] .Copy the code

App \ will \ EventServiceProvider: : class boot here () method is framework load when the service provider’s call.

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
    ];

    public function boot() { parent::boot(); }}Copy the code

Start by starting the parent’s boot() method

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [];

    protected $subscribe = [];

    public function boot()
    {
        foreach ($this->listens() as $event= >$listeners) {
            foreach ($listeners as $listener) {
                Event::listen($event.$listener);
            }
        }

        foreach ($this->subscribe as $subscriber) {
            Event::subscribe($subscriber);
        }
    }
    
    public function register()
    {
        //
    }
    
    public function listens()
    {
        return $this->listen; }}Copy the code

The above code is the core of our registration, first through the $listen object

protected $listen = [
    Registered::class => [
        SendEmailVerificationNotification::class,
    ],
];
Copy the code

This code is the heart of the binding event

Event::listen($event.$listener);
Copy the code

So what does the Event facade return

class Event extends Facade
{
    ...
    
    protected static function getFacadeAccessor()
    {
        return 'events'; }}Copy the code

In fact, we’re back where we started, events is the closure that was originally bound

$this->app->singleton('events'.function ($app) {
        return (new Dispatcher($app)) - >setQueueResolver(function () use ($app) {
              return $app->make(QueueFactoryContract::class);
        });
    });
Copy the code

Events is the class Illuminate events Dispatcher! Let’s look at the Dispatcher’s Listen method

public function listen($events.$listener)
{
    foreach ((array) $events as $event) {
        if (Str::contains($event.The '*')) {
            $this->setupWildcardListen($event.$listener);
        } else {
            $this->listeners[$event=] []$this->makeListener($listener); }}}Copy the code

So if it’s a global event it goes to $this->wildcards otherwise it goes to $this-> Listeners.

Continue to look at $this – > makeListener ($listener);

public function makeListener($listener.$wildcard = false)
{
    if (is_string($listener)) {
        return $this->createClassListener($listener.$wildcard);
    }

    return function ($event.$payload) use ($listener.$wildcard) {
        if ($wildcard) {
            return $listener($event.$payload);
        }

        return $listener(... array_values($payload));
    };
}
Copy the code

$notice [$event] is the result of the closure. At this point we have resolved how the framework registers events that are already written.

3. Subscriber registration

In addition to the one-to-one binding, events implement a one-to-many binding that is the subscriber

public function boot() {... foreach ($this->subscribe as $subscriber) {
        Event::subscribe($subscriber); }}Copy the code

Go back to the boot() method, execute the normal Event registration, and then start registering subscribe to the Dispatcher object.

public function subscribe($subscriber{/ /Parse the incoming abstraction from the container and return the corresponding instance.
    $subscriber = $this->resolveSubscriber($subscriber);

    // "The call returns an instance subscribe($this) method at the same time$dispatcherObject"
    $subscriber->subscribe($this); 
}
Copy the code

So what happens in subscribe($this)?

Here I have listed a demo, written according to the official.

public function subscribe($events)
{
  $events->listen(
        'App\Events\MyEvents'.'App\Listeners\MySubscribe@funName()'
  );
}
Copy the code

Finally, the Listen method is called, but this allows a subscriber to listen for multiple events and optionally trigger the corresponding method based on the event.

fire events !

$dispatcher = $dispatcher = $dispatcher = $dispatcher

The core method of the event invocation.

public function dispatch($event.$payload= [].$halt = false) {[$event.$payload] = $this->parseEventAndPayload(
        $event.$payload
    );

    if ($this->shouldBroadcast($payload)) {
        $this->broadcastEvent($payload[0]);
    }

    $responses = [];

    foreach ($this->getListeners($event) as $listener) {
        $response = $listener($event.$payload);

        if ($halt&&! is_null($response)) {
            return $response;
        }
        
        if ($response= = =false) {
            break;
        }

        $responses[] = $response;
    }

    return $halt ? null : $responses;
}
Copy the code

Let’s look at the system’s default event return value

[$event.$payload] = $this->parseEventAndPayload(
            $event.$payload
        );
Copy the code

This code is the event broadcast trigger

if ($this->shouldBroadcast($payload)) {
        $this->broadcastEvent($payload[0]);
}
Copy the code

Starts traversing the listener class that is resolved from the given event

foreach ($this->getListeners($event) as $listener) {... }Copy the code

$listeners ->getListeners($notice); methods

public function getListeners($eventName)
{
    $listeners = $this->listeners[$eventName]???? [];$listeners = array_merge(
        $listeners.$this->wildcardsCache[$eventName]????$this->getWildcardListeners($eventName));return class_exists($eventName.false)?$this->addInterfaceListeners($eventName.$listeners)
                : $listeners;
}
Copy the code

The main logic here is to see if there are bindings in the $this->listeners

Return the corresponding class if it exists, otherwise return the corresponding implementation interface.

$response = $listener($event, $payload);

The $listener here is the closure returned by calling makeListerer() at the time of the above binding.

public function makeListener($listener.$wildcard = false)
{
    if (is_string($listener)) {
        return $this->createClassListener($listener.$wildcard);
    }

    return function ($event.$payload) use ($listener.$wildcard) {
        if ($wildcard) {
            return $listener($event.$payload);
        }

        return $listener(... array_values($payload));
    };
}
Copy the code

The argument passed here, $event, is the object of the event class we wrote

$payload is the parameter you want to pass in to carry.

The closure logic will be explained later.

conclusion

Events provides the benefit of decoupling development, and the framework is used in many places

For example, the observer of the model is based on the event system.