Since version 3.6.0 BEdita is shipped with a basic event system, along with a callback manager that enables the binding of model events simply plugging callback behaviors, without the need to edit the model configuration itself, hence leaving core code intact.
Automatic callback behaviors
By giving a special name to your behaviors, you can attach listeners to some built-in CakePHP's model events without editing the core code. Such callback system is handled by the CallbackBehavior
which is automatically attached to every BEObject
in "callback manager" mode.
CallbackBehavior
configuration
CallbackBehavior
has an optional setting callbackManager
that allows you to decide if you want to attach your behaviors' methods as listeners for events handled by BeCallbackManager
(see below for detailed documentation) or you prefer to use standard CakePHP behaviors system. By default, BeCallbackManager
will be used.
Adding custom callbacks
Let's say you need to execute a custom piece of code every time an Event
is saved. Normally, you would create a behavior and then add the newly-born behavior to the Event::$actsAs
attribute, but this would involve the editing of a piece of source code.
Thanks to CallbackBehavior
you can attach your behavior automatically to the Event
model by naming it EventDoSomethingCallbackBehavior
(where DoSomething
can be replaced by anything you wish), and then enable it as an add-on, or place it within an enabled module.
This way, CallbackBehavior
will take care of attaching your custom behaviors following such naming convention to the respective models, and the event listeners they implement will be correctly triggered.
Unbinding custom callbacks
If you chose to attach CallbackBehavior
with callbackManager
set to true
, you might also decide to unbind single listeners. For example, if you had a custom callback behavior like this:
class EventTestingCallbackBehavior extends ModelBehavior { public function afterSave() { $this->log('afterSave', 'callback'); } public function afterDelete() { $this->log('afterDelete', 'callback'); } }
If later on you wanted to get rid of its afterDelete()
callback while doing a specific operation, you might call:
BeLib::getObject('BeCallbackManager')->unbind('Event.AfterDelete', array( 'EventTestingCallbackBehavior', 'afterDelete' ));
This way, the EventTestingCallbackBehavior::afterDelete()
method would be detached from the Event.AfterDelete
event. Please, read BeCallbackManager::unbind()
documentation for further details.
Adding callbacks on-the-fly
If you chose to attach CallbackBehavior
with callbackManager
set to true
, you might also decide to add custom listeners on the fly to model events. For example, if you attached CallbackBehavior
to the Event
model, you would have the chance to listen to those events: Event.Beforefind
, Event.AfterFind
, Event.BeforeValidate
, Event.BeforeSave
, Event.AfterSave
, Event.BeforeDelete
, Event.AfterDelete
.
Thus, this would work:
BeLib::getObject('BeCallbackManager')->bind('Event.BeforeValidate', function ($model) { /* Do some custom validation rules. */ return true; });
Please, refer to the documentation for BeCallbackManager::bind()
for further details.
BeCallbackManager
class reference
BEdita implements a basic event system. You can attach custom functions as listeners for built-in events, and you can even trigger your custom events.
function bind(string $eventName, mixed $listener)
Bind a listener to an event.
Params
$eventName
: name of the event to be listened.-
$listener
: callable to be invoked when the event is triggered.This can be either an anonymous function (PHP ≥ 5.3.0) or a fully qualified name of a callable method, like a string (e.g.:
'my_function'
) or an array containing a class name and one of its methods (e.g.:array('MyClass', 'myPublicMethod')
). Please note that CakePHP'sClassRegistry
will be used in this case to obtain an instance of the given class.
Examples
Bind a closure to an event:
$eventManager = BeLib::getObject('BeCallbackManager'); $eventManager->bind('MyModel.AfterSave', function ($model, $created, $event) { CakeLog::write('callback', 'Saved object of type "MyModel"'); });
Bind a model method to a custom event:
$eventManager = BeLib::getObject('BeCallbackManager'); $eventManager->bind('Cart.AfterPurchase', array('PurchaseHistory', 'purchaseCompleted'));
function unbind(string $eventName = null, mixed $listener = null)
Unbinds a listener from an event. If called without any argument, all events listeners are cleared.
Params
$eventName
: name of the event. If omitted or null, the given$listener
will be removed from all events.$listener
: callable to be unbinded. If omitted or null, the given$eventName
will be completely cleared.
Examples
Unbind a closure from an event:
$eventManager = BeLib::getObject('BeCallbackManager'); $listener = function ($model, $query, $event) { /* Do something... */ }; $eventManager->bind('MyModel.BeforeFind', $listener); // ... $eventManager->unbind('MyModel.BeforeFind', $listener);
Clear all listeners for an event:
$eventManager = BeLib::getObject('BeCallbackManager'); $eventManager->bind('MyModel.MyEvent', function () { /* ... */ }); $eventManager->bind('MyModel.MyEvent', function () { /* ... */ }); // ... $eventManager->unbind('MyModel.MyEvent');
function trigger(string $eventName, array $eventData = array())
Trigger an event (possibly any event) passing custom data.
For model-related events (or class-related events in general), $eventName
is usually the class name the event refers to, followed by a dot, followed by a self-explanatory event name (both model name and event name are camel cased). You are encouraged to follow this convention.
Params
$eventName
: name of the event to be triggered.$eventData
: array of data to be passed as arguments to listeners. The event will be always passed as last argument.
Return values
The triggered event is returned.
Examples
Trigger a custom event:
$eventManager = BeLib::getObject('BeCallbackManager'); $eventManager->bind('MyEvent', function ($a, $b, $event) { CakeLog::write('callback', $event->name . '_' . ($a + $b)); return 42; }); $evt = $eventManager->trigger('MyEvent', array(2, 3)); // Will result in logging 'MyEvent_5' to 'callback.log'. echo($evt->result); // Outputs: '42'.