diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Minz/ExtensionManager.php | 201 | ||||
| -rw-r--r-- | lib/Minz/HookSignature.php | 9 | ||||
| -rw-r--r-- | lib/Minz/HookType.php | 68 |
3 files changed, 144 insertions, 134 deletions
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<string,array{'list':array<callable>,'signature':'NoneToNone'|'NoneToString'|'OneToOne'|'PassArguments'}> + * @var array<value-of<Minz_HookType>,array{'list':list<callable>,'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; } } /** + * @param string|Minz_HookType $hook the hook or its name + * @return Minz_HookType|null + */ + 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 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 to call. - * @param mixed ...$args additional parameters (for signature, please see self::$hook_list). + * @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 $hook_name, ...$args) { - if (!isset(self::$hook_list[$hook_name])) { + 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 @@ +<?php +declare(strict_types=1); + +enum Minz_HookSignature { + case NoneToNone; + case NoneToString; + case OneToOne; + case PassArguments; +} diff --git a/lib/Minz/HookType.php b/lib/Minz/HookType.php new file mode 100644 index 000000000..0a9a311eb --- /dev/null +++ b/lib/Minz/HookType.php @@ -0,0 +1,68 @@ +<?php +declare(strict_types=1); + +enum Minz_HookType: string { + case ApiMisc = 'api_misc'; // function(): void + case BeforeLoginBtn = 'before_login_btn'; // function(): string + case CheckUrlBeforeAdd = 'check_url_before_add'; // function(string $url) -> 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!'); + } + } +} |
