- ^ Jelix components
- jTpl, template engine
- Zones
- jDao: relational object mapping
- Classic forms
- jForms: automatic forms
- jDb: accessing to SQL database
- jKVDb: accessing to key/value databases
- jUrl: automatic urls
- jAuth : authentication system
- jAcl2 : rights management
- jLocale: localization
- jEvents: communication between modules
Chapter: jEvents: communication between modules
« jLocale: localization | ^ Jelix components |
− Table of content
Jelix implements a simple inter-module communication system. It is based on events, and is called jEvent.
Anywhere in the code, it's possible to emit an event, to let the modules respond to, and to use the response.
The jEvent
component is follow a broadcast scheme. Some code
emits a request (an event). Some listeners are awaiting for this event,
and when it is emitted, they process it, and return something (a response).
So basically we have, on the one hand, the jEvent
class that emits events
and that gathers and return the responses, and on the other hand, some
Listener classes, located in modules, that respond to events.
Emitting an event ¶
To emit an event, we use jEvent's static method notify()
.
jEvent::notify
accepts two arguments. The first one is the name of the
event you want to send (alphanumeric characters only), and the second one (optional)
is an array of event parameters.
jEvent::notify
returns a jEvent
instance, containing all the related
responses. Responses are some data returned by the listeners (don't confuse with
the jResponse
objects returned by controllers). The structure and value of
responses depend solely on each event, the number of modules that responded and
how the data is structured in the listeners.
For example:
//first way, with parameters
$eventParams = array('user' => $userObject);
$theEvent = jEvent::notify('authCanLogin', $authCLEventParams);
//second way, without parameters
$theEvent = jEvent::notify('authCanLogin2');
To get access to the responses returned by the modules, use the
getResponse
method of the jEvent object that was returned after the
emission.
$reponses = $theEvent->getResponse();
The result is an array containing all data returned by listeners.
You have other methods to query data from responses:
inResponse($responseKey, $value)
: says if a key with the given value exists in returned data.getResponseByKey($responseKey)
: return list of data corresponding to the given keyallResponsesByKeyAreTrue($responseKey)
: says if all data of the given key aretrue
.allResponsesByKeyAreFalse($responseKey)
: says if all data of the given key arefalse
.
Responding to an event ¶
Since there is no default listener in the modules, each module that wants to
respond to events need to create a listener and declare it in the
events.xml
file of the same module. There is no limit in the number of
listeners.
The creation of the listener has two steps: the creation of the class and the declaration of the listener.
Creating a listener ¶
First, choose a name. We will use 'auth' as an example. Then create a listener
class. Note that the class name is a concatenation of the name and of
'Listener', so in our case, 'authListener'. Put that class in a file called
{name}.listener.php
, so auth.listener.php
for us, in the
classes
folder of your module. Remember, your listener class must inherit
from jEventListener
.
The listener needs to implement one method for each event it is supposed to
respond to. Those methods should follow this convention : on
following by
the event name. They need to accept as single argument a jEvent
object.
Example:
//file auth.listener.php
class authListener extends jEventListener {
function onAuthCanLogin ($event) {
//retrive user parameter
$user = $event->getParam('user');
//the actual processing
$ok = true;
if (isset($user->active)) {
$ok = ($user->active == '1');
}
$ok = $ok && ($user->password != '');
//the response
$event->add(array('canlogin'=>$ok));
}
}
This example demonstrates a listener responding to the AuthCanLogin
event.
First, the onAuthCanLogin
method retrieves an 'user' parameter from the
event object. Next, it does it's internal processing, and finally, it adds some
data to the response by calling $event->add
.
For events having a name that cannot be a method name, like name including
characters like a dot, you can indicate the method to execute into a property
eventMapping
. Keys are event names, values are method names.
class authListener extends jEventListener {
protected $eventMapping = array(
'foo.bar' => 'execFooBar'
);
function execFooBar ($event) {
// here process the event.
}
}
Note: the convention of the name of methods and the calling of methods
corresponding to events can be changed by redefining the method performEvent
of your listener.
Declaring a listener ¶
The final step to setup a listener is to declare it. This is done through the
events.xml
file located in your module root folder. For example:
<events xmlns="http://jelix.org/ns/events/1.0">
<!-- We have 2 listeners each listening for some events. However, both of them will respond to the AuthCanViewUser event. -->
<listener name="auth">
<event name="AuthCanLogin" />
<event name="AuthCanViewUser" />
</listener>
<listener name="auth2">
<event name="AuthCanLogin2" />
<event name="AuthCanViewUser" />
</listener>
</events>
A listener can listen to more than one event. Since it would take too much resources to load all the listeners one by one and check what events do they respond to, you also need to list all the events that you want a listener to listen to. Remember that two listener can also respond to the same event, and that there isn't a conventional structure for the responses.
Disabling listeners ¶
When we use a vendor module, for any reason, we could want to deactivate one of its listener about a specific events.
It is possible by indicating them into the [disabledListeners]
section in
the main configuration. Keys are event name, values are selector of listeners.
[disabledListeners]
authLogin="aModule~theListener"
In this example, the listener theListener
of the module "aModule" won't
be called when the event authLogin
will be emited.
If you deactivate several listeners for a same event, just use []
to
indicate an array:
[disabledListeners]
authLogin[]="aModule~theListener"
authLogin[]="otherModule~otherListener"