From e52a792060078419361c1f02d46d99658ff982ef Mon Sep 17 00:00:00 2001 From: Umherirrender Date: Tue, 6 Jun 2023 23:02:02 +0200 Subject: [PATCH] Create HookRunner class and the hook handler interfaces Bug: T315938 Change-Id: Iffa2b409502b4269c9746e0304feb4aaee37a86e --- extension.json | 2 +- .../Controller/NotificationController.php | 9 +- includes/DiscussionParser.php | 4 +- includes/Hooks.php | 14 +- includes/Hooks/BeforeCreateEchoEventHook.php | 26 +++ .../Hooks/BeforeDisplayOrangeAlertHook.php | 22 +++ includes/Hooks/BeforeEchoEventInsertHook.php | 20 +++ .../Hooks/EchoAbortEmailNotificationHook.php | 22 +++ .../EchoCanAbortNewMessagesAlertHook.php | 17 ++ .../EchoCreateNotificationCompleteHook.php | 20 +++ includes/Hooks/EchoGetBundleRulesHook.php | 21 +++ .../Hooks/EchoGetDefaultNotifiedUsersHook.php | 22 +++ .../Hooks/EchoGetEventsForRevisionHook.php | 22 +++ .../Hooks/EchoGetNotificationTypesHook.php | 23 +++ includes/Hooks/EventInsertCompleteHook.php | 20 +++ includes/Hooks/HookRunner.php | 148 ++++++++++++++++++ includes/Model/Event.php | 7 +- includes/Model/Notification.php | 8 +- includes/Notifier.php | 8 +- tests/phpunit/unit/HookRunnerTest.php | 16 ++ 20 files changed, 428 insertions(+), 23 deletions(-) create mode 100644 includes/Hooks/BeforeCreateEchoEventHook.php create mode 100644 includes/Hooks/BeforeDisplayOrangeAlertHook.php create mode 100644 includes/Hooks/BeforeEchoEventInsertHook.php create mode 100644 includes/Hooks/EchoAbortEmailNotificationHook.php create mode 100644 includes/Hooks/EchoCanAbortNewMessagesAlertHook.php create mode 100644 includes/Hooks/EchoCreateNotificationCompleteHook.php create mode 100644 includes/Hooks/EchoGetBundleRulesHook.php create mode 100644 includes/Hooks/EchoGetDefaultNotifiedUsersHook.php create mode 100644 includes/Hooks/EchoGetEventsForRevisionHook.php create mode 100644 includes/Hooks/EchoGetNotificationTypesHook.php create mode 100644 includes/Hooks/EventInsertCompleteHook.php create mode 100644 includes/Hooks/HookRunner.php create mode 100644 tests/phpunit/unit/HookRunnerTest.php diff --git a/extension.json b/extension.json index 0550431e5..6333ce270 100644 --- a/extension.json +++ b/extension.json @@ -15,7 +15,7 @@ "license-name": "MIT", "type": "specialpage", "requires": { - "MediaWiki": ">= 1.40.0" + "MediaWiki": ">= 1.41.0" }, "APIMetaModules": { "notifications": { diff --git a/includes/Controller/NotificationController.php b/includes/Controller/NotificationController.php index 6b4064330..554f9ac9c 100644 --- a/includes/Controller/NotificationController.php +++ b/includes/Controller/NotificationController.php @@ -12,6 +12,7 @@ use EchoServices; use InvalidArgumentException; use Iterator; use MapCacheLRU; +use MediaWiki\Extension\Notifications\Hooks\HookRunner; use MediaWiki\Extension\Notifications\Iterator\FilteredSequentialIterator; use MediaWiki\Extension\Notifications\Jobs\NotificationDeleteJob; use MediaWiki\Extension\Notifications\Jobs\NotificationJob; @@ -128,7 +129,7 @@ class NotificationController { $userIds = []; $userIdsCount = 0; $services = MediaWikiServices::getInstance(); - $hookContainer = $services->getHookContainer(); + $hookRunner = new HookRunner( $services->getHookContainer() ); $userOptionsLookup = $services->getUserOptionsLookup(); /** @var bool|null $hasMinorRevision */ $hasMinorRevision = null; @@ -147,7 +148,7 @@ class NotificationController { $userNotifyTypes = array_diff( $userNotifyTypes, [ 'email' ] ); } } - $hookContainer->run( 'EchoGetNotificationTypes', [ $user, $event, &$userNotifyTypes ] ); + $hookRunner->onEchoGetNotificationTypes( $user, $event, $userNotifyTypes ); // types such as web, email, etc foreach ( $userNotifyTypes as $type ) { @@ -489,8 +490,8 @@ class NotificationController { // Hook for injecting more users. // @deprecated $users = []; - MediaWikiServices::getInstance()->getHookContainer()->run( 'EchoGetDefaultNotifiedUsers', [ $event, &$users ] ); - // @phan-suppress-next-line PhanImpossibleCondition May be set by hook + ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) ) + ->onEchoGetDefaultNotifiedUsers( $event, $users ); if ( $users ) { $notify->add( $users ); } diff --git a/includes/DiscussionParser.php b/includes/DiscussionParser.php index 0bd7a402b..b0c2133f1 100644 --- a/includes/DiscussionParser.php +++ b/includes/DiscussionParser.php @@ -1,5 +1,6 @@ getHookContainer()->run( 'EchoGetEventsForRevision', [ &$events, $revision, $isRevert ] ); + ( new HookRunner( $services->getHookContainer() ) ) + ->onEchoGetEventsForRevision( $events, $revision, $isRevert ); // Create events foreach ( $events as $event ) { diff --git a/includes/Hooks.php b/includes/Hooks.php index 0cffcbdf0..86c288a17 100644 --- a/includes/Hooks.php +++ b/includes/Hooks.php @@ -27,6 +27,7 @@ use MediaWiki\DAO\WikiAwareEntity; use MediaWiki\Extension\Notifications\Controller\ModerationController; use MediaWiki\Extension\Notifications\Controller\NotificationController; use MediaWiki\Extension\Notifications\Formatters\EchoEventPresentationModel; +use MediaWiki\Extension\Notifications\Hooks\HookRunner; use MediaWiki\Extension\Notifications\Mapper\EventMapper; use MediaWiki\Extension\Notifications\Mapper\NotificationMapper; use MediaWiki\Extension\Notifications\Model\Event; @@ -197,8 +198,8 @@ class Hooks implements $wgEnableUserEmail; // allow extensions to define their own event - MediaWikiServices::getInstance()->getHookContainer()->run( 'BeforeCreateEchoEvent', - [ &$wgEchoNotifications, &$wgEchoNotificationCategories, &$wgEchoNotificationIcons ] ); + ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )->onBeforeCreateEchoEvent( + $wgEchoNotifications, $wgEchoNotificationCategories, $wgEchoNotificationIcons ); // Only allow mention status notifications when enabled if ( !$wgEchoMentionStatusNotifications ) { @@ -748,7 +749,7 @@ class Hooks implements /** * Handler for EchoAbortEmailNotification hook - * @param User $user + * @param UserIdentity $user * @param Event $event * @return bool true - send email, false - do not send email */ @@ -1194,8 +1195,8 @@ class Hooks implements if ( $mytalk && self::shouldDisplayTalkAlert( $user, $title ) && - MediaWikiServices::getInstance() - ->getHookContainer()->run( 'BeforeDisplayOrangeAlert', [ $user, $title ] ) + ( new HookRunner( MediaWikiServices::getInstance() + ->getHookContainer() ) )->onBeforeDisplayOrangeAlert( $user, $title ) ) { // Create new talk alert inheriting from the talk link data. $links['notifications']['talk-alert'] = array_merge( @@ -1367,7 +1368,8 @@ class Hooks implements // notifications for talk page messages, disable the new messages alert. if ( $user->isRegistered() && isset( $wgEchoNotifications['edit-user-talk'] ) - && MediaWikiServices::getInstance()->getHookContainer()->run( 'EchoCanAbortNewMessagesAlert' ) + && ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) ) + ->onEchoCanAbortNewMessagesAlert() ) { // hide new messages alert return false; diff --git a/includes/Hooks/BeforeCreateEchoEventHook.php b/includes/Hooks/BeforeCreateEchoEventHook.php new file mode 100644 index 000000000..fd2619404 --- /dev/null +++ b/includes/Hooks/BeforeCreateEchoEventHook.php @@ -0,0 +1,26 @@ +hookContainer = $hookContainer; + } + + /** + * @inheritDoc + */ + public function onBeforeCreateEchoEvent( + array &$notifications, + array &$notificationCategories, + array &$notificationIcons + ) { + return $this->hookContainer->run( + 'BeforeCreateEchoEvent', + [ &$notifications, &$notificationCategories, &$notificationIcons ] + ); + } + + /** + * @inheritDoc + */ + public function onBeforeDisplayOrangeAlert( User $user, Title $title ) { + return $this->hookContainer->run( + 'BeforeDisplayOrangeAlert', + [ $user, $title ] + ); + } + + /** + * @inheritDoc + */ + public function onBeforeEchoEventInsert( Event $event ) { + return $this->hookContainer->run( + 'BeforeEchoEventInsert', + [ $event ] + ); + } + + /** + * @inheritDoc + */ + public function onEchoAbortEmailNotification( UserIdentity $user, Event $event ) { + return $this->hookContainer->run( + 'EchoAbortEmailNotification', + [ $user, $event ] + ); + } + + /** + * @inheritDoc + */ + public function onEchoCanAbortNewMessagesAlert() { + return $this->hookContainer->run( + 'EchoCanAbortNewMessagesAlert' + ); + } + + /** + * @inheritDoc + */ + public function onEchoCreateNotificationComplete( Notification $notification ) { + return $this->hookContainer->run( + 'EchoCreateNotificationComplete', + [ $notification ] + ); + } + + /** + * @inheritDoc + */ + public function onEchoGetBundleRules( Event $event, string &$bundleKey ) { + return $this->hookContainer->run( + 'EchoGetBundleRules', + [ $event, &$bundleKey ] + ); + } + + /** + * @inheritDoc + */ + public function onEchoGetDefaultNotifiedUsers( Event $event, array &$users ) { + return $this->hookContainer->run( + 'EchoGetDefaultNotifiedUsers', + [ $event, &$users ] + ); + } + + /** + * @inheritDoc + */ + public function onEchoGetEventsForRevision( array &$events, RevisionRecord $revision, bool $isRevert ) { + return $this->hookContainer->run( + 'EchoGetEventsForRevision', + [ &$events, $revision, $isRevert ] + ); + } + + /** + * @inheritDoc + */ + public function onEchoGetNotificationTypes( User $user, Event $event, array &$userNotifyTypes ) { + return $this->hookContainer->run( + 'EchoGetNotificationTypes', + [ $user, $event, &$userNotifyTypes ] + ); + } + + /** + * @inheritDoc + */ + public function onEventInsertComplete( Event $event ) { + return $this->hookContainer->run( + 'EventInsertComplete', + [ $event ] + ); + } +} diff --git a/includes/Model/Event.php b/includes/Model/Event.php index 1b834ce26..829172f69 100644 --- a/includes/Model/Event.php +++ b/includes/Model/Event.php @@ -9,6 +9,7 @@ use InvalidArgumentException; use MediaWiki\Extension\Notifications\Cache\RevisionLocalCache; use MediaWiki\Extension\Notifications\Cache\TitleLocalCache; use MediaWiki\Extension\Notifications\Controller\NotificationController; +use MediaWiki\Extension\Notifications\Hooks\HookRunner; use MediaWiki\Extension\Notifications\Mapper\EventMapper; use MediaWiki\Extension\Notifications\Mapper\TargetPageMapper; use MediaWiki\Logger\LoggerFactory; @@ -192,15 +193,15 @@ class Event extends AbstractEntity implements Bundleable { } } - $hookContainer = $services->getHookContainer(); - if ( !$hookContainer->run( 'BeforeEchoEventInsert', [ $obj ] ) ) { + $hookRunner = new HookRunner( $services->getHookContainer() ); + if ( !$hookRunner->onBeforeEchoEventInsert( $obj ) ) { return false; } // @Todo - Database insert logic should not be inside the model $obj->insert(); - $hookContainer->run( 'EventInsertComplete', [ $obj ] ); + $hookRunner->onEventInsertComplete( $obj ); global $wgEchoUseJobQueue; diff --git a/includes/Model/Notification.php b/includes/Model/Notification.php index a167c3228..ca5c0ce43 100644 --- a/includes/Model/Notification.php +++ b/includes/Model/Notification.php @@ -4,6 +4,7 @@ namespace MediaWiki\Extension\Notifications\Model; use Bundleable; use InvalidArgumentException; +use MediaWiki\Extension\Notifications\Hooks\HookRunner; use MediaWiki\Extension\Notifications\Mapper\NotificationMapper; use MediaWiki\MediaWikiServices; use MWEchoNotifUser; @@ -106,14 +107,13 @@ class Notification extends AbstractEntity implements Bundleable { $notifMapper = new NotificationMapper(); $services = MediaWikiServices::getInstance(); - $hookContainer = $services->getHookContainer(); + $hookRunner = new HookRunner( $services->getHookContainer() ); // Get the bundle key for this event if web bundling is enabled $bundleKey = ''; if ( !empty( $wgEchoNotifications[$this->event->getType()]['bundle']['web'] ) ) { - $hookContainer->run( 'EchoGetBundleRules', [ $this->event, &$bundleKey ] ); + $hookRunner->onEchoGetBundleRules( $this->event, $bundleKey ); } - // @phan-suppress-next-line PhanImpossibleCondition May be set by hook if ( $bundleKey ) { $hash = md5( $bundleKey ); $this->bundleHash = $hash; @@ -134,7 +134,7 @@ class Notification extends AbstractEntity implements Bundleable { $services->getTalkPageNotificationManager() ->setUserHasNewMessages( $this->user ); } - $hookContainer->run( 'EchoCreateNotificationComplete', [ $this ] ); + $hookRunner->onEchoCreateNotificationComplete( $this ); } /** diff --git a/includes/Notifier.php b/includes/Notifier.php index 3f53bda84..a410c8b95 100644 --- a/includes/Notifier.php +++ b/includes/Notifier.php @@ -2,6 +2,7 @@ use MediaWiki\Extension\Notifications\Formatters\EchoHtmlEmailFormatter; use MediaWiki\Extension\Notifications\Formatters\EchoPlainTextEmailFormatter; +use MediaWiki\Extension\Notifications\Hooks\HookRunner; use MediaWiki\Extension\Notifications\Model\Event; use MediaWiki\Extension\Notifications\Model\Notification; use MediaWiki\MediaWikiServices; @@ -52,9 +53,9 @@ class EchoNotifier { return false; } - $hookContainer = $services->getHookContainer(); + $hookRunner = new HookRunner( $services->getHookContainer() ); // Final check on whether to send email for this user & event - if ( !$hookContainer->run( 'EchoAbortEmailNotification', [ $user, $event ] ) ) { + if ( !$hookRunner->onEchoAbortEmailNotification( $user, $event ) ) { return false; } @@ -74,9 +75,8 @@ class EchoNotifier { if ( !empty( $wgEchoNotifications[$event->getType()]['bundle']['web'] ) || !empty( $wgEchoNotifications[$event->getType()]['bundle']['email'] ) ) { - $hookContainer->run( 'EchoGetBundleRules', [ $event, &$bundleString ] ); + $hookRunner->onEchoGetBundleRules( $event, $bundleString ); } - // @phan-suppress-next-line PhanImpossibleCondition May be set by hook if ( $bundleString ) { $bundleHash = md5( $bundleString ); } diff --git a/tests/phpunit/unit/HookRunnerTest.php b/tests/phpunit/unit/HookRunnerTest.php new file mode 100644 index 000000000..db1b1d38a --- /dev/null +++ b/tests/phpunit/unit/HookRunnerTest.php @@ -0,0 +1,16 @@ + [ HookRunner::class ]; + } +}