diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 0b8c63bbe..fe190dc77 100644 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -55,7 +55,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $url = trim($url); /** @var string|null $urlHooked */ - $urlHooked = Minz_ExtensionManager::callHook('check_url_before_add', $url); + $urlHooked = Minz_ExtensionManager::callHook(Minz_HookType::CheckUrlBeforeAdd, $url); if ($urlHooked === null) { throw new FreshRSS_FeedNotAdded_Exception($url); } @@ -106,7 +106,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { } /** @var FreshRSS_Feed|null $feed */ - $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + $feed = Minz_ExtensionManager::callHook(Minz_HookType::FeedBeforeInsert, $feed); if ($feed === null) { throw new FreshRSS_FeedNotAdded_Exception($url); } @@ -465,7 +465,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $categoriesEntriesTitle = []; foreach ($feeds as $feed) { - $feed = Minz_ExtensionManager::callHook('feed_before_actualize', $feed); + $feed = Minz_ExtensionManager::callHook(Minz_HookType::FeedBeforeActualize, $feed); if (!($feed instanceof FreshRSS_Feed)) { continue; } @@ -616,10 +616,10 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $entry->_isFavorite(null); // Do not change favourite state $entry->_isRead($mark_updated_article_unread ? false : null); //Change is_read according to policy. if ($mark_updated_article_unread) { - Minz_ExtensionManager::callHook('entry_auto_unread', $entry, 'updated_article'); + Minz_ExtensionManager::callHook(Minz_HookType::EntryAutoUnread, $entry, 'updated_article'); } - $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeInsert, $entry); if (!($entry instanceof FreshRSS_Entry)) { // An extension has returned a null value, there is nothing to insert. continue; @@ -642,7 +642,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { // If the entry has changed, there is a good chance for the full content to have changed as well. $entry->loadCompleteContent(true); - $entry = Minz_ExtensionManager::callHook('entry_before_update', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeUpdate, $entry); if (!($entry instanceof FreshRSS_Entry)) { // An extension has returned a null value, there is nothing to insert. continue; @@ -655,7 +655,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $id = uTimeString(); $entry->_id($id); - $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeInsert, $entry); if (!($entry instanceof FreshRSS_Entry)) { // An extension has returned a null value, there is nothing to insert. continue; @@ -681,7 +681,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $feed->pubSubHubbubError(true); } - $entry = Minz_ExtensionManager::callHook('entry_before_add', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeAdd, $entry); if (!($entry instanceof FreshRSS_Entry)) { // An extension has returned a null value, there is nothing to insert. continue; @@ -911,7 +911,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { // Case of a batch refresh (e.g. cron) $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); $databaseDAO->minorDbMaintenance(); - Minz_ExtensionManager::callHookVoid('freshrss_user_maintenance'); + Minz_ExtensionManager::callHookVoid(Minz_HookType::FreshrssUserMaintenance); FreshRSS_feed_Controller::commitNewEntries(); $feedDAO = FreshRSS_Factory::createFeedDao(); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 9f9f6b2bd..8e03299f9 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -478,14 +478,14 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { } $newGuids[$entry->guid()] = true; - $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeInsert, $entry); if (!($entry instanceof FreshRSS_Entry)) { // An extension has returned a null value, there is nothing to insert. continue; } if (isset($existingHashForGuids['f_' . $feed_id][$entry->guid()])) { - $entry = Minz_ExtensionManager::callHook('entry_before_update', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeUpdate, $entry); if (!($entry instanceof FreshRSS_Entry)) { // An extension has returned a null value, there is nothing to insert. continue; @@ -495,7 +495,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { } else { $entry->_lastSeen(time()); - $entry = Minz_ExtensionManager::callHook('entry_before_add', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeAdd, $entry); if (!($entry instanceof FreshRSS_Entry)) { // An extension has returned a null value, there is nothing to insert. continue; @@ -581,7 +581,7 @@ class FreshRSS_importExport_Controller extends FreshRSS_ActionController { } // Call the extension hook - $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + $feed = Minz_ExtensionManager::callHook(Minz_HookType::FeedBeforeInsert, $feed); if ($feed instanceof FreshRSS_Feed) { // addFeedObject checks if feed is already in DB so nothing else to // check here. diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 5fd925f72..1370c00c7 100644 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -32,7 +32,7 @@ class FreshRSS_javascript_Controller extends FreshRSS_ActionController { $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); $databaseDAO->minorDbMaintenance(); - Minz_ExtensionManager::callHookVoid('freshrss_user_maintenance'); + Minz_ExtensionManager::callHookVoid(Minz_HookType::FreshrssUserMaintenance); $catDAO = FreshRSS_Factory::createCategoryDao(); $this->view->categories = $catDAO->listCategoriesOrderUpdate(FreshRSS_Context::userConf()->dynamic_opml_ttl_default); diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index bec639b39..bd140b6d5 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -283,7 +283,7 @@ class FreshRSS_update_Controller extends FreshRSS_ActionController { $res = do_post_update(); } - Minz_ExtensionManager::callHookVoid('post_update'); + Minz_ExtensionManager::callHookVoid(Minz_HookType::PostUpdate); if ($res === true) { @unlink(UPDATE_FILENAME); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index cac803329..0d433dc2b 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -66,7 +66,7 @@ class FreshRSS extends Minz_FrontController { self::checkEmailValidated(); } - Minz_ExtensionManager::callHookVoid('freshrss_init'); + Minz_ExtensionManager::callHookVoid(Minz_HookType::FreshrssInit); } private static function initAuth(): void { diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 7254dd513..0769762f8 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -818,12 +818,12 @@ HTML; if (!$this->isRead()) { if ($feed->attributeBoolean('read_upon_reception') ?? FreshRSS_Context::userConf()->mark_when['reception']) { $this->_isRead(true); - Minz_ExtensionManager::callHook('entry_auto_read', $this, 'upon_reception'); + Minz_ExtensionManager::callHook(Minz_HookType::EntryAutoRead, $this, 'upon_reception'); } if (!empty($titlesAsRead[$this->title()])) { Minz_Log::debug('Mark title as read: ' . $this->title()); $this->_isRead(true); - Minz_ExtensionManager::callHook('entry_auto_read', $this, 'same_title_in_feed'); + Minz_ExtensionManager::callHook(Minz_HookType::EntryAutoRead, $this, 'same_title_in_feed'); } } FreshRSS_Context::userConf()->applyFilterActions($this); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index ad1cc4393..f236cd3f3 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -387,7 +387,7 @@ SQL; $values = array_merge($values, $ids); $stm = $this->pdo->prepare($sql); if ($stm !== false && $stm->execute($values)) { - Minz_ExtensionManager::callHook('entries_favorite', $ids, $is_favorite); + Minz_ExtensionManager::callHook(Minz_HookType::EntriesFavorite, $ids, $is_favorite); return $stm->rowCount(); } else { $info = $stm === false ? $this->pdo->errorInfo() : $stm->errorInfo(); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 2b29f7b22..112da1a00 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -255,7 +255,7 @@ class FreshRSS_Feed extends Minz_Model { $params = ''; if ($this->customFavicon()) { $current = $this->id . Minz_User::name(); - $hookParams = Minz_ExtensionManager::callHook('custom_favicon_hash', $this); + $hookParams = Minz_ExtensionManager::callHook(Minz_HookType::CustomFaviconHash, $this); $params = $hookParams !== null ? $hookParams : $current; } else { $params = $this->website(fallback: true) . $this->proxyParam(); @@ -579,9 +579,9 @@ class FreshRSS_Feed extends Minz_Model { // Do not use `$simplePie->enable_cache(false);` as it would prevent caching in multiuser context $this->clearCache(); } - Minz_ExtensionManager::callHook('simplepie_before_init', $simplePie, $this); + Minz_ExtensionManager::callHook(Minz_HookType::SimplepieBeforeInit, $simplePie, $this); $simplePieResult = $simplePie->init(); - Minz_ExtensionManager::callHook('simplepie_after_init', $simplePie, $this, $simplePieResult); + Minz_ExtensionManager::callHook(Minz_HookType::SimplepieAfterInit, $simplePie, $this, $simplePieResult); if ($simplePieResult === false || $simplePie->get_hash() === '' || !empty($simplePie->error())) { if ($simplePie->status_code() === 429) { diff --git a/app/Models/FilterActionsTrait.php b/app/Models/FilterActionsTrait.php index 3d8257e34..36b3682d8 100644 --- a/app/Models/FilterActionsTrait.php +++ b/app/Models/FilterActionsTrait.php @@ -132,7 +132,7 @@ trait FreshRSS_FilterActionsTrait { case 'read': if (!$entry->isRead()) { $entry->_isRead(true); - Minz_ExtensionManager::callHook('entry_auto_read', $entry, 'filter'); + Minz_ExtensionManager::callHook(Minz_HookType::EntryAutoRead, $entry, 'filter'); } break; case 'star': diff --git a/app/Models/ViewMode.php b/app/Models/ViewMode.php index 54379b130..fde073097 100644 --- a/app/Models/ViewMode.php +++ b/app/Models/ViewMode.php @@ -51,7 +51,7 @@ final class FreshRSS_ViewMode { $modes = self::getDefaultModes(); // Allow extensions to add their own view modes - $extensionModes = Minz_ExtensionManager::callHook('view_modes', []); + $extensionModes = Minz_ExtensionManager::callHook(Minz_HookType::ViewModes, []); if (is_array($extensionModes)) { foreach ($extensionModes as $mode) { if ($mode instanceof FreshRSS_ViewMode) { diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index e7af7589d..b567544b3 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -311,7 +311,7 @@ class FreshRSS_Import_Service { // Call the extension hook /** @var FreshRSS_Feed|null */ - $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + $feed = Minz_ExtensionManager::callHook(Minz_HookType::FeedBeforeInsert, $feed); if ($dry_run) { if ($feed !== null) { diff --git a/app/actualize_script.php b/app/actualize_script.php index 2be2a117a..e64d0b707 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -96,7 +96,7 @@ foreach ($users as $user) { // NB: Extensions and hooks are reinitialised there $app->init(); - Minz_ExtensionManager::addHook('feed_before_actualize', static function (FreshRSS_Feed $feed) use ($mutexFile) { + Minz_ExtensionManager::addHook(Minz_HookType::FeedBeforeActualize, static function (FreshRSS_Feed $feed) use ($mutexFile) { touch($mutexFile); return $feed; }); diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 7413f002d..6ebf232e2 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -60,7 +60,7 @@ - + @@ -88,7 +88,7 @@
  • - + diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 1e4290f98..e92b3c2ef 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -87,7 +87,7 @@
  • - + @@ -103,7 +103,7 @@ disable_update) { ?>
  • - + @@ -117,7 +117,7 @@ - + diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 2f09465aa..d477bff37 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -190,7 +190,7 @@ - + - +
    - +
    entryIdsTagNames)) { foreach ($this->entries as $entry) { if (!$this->internal_rendering) { /** @var FreshRSS_Entry|null $entry */ - $entry = Minz_ExtensionManager::callHook('entry_before_display', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeDisplay, $entry); } if ($entry === null) { continue; diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 0666a7130..c5dae8460 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -50,7 +50,7 @@ $originalIconUrl = $this->feed->favicon(); $this->feed->_attribute('customFavicon', $currentIconUrl !== $originalIconUrl); $this->feed->resetFaviconHash(); - $ext_url = Minz_ExtensionManager::callHook('custom_favicon_btn_url', $this->feed); + $ext_url = Minz_ExtensionManager::callHook(Minz_HookType::CustomFaviconBtnUrl, $this->feed); ?>
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 2d2d2e364..2cedc20c3 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -3,7 +3,7 @@ declare(strict_types=1); /** @var FreshRSS_View $this */ $mark = FreshRSS_Context::userConf()->mark_when; $s = FreshRSS_Context::userConf()->shortcuts; -$extData = Minz_ExtensionManager::callHook('js_vars', []); +$extData = Minz_ExtensionManager::callHook(Minz_HookType::JsVars, []); echo json_encode([ 'context' => [ 'anonymous' => !FreshRSS_Auth::hasAccess(), diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index cc800c3fe..1b942ae17 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -47,7 +47,7 @@ $today = @strtotime('today'); $nbEntries = 0; foreach ($this->entries as $item): /** @var FreshRSS_Entry|null $item */ - $item = Minz_ExtensionManager::callHook('entry_before_display', $item); + $item = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeDisplay, $item); if ($item === null) { continue; } diff --git a/app/views/index/reader.phtml b/app/views/index/reader.phtml index bb957f232..49321f9f5 100644 --- a/app/views/index/reader.phtml +++ b/app/views/index/reader.phtml @@ -20,7 +20,7 @@ $useKeepUnreadImportant = !FreshRSS_Context::isImportant() && !FreshRSS_Context: $nbEntries = 0; foreach ($this->entries as $entry): /** @var FreshRSS_Entry|null $entry */ - $entry = Minz_ExtensionManager::callHook('entry_before_display', $entry); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeDisplay, $entry); if ($entry === null) { continue; } diff --git a/app/views/index/rss.phtml b/app/views/index/rss.phtml index 7d92bd140..7caf4cb9d 100644 --- a/app/views/index/rss.phtml +++ b/app/views/index/rss.phtml @@ -23,7 +23,7 @@ foreach ($this->entries as $item) { if (!$this->internal_rendering) { /** @var FreshRSS_Entry|null $item */ - $item = Minz_ExtensionManager::callHook('entry_before_display', $item); + $item = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeDisplay, $item); if ($item === null) { continue; } diff --git a/cli/actualize-user.php b/cli/actualize-user.php index d5633766f..77254d834 100755 --- a/cli/actualize-user.php +++ b/cli/actualize-user.php @@ -20,13 +20,13 @@ if (!empty($cliOptions->errors)) { $username = cliInitUser($cliOptions->user); -Minz_ExtensionManager::callHookVoid('freshrss_user_maintenance'); +Minz_ExtensionManager::callHookVoid(Minz_HookType::FreshrssUserMaintenance); fwrite(STDERR, 'FreshRSS actualizing user “' . $username . "”…\n"); $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); $databaseDAO->minorDbMaintenance(); -Minz_ExtensionManager::callHookVoid('freshrss_user_maintenance'); +Minz_ExtensionManager::callHookVoid(Minz_HookType::FreshrssUserMaintenance); FreshRSS_feed_Controller::commitNewEntries(); $feedDAO = FreshRSS_Factory::createFeedDao(); diff --git a/docs/en/developers/03_Backend/05_Extensions.md b/docs/en/developers/03_Backend/05_Extensions.md index fcae42b5a..189e5d64f 100644 --- a/docs/en/developers/03_Backend/05_Extensions.md +++ b/docs/en/developers/03_Backend/05_Extensions.md @@ -143,8 +143,8 @@ final class HelloWorldExtension extends Minz_Extension public function init(): void { parent::init(); - $this->registerHook('entry_before_display', [$this, 'renderEntry']); - $this->registerHook('check_url_before_add', [self::class, 'checkUrl']); + $this->registerHook(Minz_HookType::EntryBeforeDisplay, [$this, 'renderEntry']); + $this->registerHook(Minz_HookType::CheckUrlBeforeAdd, [self::class, 'checkUrl']); } public function renderEntry(FreshRSS_Entry $entry): FreshRSS_Entry { @@ -164,7 +164,7 @@ final class HelloWorldExtension extends Minz_Extension The following events are available: -* `api_misc` (`function(): void`): to allow extensions to have own API endpoint +* `api_misc` (`function(): void`): to allow extensions to have their own API endpoint on `/api/misc.php/Extension%20Name/` or `/api/misc.php?ext=Extension%20Name`. * `before_login_btn` (`function(): string`): Allows to insert HTML before the login button. Applies to the create button on the register page as well. Example use case is inserting a captcha widget. * `check_url_before_add` (`function($url) -> Url | null`): will be executed every time a URL is added. The URL itself will be passed as parameter. This way a website known to have feeds which doesn’t advertise it in the header can still be automatically supported. diff --git a/docs/fr/developers/03_Backend/05_Extensions.md b/docs/fr/developers/03_Backend/05_Extensions.md index 18cc892be..00a229e94 100644 --- a/docs/fr/developers/03_Backend/05_Extensions.md +++ b/docs/fr/developers/03_Backend/05_Extensions.md @@ -197,8 +197,8 @@ final class HelloWorldExtension extends Minz_Extension public function init(): void { parent::init(); - $this->registerHook('entry_before_display', [$this, 'renderEntry']); - $this->registerHook('check_url_before_add', [self::class, 'checkUrl']); + $this->registerHook(Minz_HookType::EntryBeforeDisplay, [$this, 'renderEntry']); + $this->registerHook(Minz_HookType::CheckUrlBeforeAdd, [self::class, 'checkUrl']); } public function renderEntry(FreshRSS_Entry $entry): FreshRSS_Entry { diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index b91a89de7..04e1806c4 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -19,114 +19,9 @@ final class Minz_ExtensionManager { /** * List of available hooks. Please keep this list sorted. - * @var array,'signature':'NoneToNone'|'NoneToString'|'OneToOne'|'PassArguments'}> + * @var array,array{'list':list,'signature':Minz_HookSignature}> */ - private static array $hook_list = [ - 'api_misc' => [ // function(): void - 'list' => [], - 'signature' => 'NoneToNone', - ], - 'before_login_btn' => [ // function(): string - 'list' => [], - 'signature' => 'NoneToString', - ], - 'check_url_before_add' => [ // function($url) -> Url | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'custom_favicon_btn_url' => [ // function(FreshRSS_Feed $feed): string | null - 'list' => [], - 'signature' => 'PassArguments', - ], - 'custom_favicon_hash' => [ // function(FreshRSS_Feed $feed): string | null - 'list' => [], - 'signature' => 'PassArguments', - ], - 'entries_favorite' => [ // function(array $ids, bool $is_favorite): void - 'list' => [], - 'signature' => 'PassArguments', - ], - 'entry_auto_read' => [ // function(FreshRSS_Entry $entry, string $why): void - 'list' => [], - 'signature' => 'PassArguments', - ], - 'entry_auto_unread' => [ // function(FreshRSS_Entry $entry, string $why): void - 'list' => [], - 'signature' => 'PassArguments', - ], - 'entry_before_display' => [ // function($entry) -> Entry | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'entry_before_insert' => [ // function($entry) -> Entry | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'entry_before_add' => [ // function($entry) -> Entry | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'entry_before_update' => [ // function($entry) -> Entry | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'feed_before_actualize' => [ // function($feed) -> Feed | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'feed_before_insert' => [ // function($feed) -> Feed | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'freshrss_init' => [ // function() -> none - 'list' => [], - 'signature' => 'NoneToNone', - ], - 'freshrss_user_maintenance' => [ // function() -> none - 'list' => [], - 'signature' => 'NoneToNone', - ], - 'js_vars' => [ // function($vars = array) -> array | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'menu_admin_entry' => [ // function() -> string - 'list' => [], - 'signature' => 'NoneToString', - ], - 'menu_configuration_entry' => [ // function() -> string - 'list' => [], - 'signature' => 'NoneToString', - ], - 'menu_other_entry' => [ // function() -> string - 'list' => [], - 'signature' => 'NoneToString', - ], - 'nav_menu' => [ // function() -> string - 'list' => [], - 'signature' => 'NoneToString', - ], - 'nav_reading_modes' => [ // function($readingModes = array) -> array | null - 'list' => [], - 'signature' => 'OneToOne', - ], - 'post_update' => [ // function(none) -> none - 'list' => [], - 'signature' => 'NoneToNone', - ], - 'simplepie_after_init' => [ // function(\SimplePie\SimplePie $simplePie, FreshRSS_Feed $feed, bool $result): void - 'list' => [], - 'signature' => 'PassArguments', - ], - 'simplepie_before_init' => [ // function(\SimplePie\SimplePie $simplePie, FreshRSS_Feed $feed): void - 'list' => [], - 'signature' => 'PassArguments', - ], - 'view_modes' => [ // function($viewModes = array) -> array | null - 'list' => [], - 'signature' => 'OneToOne', - ], - ]; + private static array $hook_list = []; /** Remove extensions and hooks from a previous initialisation */ private static function reset(): void { @@ -134,10 +29,12 @@ final class Minz_ExtensionManager { self::$ext_list = []; self::$ext_list_enabled = []; self::$ext_auto_enabled = []; - foreach (self::$hook_list as $hook_type => $hook_data) { - $hadAny |= !empty($hook_data['list']); - $hook_data['list'] = []; - self::$hook_list[$hook_type] = $hook_data; + foreach (Minz_HookType::cases() as $hook_type) { + $hadAny |= !empty(self::$hook_list[$hook_type->value]['list']); + self::$hook_list[$hook_type->value] = [ + 'list' => [], + 'signature' => $hook_type->signature(), + ]; } if ($hadAny) { gc_collect_cycles(); @@ -357,46 +254,62 @@ final class Minz_ExtensionManager { /** * Add a hook function to a given hook. * - * The hook name must be a valid one. For the valid list, see self::$hook_list - * array keys. + * The hook name must be a valid one. For the valid list, see Minz_HookType enum. * - * @param string $hook_name the hook name (must exist). + * @param string|Minz_HookType $hook the hook name (must exist). * @param callable $hook_function the function name to call (must be callable). */ - public static function addHook(string $hook_name, $hook_function): void { - if (isset(self::$hook_list[$hook_name]) && is_callable($hook_function)) { + public static function addHook(string|Minz_HookType $hook, $hook_function): void { + if (null === $hook = self::extractHook($hook)) { + return; + } + $hook_name = $hook->value; + + if (is_callable($hook_function)) { self::$hook_list[$hook_name]['list'][] = $hook_function; } } /** - * Call functions related to a given hook. - * - * The hook name must be a valid one. For the valid list, see self::$hook_list - * array keys. - * - * @param string $hook_name the hook to call. - * @param mixed ...$args additional parameters (for signature, please see self::$hook_list). - * @return mixed|void|null final result of the called hook. + * @param string|Minz_HookType $hook the hook or its name + * @return Minz_HookType|null */ - public static function callHook(string $hook_name, ...$args) { - if (!isset(self::$hook_list[$hook_name])) { - return; + private static function extractHook(string|Minz_HookType $hook) { + if ($hook instanceof Minz_HookType) { + return $hook; } + return Minz_HookType::tryFrom($hook); + } + + /** + * Call functions related to a given hook. + * + * The hook name must be a valid one. For the valid list, see Minz_HookType enum. + * + * @param string|Minz_HookType $hook the hook to call. + * @param mixed ...$args additional parameters (for signature, please see Minz_HookType enum). + * @return mixed|void|null final result of the called hook. + */ + public static function callHook(string|Minz_HookType $hook, ...$args) { + if (null === $hook = self::extractHook($hook)) { + return; + } + $hook_name = $hook->value; + $signature = self::$hook_list[$hook_name]['signature']; - if ($signature === 'OneToOne') { + if ($signature === Minz_HookSignature::OneToOne) { return self::callOneToOne($hook_name, $args[0] ?? null); - } elseif ($signature === 'PassArguments') { + } elseif ($signature === Minz_HookSignature::PassArguments) { foreach (self::$hook_list[$hook_name]['list'] as $function) { $result = call_user_func($function, ...$args); if ($result !== null) { return $result; } } - } elseif ($signature === 'NoneToString') { + } elseif ($signature === Minz_HookSignature::NoneToString) { return self::callHookString($hook_name); - } elseif ($signature === 'NoneToNone') { + } elseif ($signature === Minz_HookSignature::NoneToNone) { self::callHookVoid($hook_name); } return; @@ -411,12 +324,17 @@ final class Minz_ExtensionManager { * * If a hook return a null value, the method is stopped and return null. * - * @param string $hook_name is the hook to call. + * @param string|Minz_HookType $hook is the hook to call. * @param mixed $arg is the argument to pass to the first extension hook. * @return mixed|null final chained result of the hooks. If nothing is changed, * the initial argument is returned. */ - private static function callOneToOne(string $hook_name, mixed $arg): mixed { + private static function callOneToOne(string|Minz_HookType $hook, mixed $arg): mixed { + if (null === $hook = self::extractHook($hook)) { + return $arg; + } + $hook_name = $hook->value; + $result = $arg; foreach (self::$hook_list[$hook_name]['list'] as $function) { $result = call_user_func($function, $arg); @@ -436,10 +354,15 @@ final class Minz_ExtensionManager { * The result is concatenated between each hook and the final string is * returned. * - * @param string $hook_name is the hook to call. + * @param string|Minz_HookType $hook is the hook to call. * @return string concatenated result of the call to all the hooks. */ - public static function callHookString(string $hook_name): string { + public static function callHookString(string|Minz_HookType $hook): string { + if (null === $hook = self::extractHook($hook)) { + return ''; + } + $hook_name = $hook->value; + $result = ''; foreach (self::$hook_list[$hook_name]['list'] ?? [] as $function) { $return = call_user_func($function); @@ -456,9 +379,14 @@ final class Minz_ExtensionManager { * This case is simpler than callOneToOne because hooks are called one by * one, without any consideration of argument nor result. * - * @param string $hook_name is the hook to call. + * @param string|Minz_HookType $hook is the hook to call. */ - public static function callHookVoid(string $hook_name): void { + public static function callHookVoid(string|Minz_HookType $hook): void { + if (null === $hook = self::extractHook($hook)) { + return; + } + $hook_name = $hook->value; + foreach (self::$hook_list[$hook_name]['list'] ?? [] as $function) { call_user_func($function); } @@ -468,9 +396,14 @@ final class Minz_ExtensionManager { * Call a hook which takes no argument and returns nothing. * Same as callHookVoid but only calls the first extension. * - * @param string $hook_name is the hook to call. + * @param string|Minz_HookType $hook is the hook to call. */ - public static function callHookUnique(string $hook_name): bool { + public static function callHookUnique(string|Minz_HookType $hook): bool { + if (null === $hook = self::extractHook($hook)) { + throw new \RuntimeException("The “{$hook}” does not exist!"); + } + $hook_name = $hook->value; + foreach (self::$hook_list[$hook_name]['list'] ?? [] as $function) { call_user_func($function); return true; diff --git a/lib/Minz/HookSignature.php b/lib/Minz/HookSignature.php new file mode 100644 index 000000000..bfc7410d6 --- /dev/null +++ b/lib/Minz/HookSignature.php @@ -0,0 +1,9 @@ + string | null + case CustomFaviconBtnUrl = 'custom_favicon_btn_url'; // function(FreshRSS_Feed $feed): string | null + case CustomFaviconHash = 'custom_favicon_hash'; // function(FreshRSS_Feed $feed): string | null + case EntriesFavorite = 'entries_favorite'; // function(array $ids, bool $is_favorite): void + case EntryAutoRead = 'entry_auto_read'; // function(FreshRSS_Entry $entry, string $why): void + case EntryAutoUnread = 'entry_auto_unread'; // function(FreshRSS_Entry $entry, string $why): void + case EntryBeforeDisplay = 'entry_before_display'; // function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null + case EntryBeforeInsert = 'entry_before_insert'; // function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null + case EntryBeforeAdd = 'entry_before_add'; // function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null + case EntryBeforeUpdate = 'entry_before_update'; // function(FreshRSS_Entry $entry) -> FreshRSS_Entry | null + case FeedBeforeActualize = 'feed_before_actualize'; // function(FreshRSS_Feed $feed) -> FreshRSS_Feed | null + case FeedBeforeInsert = 'feed_before_insert'; // function(FreshRSS_Feed $feed) -> FreshRSS_Feed | null + case FreshrssInit = 'freshrss_init'; // function() -> none + case FreshrssUserMaintenance = 'freshrss_user_maintenance'; // function() -> none + case JsVars = 'js_vars'; // function($vars = array) -> array | null + case MenuAdminEntry = 'menu_admin_entry'; // function() -> string + case MenuConfigurationEntry = 'menu_configuration_entry'; // function() -> string + case MenuOtherEntry = 'menu_other_entry'; // function() -> string + case NavMenu = 'nav_menu'; // function() -> string + case NavReadingModes = 'nav_reading_modes'; // function($readingModes = array) -> array | null + case PostUpdate = 'post_update'; // function(none) -> none + case SimplepieAfterInit = 'simplepie_after_init'; // function(\SimplePie\SimplePie $simplePie, FreshRSS_Feed $feed, bool $result): void + case SimplepieBeforeInit = 'simplepie_before_init'; // function(\SimplePie\SimplePie $simplePie, FreshRSS_Feed $feed): void + case ViewModes = 'view_modes'; // function($viewModes = array) -> array | null + + public function signature(): Minz_HookSignature { + switch ($this) { + case Minz_HookType::ApiMisc: + case Minz_HookType::FreshrssInit: + case Minz_HookType::FreshrssUserMaintenance: + case Minz_HookType::PostUpdate: + return Minz_HookSignature::NoneToNone; + case Minz_HookType::BeforeLoginBtn: + case Minz_HookType::MenuAdminEntry: + case Minz_HookType::MenuConfigurationEntry: + case Minz_HookType::MenuOtherEntry: + case Minz_HookType::NavMenu: + return Minz_HookSignature::NoneToString; + case Minz_HookType::CheckUrlBeforeAdd: + case Minz_HookType::EntryBeforeDisplay: + case Minz_HookType::EntryBeforeInsert: + case Minz_HookType::EntryBeforeAdd: + case Minz_HookType::EntryBeforeUpdate: + case Minz_HookType::FeedBeforeActualize: + case Minz_HookType::FeedBeforeInsert: + case Minz_HookType::JsVars: + case Minz_HookType::NavReadingModes: + case Minz_HookType::ViewModes: + return Minz_HookSignature::OneToOne; + case Minz_HookType::CustomFaviconBtnUrl: + case Minz_HookType::CustomFaviconHash: + case Minz_HookType::EntriesFavorite: + case Minz_HookType::EntryAutoRead: + case Minz_HookType::EntryAutoUnread: + case Minz_HookType::SimplepieAfterInit: + case Minz_HookType::SimplepieBeforeInit: + return Minz_HookSignature::PassArguments; + default: + throw new \RuntimeException('The hook is not configured!'); + } + } +} diff --git a/p/api/fever.php b/p/api/fever.php index 420a17f64..76e3a4ac3 100644 --- a/p/api/fever.php +++ b/p/api/fever.php @@ -519,7 +519,7 @@ final class FeverAPI foreach ($entries as $item) { /** @var FreshRSS_Entry|null $entry */ - $entry = Minz_ExtensionManager::callHook('entry_before_display', $item); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeDisplay, $item); if ($entry === null) { continue; } diff --git a/p/api/greader.php b/p/api/greader.php index 6b67a7451..538292f58 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -570,7 +570,7 @@ final class GReaderAPI { $items = []; foreach ($entries as $item) { /** @var FreshRSS_Entry|null $entry */ - $entry = Minz_ExtensionManager::callHook('entry_before_display', $item); + $entry = Minz_ExtensionManager::callHook(Minz_HookType::EntryBeforeDisplay, $item); if ($entry === null) { continue; } diff --git a/p/api/misc.php b/p/api/misc.php index fe75b5be7..928c0b6e6 100644 --- a/p/api/misc.php +++ b/p/api/misc.php @@ -63,6 +63,6 @@ Minz_ExtensionManager::init(); Minz_Translate::init(); -if (!Minz_ExtensionManager::callHookUnique('api_misc')) { +if (!Minz_ExtensionManager::callHookUnique(Minz_HookType::ApiMisc)) { serviceUnavailable(); }