Skip to main content
added 26 characters in body
Source Link
artfulrobot
  • 4k
  • 16
  • 33
/**
 * 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/
  Civi::dispatcher$container->findDefinition('dispatcher')
  ->addMethodCall('addListener', [
    'civi.something.you.made.up',
    'your_listener_callable']);
}
/**
 * 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/
  Civi::dispatcher()->addMethodCall('addListener', [
    'civi.something.you.made.up',
    'your_listener_callable']);
}
/**
 * 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']);
}
Source Link
artfulrobot
  • 4k
  • 16
  • 33

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/
  Civi::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!