I find the 'normal' way pretty ugly.
- listing the args by name in an array, then
- supplying the args, then
- needing to pass by ref a NULL/dummy variable for each of the remaining 6 or was it 7? arguments - this is ugly and error prone and passing
CRM_Core_DAO::$_nullObject
is risky as it allows the hook to overwrite that so it's no longer NULL.
I think the following can be a nicer approach, here's an example:
Fire an event
// Create an event object with all the data you wan to pass in.
$event = Civi\Core\Event\GenericHookEvent::create(
['fname' => $fname, 'votes' => &$votes]);
Civi::dispatcher()->dispatch('civi.something.you.make.up', $event);
Example listener
function your_listener_callable($event) {
print "running " . __FUNCTION__ . "\n";
// We can overwrite data
$event->fname = 'Wilma Flintstone';
// We can alter anything passed by reference.
$event->votes++;
// To return a value you need to pass it in an array like so:
$event->addReturnValues(['Successfully recorded votes!']);
// We can't write any properties that the event did
// not originally have defined, so this won't work:
$event->friend = 'Barney';
}
Use data resulting from the event
This code would come directly after the 'Fire an event' code.
print "$fname ($event->fname) now has $votes votes.\n";
$return = $event->getReturnValues();
print "The hook returned: $return[0]\n";
// $event->friend === NULL
Link your listener to the event.
You'd normally do this in a hook_civicrm_container()
function to ensure it is only added once.
/**
* Implements hook_civicrm_container().
*
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_container/
*/
function myext_civicrm_container($container) {
// https://docs.civicrm.org/dev/en/latest/hooks/usage/symfony/
$container->findDefinition('dispatcher')
->addMethodCall('addListener', [
'civi.something.you.made.up',
'your_listener_callable']);
}
Full working command line example
You can run this with cv scr hookexample.php
<?php
use \Civi\Core\Event\GenericHookEvent;
if (php_sapi_name() !== 'cli') {
http_response_code(404);
exit;
}
function your_listener_callable($event) {
print "running " . __FUNCTION__ . "\n";
// We can overwrite data passed by value, but that's probably confusing.
$event->fname = 'Wilma Flintstone';
// We can alter anything passed by reference.
$event->votes++;
// To return a value you need to pass it in an array like so:
$event->addReturnValues(['Successfully recorded votes!']);
// We can't write any properties that the event did not originally
// have defined, so this won't work:
$event->friend = 'Barney';
}
// As this is a single-pass script we can just do this:
Civi::dispatcher()->addListener('civi.something.you.make.up', 'your_listener_callable');
$votes = 0;
$fname = 'Wilma';
print "$fname has $votes votes.\n";
$event = GenericHookEvent::create(['fname' => 'Wilma', 'votes' => &$votes]);
Civi::dispatcher()->dispatch('civi.something.you.make.up', $event);
$return = $event->getReturnValues();
print "$fname ($event->fname) now has $votes votes.\n";
print "The hook returned: $return[0]\n";
// $event->friend is NULL.
Outputs:
Wilma has 0 votes.
running your_listener_callable
Wilma (Wilma Flintstone) now has 1 votes.
The hook returned: Successfully recorded votes!