From 6f1818fd2eb0911360a288657b1c65c6b2b6a3e0 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Thu, 13 Apr 2017 19:05:57 -0700 Subject: [PATCH] CiviEventInspector - Prefer "event" nomenclature instead of "hook" Events are a superset of hooks. --- Civi/Core/CiviEventInspector.php | 101 +++++++++++------- Civi/Core/Container.php | 2 +- .../Civi/Core/CiviEventInspectorTest.php | 35 ++++-- 3 files changed, 85 insertions(+), 53 deletions(-) diff --git a/Civi/Core/CiviEventInspector.php b/Civi/Core/CiviEventInspector.php index bee94cae77..f4dc1c6e2a 100644 --- a/Civi/Core/CiviEventInspector.php +++ b/Civi/Core/CiviEventInspector.php @@ -4,12 +4,12 @@ namespace Civi\Core; /** * Class CiviEventInspector * - * The hook inspector is a development tool which provides metadata about hooks. + * The event inspector is a development tool which provides metadata about events. * It can be used for code-generators and documentation-generators. * * @code * $i = new CiviEventInspector(); - * print_r(CRM_Utils_Array::collect('name', $i->getHooks())); + * print_r(CRM_Utils_Array::collect('name', $i->getAll())); * @endCode * * Note: The inspector is only designed for use in developer workflows, such @@ -24,99 +24,118 @@ class CiviEventInspector { * @param \Civi\Core\Event\GenericHookEvent $e * @see \CRM_Utils_Hook::hooks() */ - public static function findBuiltInHooks(\Civi\Core\Event\GenericHookEvent $e) { + public static function findBuiltInEvents(\Civi\Core\Event\GenericHookEvent $e) { $skipList = array('singleton'); $e->inspector->addStaticStubs('CRM_Utils_Hook', 'hook_civicrm_', - function ($hook, $method) use ($skipList) { - return in_array($method->name, $skipList) ? NULL : $hook; + function ($eventDef, $method) use ($skipList) { + return in_array($method->name, $skipList) ? NULL : $eventDef; }); } /** * @var array - * Array(string $name => array $hookDef). + * Array(string $name => array $eventDef). * - * Ex: $hooks['hook_civicrm_foo']['description_html'] = 'Hello world'; + * Ex: $eventDefs['hook_civicrm_foo']['description_html'] = 'Hello world'; */ - protected $hooks; + protected $eventDefs; /** - * Perform a scan to identify/describe all hooks. + * Perform a scan to identify/describe all events. * * @param bool $force * @return CiviEventInspector */ public function build($force = FALSE) { - if ($force || $this->hooks === NULL) { - $this->hooks = array(); + if ($force || $this->eventDefs === NULL) { + $this->eventDefs = array(); \CRM_Utils_Hook::hooks($this); - ksort($this->hooks); + ksort($this->eventDefs); } return $this; } /** - * Get a list of all hooks. + * Get a list of all events. * * @return array - * Array(string $name => array $hookDef). - * Ex: $hooks['hook_civicrm_foo']['description_html'] = 'Hello world'; + * Array(string $name => array $eventDef). + * Ex: $result['hook_civicrm_foo']['description_html'] = 'Hello world'; */ public function getAll() { $this->build(); - return $this->hooks; + return $this->eventDefs; } /** - * Get the definition of one hook. + * Find any events that match a pattern. + * + * @param string $regex + * @return array + * Array(string $name => array $eventDef). + * Ex: $result['hook_civicrm_foo']['description_html'] = 'Hello world'; + */ + public function find($regex) { + $this->build(); + return array_filter($this->eventDefs, function($e) use ($regex) { + return preg_match($regex, $e['name']); + }); + } + + /** + * Get the definition of one event. * * @param string $name * Ex: 'hook_civicrm_alterSettingsMetaData'. * @return array - * Ex: $hook['description_html'] = 'Hello world'; + * Ex: $result['description_html'] = 'Hello world'; */ public function get($name) { $this->build(); - return $this->hooks[$name]; + return $this->eventDefs[$name]; } /** - * @param $hook + * @param $eventDef * @return bool * TRUE if valid. */ - public function validate($hook) { + public function validate($eventDef) { return - is_array($hook) - && !empty($hook['name']) - && isset($hook['signature']) - && is_array($hook['fields']); + is_array($eventDef) + && !empty($eventDef['name']) + && isset($eventDef['signature']) + && is_array($eventDef['fields']); } /** - * Add a new hook definition. + * Add a new event definition. * - * @param array $hook + * @param array $eventDef * @return CiviEventInspector */ - public function add($hook) { - $name = isset($hook['name']) ? $hook['name'] : NULL; + public function add($eventDef) { + $name = isset($eventDef['name']) ? $eventDef['name'] : NULL; + + if (!isset($eventDef['is_hook'])) { + $eventDef['is_hook'] = (bool) preg_match('/^hook_/', $eventDef['name']); + } - if (empty($hook['signature'])) { - $hook['signature'] = implode(', ', array_map( + if (empty($eventDef['signature'])) { + $eventDef['signature'] = implode(', ', array_map( function ($field) { $sigil = $field['ref'] ? '&$' : '$'; return $sigil . $field['name']; }, - $hook['fields'] + $eventDef['fields'] )); } - if (TRUE !== $this->validate($hook)) { - throw new \CRM_Core_Exception("Failed to register hook ($name). Invalid definition."); + if (TRUE !== $this->validate($eventDef)) { + throw new \CRM_Core_Exception("Failed to register event ($name). Invalid definition."); } - $this->hooks[$name] = $hook; + $this->eventDefs[$name] = $eventDef; return $this; } @@ -133,7 +152,7 @@ class CiviEventInspector { * An optional function to filter/rewrite the metadata for each hook. * @return CiviEventInspector */ - public function addStaticStubs($className, $prefix = 'hook_', $filter = NULL) { + public function addStaticStubs($className, $prefix, $filter = NULL) { $class = new \ReflectionClass($className); foreach ($class->getMethods(\ReflectionMethod::IS_STATIC) as $method) { @@ -141,7 +160,7 @@ class CiviEventInspector { continue; } - $hook = array( + $eventDef = array( 'name' => $prefix . $method->name, 'description_html' => $method->getDocComment() ? \CRM_Admin_Page_APIExplorer::formatDocBlock($method->getDocComment()) : '', 'fields' => array(), @@ -149,7 +168,7 @@ class CiviEventInspector { ); foreach ($method->getParameters() as $parameter) { - $hook['fields'][$parameter->getName()] = array( + $eventDef['fields'][$parameter->getName()] = array( 'name' => $parameter->getName(), 'ref' => (bool) $parameter->isPassedByReference(), // WISHLIST: 'type' => 'mixed', @@ -157,13 +176,13 @@ class CiviEventInspector { } if ($filter !== NULL) { - $hook = $filter($hook, $method); - if ($hook === NULL) { + $eventDef = $filter($eventDef, $method); + if ($eventDef === NULL) { continue; } } - $this->add($hook); + $this->add($eventDef); } return $this; diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index ec31c5415e..1dcd8a8969 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -250,7 +250,7 @@ class Container { $dispatcher->addListener('hook_civicrm_post::Case', array('\Civi\CCase\Events', 'fireCaseChange')); $dispatcher->addListener('hook_civicrm_caseChange', array('\Civi\CCase\Events', 'delegateToXmlListeners')); $dispatcher->addListener('hook_civicrm_caseChange', array('\Civi\CCase\SequenceListener', 'onCaseChange_static')); - $dispatcher->addListener('hook_civicrm_hooks', array('\Civi\Core\CiviEventInspector', 'findBuiltInHooks')); + $dispatcher->addListener('hook_civicrm_hooks', array('\Civi\Core\CiviEventInspector', 'findBuiltInEvents')); $dispatcher->addListener('civi.dao.postInsert', array('\CRM_Core_BAO_RecurringEntity', 'triggerInsert')); $dispatcher->addListener('civi.dao.postUpdate', array('\CRM_Core_BAO_RecurringEntity', 'triggerUpdate')); $dispatcher->addListener('civi.dao.postDelete', array('\CRM_Core_BAO_RecurringEntity', 'triggerDelete')); diff --git a/tests/phpunit/Civi/Core/CiviEventInspectorTest.php b/tests/phpunit/Civi/Core/CiviEventInspectorTest.php index 0cdc90f8b6..36482f13f1 100644 --- a/tests/phpunit/Civi/Core/CiviEventInspectorTest.php +++ b/tests/phpunit/Civi/Core/CiviEventInspectorTest.php @@ -9,13 +9,14 @@ class CiviEventInspectorTest extends \CiviUnitTestCase { public function testGet() { $inspector = new CiviEventInspector(); - $hook = $inspector->get('hook_civicrm_alterSettingsMetaData'); - $this->assertEquals('hook_civicrm_alterSettingsMetaData', $hook['name']); - $this->assertEquals(array('settingsMetaData', 'domainID', 'profile'), array_keys($hook['fields'])); - $this->assertTrue($hook['fields']['settingsMetaData']['ref']); - $this->assertFalse($hook['fields']['domainID']['ref']); - $this->assertEquals('&$settingsMetaData, $domainID, $profile', $hook['signature']); - $this->assertTrue($inspector->validate($hook)); + $eventDef = $inspector->get('hook_civicrm_alterSettingsMetaData'); + $this->assertEquals('hook_civicrm_alterSettingsMetaData', $eventDef['name']); + $this->assertEquals(array('settingsMetaData', 'domainID', 'profile'), array_keys($eventDef['fields'])); + $this->assertTrue($eventDef['is_hook']); + $this->assertTrue($eventDef['fields']['settingsMetaData']['ref']); + $this->assertFalse($eventDef['fields']['domainID']['ref']); + $this->assertEquals('&$settingsMetaData, $domainID, $profile', $eventDef['signature']); + $this->assertTrue($inspector->validate($eventDef)); } public function testGetAll() { @@ -23,11 +24,23 @@ class CiviEventInspectorTest extends \CiviUnitTestCase { $all = $inspector->getAll(); $this->assertTrue(count($all) > 1); $this->assertTrue(isset($all['hook_civicrm_alterSettingsMetaData'])); - foreach ($all as $name => $hook) { - $this->assertEquals($name, $hook['name']); - $this->assertNotEmpty($hook['description_html']); - $this->assertTrue($inspector->validate($hook)); + foreach ($all as $name => $eventDef) { + $this->assertEquals($name, $eventDef['name']); + $this->assertNotEmpty($eventDef['description_html']); + $this->assertTrue($inspector->validate($eventDef)); } } + public function testFind() { + $inspector = new CiviEventInspector(); + + $result_a = $inspector->find('/^hook_civicrm_post/'); + $this->assertTrue(is_array($result_a['hook_civicrm_post'])); + $this->assertFalse(isset($result_a['hook_civicrm_pre'])); + + $result_b = $inspector->find('/^hook_civicrm_pre/'); + $this->assertTrue(is_array($result_b['hook_civicrm_pre'])); + $this->assertFalse(isset($result_b['hook_civicrm_post'])); + } + } -- 2.25.1