Event Listener (Observer) Pattern

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

See: Observer pattern on Wikipedia

The Flow

First, there will be many listeners(observers), we can attach them to a dispatcher object.


Now, all listeners listened this dispatcher, if some event triggered, this dispatcher will notify all listeners.


So, if any listener has the method which matched the event, dispatcher will call this method.

Start Using Event

Create an event object named onBeforeContentSave, and set some arguments.

use Windwalker\Event\Event;

$event = new Event('onBeforeContentSave');

$content = new stdClass;

$event->setArgument('title', 'My content');
$event->setArgument('content', $content);

Create your listener:

use Windwalker\Event\EventInterface;

class ContentListener
    public function onBeforeContentSave(EventInterface $event)
        $event->getArgument('content')->title = $event->getArgument('title');

     public function onAfterContentSave(EventInterface $event)
        // Do something

Add listener to Dispatcher:

$dispatcher = \Windwalker\Ioc::getDispatcher();

// OR

$dispatcher = $container->get('dispatcher');

// Attach listener
$dispatcher->addListener(new ContentListener);

Then we trigger the event we created:

// Trigger the onBeforeContentSave

// ContentListener::onBeforeContentSave will set title into $content object.
$content->title == 'My content';

If a method name in listener equals to event name, Dispatcher will run this method and inject Event into this method. Then we can do many things we want.

Array Access

Event can access like array:

// Set
$event['data'] = $data;

// Get
$data = $event['data'];


There can be two types of listeners, using class or closure.

Class Listeners

Using class, just new an instance

$dispatcher->addListener(new ContentListener);

You may provides priority for every methods.

use Windwalker\Event\ListenerPriority;

// Add priorities
    new ContentListener,
        'onBeforeContentSave' => ListenerPriority::LOW,
        'onAfterContentSave' => ListenerPriority::HIGH

// Or using an inner method to get all methods
$dispatcher->addListener(new ContentListener, ContentListener::getPriorities());

Closure Listeners

If using closure, you must provide the priority and an event name to listen.

    function (EventInterface $event)
        // Do something
    array('onContentSave' => ListenerPriority::NORMAL)

Or use listen() method.

$dispatcher->listen('onContentSave', function (EventInterface $event)
    // Do something
}, ListenerPriority::NORMAL);


Trigger An Event Object

This is the most normal way to trigger an event.

$event = new Event('onFlowerBloom');

$event->setArgument('flower', 'sakura');


Add arguments when triggering event, the arguments will merge with previous arguments you set.

$args = array(
    'foo' => 'bar'

$dispatcher->triggerEvent($event, $args);

Add An Event Then Trigger It Later

We can add an event into Dispatcher, then use event name to raise it laster.

$event = new Event('onFlowerBloom');

$event->setArgument('flower', 'sakura');


// Nothing happen


Trigger A New Event Instantly

We don't need create event first, just trigger a string as event name, Dispatcher will create an event instantly.

$args = array(
    'foo' => 'bar'

$dispatcher->triggerEvent('onCloudMoving', $args);

Stopping Event

If you stop an event, the next listeners in the queue won't be called.

class ContentListener
    public function onBeforeContentSave(EventInterface $event)
        // Stopping the Event propagation.

DispatcherAwareInterface and Trait

In PHP 5.4 or higher, you can use DispatcherAwareTrait.

use Windwalker\Event\DispatcherAwareInterface;
use Windwalker\Event\DispatcherAwareTrait;

class Application implements DispatcherAwareInterface
    use DispatcherAwareTrait;

    // ...

Default Events


  • onAfterInitialise
  • onAfterBoot
  • onBeforeExecute
  • onBeforeRouting
  • onRouterBeforeRouteMatch
  • onRouterAfterRouteMatch
  • onAfterRouteMatched
  • onAfterRouting
  • onPackageBeforeExecute
  • onPackageAfterExecute
  • onAfterExecute
  • onBeforeRespond
  • onAfterRespond
  • onBeforeRedirect


  • onControllerBeforeExecute
  • onControllerAfterExecute


  • onViewAfterHandleData
  • onViewBeforeRender
  • onViewAfterRender


  • onRendererPrepareGlobals


  • onAssetRenderStyles
  • onAssetRenderScripts


  • onLoadAuthenticationMethods
  • onLoadAuthorisationPolicies
  • onUserBeforeLogin
  • onUserAuthorisation
  • onUserAfterLogin
  • onUserLoginFailure
  • onUserBeforeLogout
  • onUserAfterLogout
  • onUserLogoutFailure
  • onUserBeforeSave
  • onUserSaveFailure
  • onUserAfterSave
  • onUserBeforeDelete
  • onUserDeleteFailure
  • onUseAfterDelete


  • onMailerAfterCreateMessage
  • onMailerBeforeSend

If you found a typo or error, please help us improve this document.