The Croogo CMS is based on CakePHP and use Cake's awesome Events System. The idea and concept of loosely coupled objects is the key for good quality code and scalability during the life cycle of a project. My customers ask me often what happen when their needs on a Portal, Application or CMS grow. Do we build a new Website again, and again every 2-4 Years? - My answer is "No". With Croogo CMS we have the Event Management and can connect new Plugins and Business logic trough the implemented Events, this is called event driven programming.

We don't want to hard code dependencies in the Controller, Component or lazy load the other Class in our working Model. The solution must be a clean communication between other parts of the application like custom Business logic functions or Plugins.

The only hard coded parts are the defined Listeners all over the place in the Controller actions or View forms. It's very simple and straightforward, the event object holds information about the event, and provides the ability to stop event propagation at any point. The way how Croogo build in dispatcher function works is very simple. Here the dispatchEvent() public static function.

<?php
/**
 * Convenience method to dispatch event.
 *
 * Creates, dispatches, and returns a new CakeEvent object.
 *
 * @see CakeEvent::__construct()
 * @param string $name Name of the event
 * @param object $subject the object that this event applies to
 * @param mixed $data any value you wish to be transported with this event
 */
public static function dispatchEvent($name, $subject = null, $data = null)
{
    $event = new CakeEvent($name, $subject, $data);
    if ($subject) {
        $event = $subject->getEventManager()->dispatch($event);
    } else {
        $event = CakeEventManager::instance()->dispatch($event);
    }
    return $event;
}

This method create a new CakeEvent() object. The $name variable is the given 'Controller.Action' name. You can define it how you want, I use 'Controller.Orders.afterOrderCreate.' or 'Component.Users.beforeApiUserLogin.' depending on the location of the event. The $subject variable handle the $this instance given by the event action trigger. If the $subject is not given, the CakeEventManager dispatches a new event by the event key name or instance of CakeEvent. For more details on configuration read the CakeEventManager functions.

Now the $event is ready for some custom Plugin or Business logic. First of all the Event handlers must be definied over the /Config/events.php configuration file, we stay with our Store Orders example.

<?php
$config = [
    'EventHandlers' => [
        // Store Order
        'Store.OrderEventHandler' => [
			'options' => [
				'priority' => 10,
			],
		],
	],
];

In fact this move is very smart because you define your Events in the events.php config file, before you write the controller action methods you want to handle.

Now the last part come into the events game and that is the specific handler file located in the /Event/* folder. Each file in this paradigm is named like PluginModelEventHandler.php in our example StoreOrderEventHandler.php and this file look like that.

<?php
App::uses('CakeEventListener', 'Event');

class StoreOrderEventHandler extends Object implements CakeEventListener
{
    /**
     * 
     * @return type
     */
    public function implementedEvents()
    {
        return [
            // Order create
            'Controller.Orders.afterOrderCreate' => [
                'callable' => 'onAfterOrderCreate',
            ],
        ];
    }

    /**
     * 
     * @param type $event
     * @return boolean
     */
    public function onAfterOrderCreate($event)
    {   
        $Controller = $event->subject();
        
        // Your custom Business logic and further process

        return true;
    }
}

First we implement the Events we want to handle over the implementedEvents() function, at this point the callable function must exist, if not we get in serious bootstrapping errors. How you name and call the functions is up to you. I'm fine with 'on' as prefix.