Tutorial: Events and Listeners¶
Introduction¶
phpBB 3.1 introduced a system of events throughout the codebase and template files that allow extensions to use listeners to add features, inject code, and modify existing functionality and behaviour.
This tutorial explains how to use events and listeners:
Template Events & Listeners¶
Template events allow extensions to inject code into the template files. Events can be found throughout the template structure of phpBB’s styles, providing multiple useful injection points. A typical template event looks like:
{% EVENT event_name_and_position %}
See also
View the full list of Template events.
Listening for an event¶
To subscribe to a template event, we must create a listener, a template file
with exactly the same name as the identifier of the template event we want to
use, and place it in the event/
subdirectory of a style’s template folder.
For example, we will use the overall_header_navigation_prepend
event to add a
new link before the existing links in the board’s navigation bar. The listener
for this event will be:
acme/demo/styles/prosilver/template/event/overall_header_navigation_prepend.html
Tip
If you want a template listener to be used by all styles, it should be placed
in the all/
style directory, e.g. vendor/extname/styles/all/template/event/
.
This helps prevent code duplication and eases style file management.
The prosilver and subsilver2 directories should be used for template files that must be custom tailored to each style. Similarly, if a 3rd-party style requires additional customisation to maintain compatibility, a folder for that style should be included with those template files.
To add ACP template listeners, place those files in vendor/extname/adm/style/event/
.
Inside the template listener, we will create a nav-bar link. This consists of a simple list element, with a link and a description:
<li class="small-icon icon-faq no-bulletin">
<a href="{{ U_DEMO_PAGE }}">
{{ lang('DEMO_PAGE') }}
</a>
</li>
Once the template listener has been created, you should be able to see the new link
in the board’s nav-bar, with the icon of the FAQ link and the
text DEMO_PAGE
. We will fix the link text in the next section.
Tip
If the link does not appear, you may need to purge the board cache from
the main page of the ACP. You can also enable DEBUG_MODE
in your
config.php
file, which will force the template engine to always
look for template listeners when a page is being rendered.
It’s important to understand that when phpBB compiles the templates, there is no current system for determining the priority in which template listeners from different extensions subscribed to the same event are compiled. In rare cases some extensions could cause a conflict, in which case the recommendation is for the extension authors to work together on a solution for their conflicting template listeners.
PHP Core Events & Listeners¶
Events allow extensions to execute code in many locations within core phpBB code, without modifying any of the code. That way extensions can easily add features, remove functionality or modify behaviour, while maintaining compatibility and simple update procedures.
Terminology¶
- Events
Events are dispatched at various places in the core phpBB code. Listeners in extensions subscribe to these events. They are able to execute code whenever the respective event has occurred. An alternative name for events is “hook locations”.
- Listeners
Listeners are triggered by events. They are methods that can process incoming data and manipulate variables in the scope of the event. So they can change phpBB’s behaviour, add new functionality or if used in the context of templates, modify the output. Numerous listeners form part of a subscriber. An alternative name for listeners is “hooks”.
See also
View the full list of supported PHP events.
The event listener¶
In the previous section we created a template listener that adds a link for the Acme
Demo extension to phpBB’s nav-bar. We will now use PHP events to load a language
file that contains the DEMO_PAGE
language key so that our nav-bar link will
display with the correct text.
To do so, we need to create a PHP event listener class (a.k.a. subscriber class).
This class includes a set of listener methods, each of which can subscribe
to PHP events in phpBB’s codebase. The listener class must be created in the
event/
subdirectory of the extension directory or it will not work. It must also
conform to the following requirements:
Follow extension class name-spacing conventions:
vendor\extname\event\subscribername.php
.Implement Symfony’s
Symfony\Component\EventDispatcher\EventSubscriberInterface
interface.Use the static method
getSubscribedEvents()
to subscribe methods in the listener to specific events, the keys of which contain event names and the values of which contain listener function names.
In the Acme Demo extension, we want to load our language file everywhere. Therefore
we will subscribe a listener function to phpBB’s core.user_setup
event:
<?php
namespace acme\demo\event;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class main_listener implements EventSubscriberInterface
{
/**
* Assign functions defined in this class to event listeners in the core
*
* @return array
*/
static public function getSubscribedEvents()
{
return [
'core.user_setup' => 'load_language_on_setup',
];
}
/**
* Load the Acme Demo language file
* acme/demo/language/en/demo.php
*
* @param \phpbb\event\data $event The event object
*/
public function load_language_on_setup($event)
{
$lang_set_ext = $event['lang_set_ext'];
$lang_set_ext[] = [
'ext_name' => 'acme/demo',
'lang_set' => 'demo',
];
$event['lang_set_ext'] = $lang_set_ext;
}
}
So what is the main_listener.php
class above actually doing?
The getSubscribedEvents()
method is subscribing our listener function
load_language_on_setup()
to the event named core.user_setup
. This means
that when this event occurs, our function will execute.
Tip
You can assign multiple listener functions to a single event using an array:
'core.user_setup' => [['foo_method'], ['bar_method']]
The load_language_on_setup()
listener method simply adds
our language file to phpBB’s language data array. Generally speaking, a listener
is simply a public function in the subscriber class, referred to in the array
returned by getSubscribedEvents()
. It takes one argument, $event
. This
parameter allows you to access and modify the variables that are given to the
event from the core code. In this case we are modifying the lang_set_ext
variable by adding Acme Demo’s language file to it.
Note
Note how the lang_set_ext
event variable is first copied by assigning
it to a local variable, then modified, and then copied back. This shortcut
does not work: $event['foo']['bar'] = $baz;
This is because the event
variables are overloaded, which is a limitation in PHP.
Registering the listener¶
To have phpBB autoload and execute our event listener class, we need to create a
service definition for it. This is done by creating a config/services.yml
file in the extension:
services:
acme.demo.listener:
class: acme\demo\event\main_listener
tags:
- { name: event.listener }
Warning
YAML files are indentation sensitive. They require an indentation size of 4 spaces per indent, do not use tabs.
The first line tells phpBB that a list of services is being registered. On the next line we specify the name of the service, which is for our event listener in this case.
Important
Service names must be prefixed with your vendor and extension name.
The class
attribute must contain the name-space and class name of the
service being registered. The name-space depends on the file’s location,
within the ext/
directory. Thus, the file ext/acme/demo/event/main_listener.php
has the namespace acme\demo\event
and class name main_listener
.
The full name of the class is therefore acme\demo\event\main_listener
which is what we need to specify here.
The tags
attribute tells phpBB that the service is an event listener.
Once the services YAML file has been created (or modified), phpBB’s cache
needs to be purged. After purging the cache in the ACP, the description of
the link in the navigation bar should now display Demo
instead of
DEMO_PAGE
.
Note
phpBB’s core PHP and template files have been prepared with dozens of event locations. However, if there are no events where your extension may need one, the phpBB development team welcomes event requests at the area51.com Event Requests forum.
Prioritising event listeners (optional)¶
Sometimes different extensions can run into problems when competing for use of the same PHP core events. In trying to resolve these issues, the extension developer may want to prioritise their extension over others, so that their extension will be triggered before other extensions.
In such cases, the getSubscribedEvents()
method provides an argument for
setting a priority for event listener methods. For example:
static public function getSubscribedEvents()
{
return [
'core.user_setup' => ['foo_method', $priority]
];
}
In this example, $priority
is an integer, the value of which defaults to 0.
Setting this integer to higher values equals more importance and therefore that
listener will be triggered earlier than others subscribed to this event.
We have now used events and listeners to modify phpBB and insert a nice link into the nav-bar. However, the link still does not work yet. Continue on to the next section to learn how to use controllers and routing to make our nav-bar link open up a custom user facing page.