Skip to content

Commit 51a7918

Browse files
authored
docs: add some docs for the new PSR hook interface (simplesamlphp#2567)
* docs: add some docs for the new PSR hook interface * some of the crappier lint * indent * lint * . * lint2 * lint again * gotta watch out for those double blanks!! * transpose I can understand
1 parent f1d494e commit 51a7918

1 file changed

Lines changed: 122 additions & 1 deletion

File tree

docs/simplesamlphp-modules.md

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,128 @@ replaces `modules/core/templates/default/loginuserpass.php`.
185185
`templates/default/frontpage.php`. This theme can be activated by
186186
setting `theme.use` to `example:test`.
187187

188-
## Hook interface
188+
## Event listeners (new Hooks)
189+
190+
In SimpleSAMLphp 2.5 the hook interface was updated to use PSR-14
191+
events [PSR-14 events](https://www.php-fig.org/psr/psr-14) as well as
192+
the legacy custom "hook" interface. When hooks are called in 2.5 both
193+
the new PSR-14 event listeners are called followed by the older custom
194+
hook. You are likely better to create new event listeners in new
195+
configurations and might like to consider moving your hooks to event
196+
listeners over time.
197+
198+
If you are using an older version of SimpleSAMLphp please see the
199+
below section for information on how to use the older interface.
200+
201+
This section discusses how to make new event listeners with an
202+
eye toward moving an existing hook to become an event listener.
203+
204+
The PSR events that can be used are defined in your module's
205+
src/Event subdirectory. For example, for the admin module you can
206+
see modules/admin/src/Event/ConfigPageEvent.php which defines
207+
a class ConfigPageEvent in the `SimpleSAML\Module\admin\Event` namespace.
208+
209+
That event takes some state in the constructor and likely has one or
210+
more access methods to later retrieve that state.
211+
212+
The event might be listened to by the same or another module by
213+
defining a `Listener` class. In the running concrete example the class
214+
in modules/cron/src/Event/Listener/ConfigPageListener.php defines a
215+
`ConfigPageListener` class in the
216+
`SimpleSAML\Module\cron\Event\Listener` namespace. That listener class
217+
has an `__invoke` method that will be passed the `ConfigPageEvent`
218+
object and has no return value.
219+
220+
The `ConfigPageEvent` is a reasonable starting point for testing your
221+
own listener. If you create a new listener for ConfigPageEvent you can
222+
use `Logger::error` to check that you get called and use the
223+
admin/config page through the admin module to trigger this event
224+
fairly easily. You might like to base your new listener on the
225+
ConfigPageListener for the cron module.
226+
227+
To update a hook from a 2.4 release or below you will need to move
228+
your hook class from the `hooks` directory to the `src/Event/Listener`
229+
subdirectory. Considering the config page example again, the
230+
`hooks/hook_configpage.php` file should move to `src/Event/Listener`.
231+
That hook defined a single top level function with a specific function
232+
name `cron_hook_configpage`. In the event listener the new
233+
`src/Event/Listener/ConfigPageListener.php` file will need to be in
234+
the `SimpleSAML\Module\cron\Event\Listener` namespace and define a
235+
class `ConfigPageListener`. The single top level function is moved
236+
into a member function `__invoke` taking a single parameter
237+
`ConfigPageEvent`.
238+
239+
The old hook function took a reference `Template &$template` directly
240+
as the single argument. The new PSR class takes a `ConfigPageEvent`
241+
object. The ConfigPageEvent object provides access to the template
242+
using the `getTemplate` method on the event.
243+
244+
The old hook function in `hooks` might look like the following.
245+
246+
// old hook interface
247+
function cron_hook_configpage(Template &$template): void
248+
{
249+
$template->data['links'][] = [
250+
'href' => Module::getModuleURL('cron/info'),
251+
'text' => Translate::noop('Cron module information page'),
252+
];
253+
...
254+
}
255+
256+
The new Listener version in `src/Event/Listener` is shown below.
257+
258+
class ConfigPageListener
259+
{
260+
public function __invoke(ConfigPageEvent $event): void
261+
{
262+
$template = $event->getTemplate();
263+
264+
$template->data['links'][] = [
265+
'href' => \SimpleSAML\Module::getModuleURL('cron/info'),
266+
'text' => \SimpleSAML\Locale\Translate::noop('Cron module information page'),
267+
];
268+
...
269+
}
270+
}
271+
272+
That `ConfigPageEvent` class is defined in
273+
`modules/admin/src/Event/ConfigPageEvent.php`.
274+
275+
class ConfigPageEvent
276+
{
277+
public function __construct(
278+
private readonly XHTML\Template $template,
279+
)
280+
{}
281+
282+
public function getTemplate(): XHTML\Template
283+
{
284+
return $this->template;
285+
}
286+
}
287+
288+
In summary to move a hook to the new PSR-14 events you have to move
289+
the hook file to your module's src/Event/Listener directory and have
290+
it take a new Event object that passes the function argument to it.
291+
The event will be a simple class defined in your `src/Event`
292+
directory.
293+
294+
When you wish to call event listeners in your code you can use code
295+
like the following. The event dispatcher is passed an event which
296+
contains all of the state you wish to make available to the event
297+
listeners. You can then get the state which may have been updated by
298+
one or more listeners using a getter method and do something with the
299+
result.
300+
301+
$eventDispatcher = ModuleEventDispatcherFactory::getInstance();
302+
$event = $eventDispatcher->dispatch(new ConfigPageEvent($t));
303+
$t = $event->getTemplate();
304+
305+
## Hook interface (SimpleSAMLphp 2.4 and below)
306+
307+
Releases 2.4 and below use a custom hook interface to allow code to
308+
run when specific things of interest are happening. If you are using
309+
SimpleSAMLphp 2.5 or above please see the above section on Event listeners instead.
189310

190311
The hook interface allows you to call a hook function in all enabled
191312
modules which define that hook. Hook functions are stored in a

0 commit comments

Comments
 (0)