@@ -185,7 +185,128 @@ replaces `modules/core/templates/default/loginuserpass.php`.
185185` templates/default/frontpage.php ` . This theme can be activated by
186186setting ` 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
190311The hook interface allows you to call a hook function in all enabled
191312modules which define that hook. Hook functions are stored in a
0 commit comments