From c8d8465306767fe281283ed005f1f1cb86d0f7c1 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 21 May 2021 11:51:32 -0700 Subject: [PATCH] BAOs - Allow BAOs to subscribe to hooks/events via `EventSubscriberInterface` or `HookInterface` Before: There is no pleasant way for a BAO to register a listener for an event. True, one can use `Civi::dispatch()`, but (lacking a good initialization point) it's hard to register reliably. True, you can also add new items to `\Civi\Core\Container::createEventDispatcher()`, but this is rather out-of-the-way. After: A BAO class may optionally implement `EventDispatcherInterface` or `HookInterface`. Methods will be automatically registered. The list of listeners will be cached in the container. --- CRM/Core/DAO/AllCoreTables.php | 17 +++++++++++++++++ Civi/Core/Container.php | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/CRM/Core/DAO/AllCoreTables.php b/CRM/Core/DAO/AllCoreTables.php index 0e4b38b848..04e4fe32dc 100644 --- a/CRM/Core/DAO/AllCoreTables.php +++ b/CRM/Core/DAO/AllCoreTables.php @@ -276,6 +276,23 @@ class CRM_Core_DAO_AllCoreTables { return array_values(self::daoToClass()); } + /** + * Get a list of all extant BAO classes. + * + * @return array + * Ex: ['Contact' => 'CRM_Contact_BAO_Contact'] + */ + public static function getBaoClasses() { + $r = []; + foreach (\CRM_Core_DAO_AllCoreTables::daoToClass() as $entity => $daoClass) { + $baoClass = str_replace('_DAO_', '_BAO_', $daoClass); + if (class_exists($baoClass)) { + $r[$entity] = $baoClass; + } + } + return $r; + } + /** * Get the classname for the table. * diff --git a/Civi/Core/Container.php b/Civi/Core/Container.php index 947a2657d8..fa723a77b3 100644 --- a/Civi/Core/Container.php +++ b/Civi/Core/Container.php @@ -1,6 +1,7 @@ addTag('kernel.event_subscriber')->setPublic(TRUE); } + $dispatcherDefn = $container->getDefinition('dispatcher'); + foreach (\CRM_Core_DAO_AllCoreTables::getBaoClasses() as $baoEntity => $baoClass) { + $listenerMap = EventScanner::findListeners($baoClass, $baoEntity); + if ($listenerMap) { + $file = (new \ReflectionClass($baoClass))->getFileName(); + $container->addResource(new \Symfony\Component\Config\Resource\FileResource($file)); + $dispatcherDefn->addMethodCall('addListenerMap', [$baoClass, $listenerMap]); + } + } + \CRM_Api4_Services::hook_container($container); \CRM_Utils_Hook::container($container); -- 2.25.1