From e56e42e7e7ffd812c9bb61299e8ca28474872089 Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Wed, 17 Dec 2025 11:15:38 +0100 Subject: [PATCH] refactor(navigation-manager): Cleanup implementation and add type hinting Signed-off-by: Carl Schwan --- lib/private/NavigationManager.php | 49 ++++++++++++++++--------------- lib/public/INavigationManager.php | 49 +++++++++++++++++++++++-------- 2 files changed, 61 insertions(+), 37 deletions(-) diff --git a/lib/private/NavigationManager.php b/lib/private/NavigationManager.php index eb88c5d7d65..6b622bbb3ea 100644 --- a/lib/private/NavigationManager.php +++ b/lib/private/NavigationManager.php @@ -19,16 +19,20 @@ use OCP\IUser; use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\Navigation\Events\LoadAdditionalEntriesEvent; +use Override; use Psr\Log\LoggerInterface; /** * Manages the Nextcloud navigation + * @psalm-import-type NavigationEntry from INavigationManager + * @psalm-import-type NavigationEntryOutput from INavigationManager */ class NavigationManager implements INavigationManager { + /** @var array */ protected array $entries = []; + /** @var list */ protected array $closureEntries = []; - /** @var string $activeEntry */ - protected $activeEntry; + protected ?string $activeEntry = null; protected array $unreadCounters = []; protected bool $init = false; /** User defined app order (cached for the `add` function) */ @@ -46,10 +50,8 @@ class NavigationManager implements INavigationManager { ) { } - /** - * @inheritDoc - */ - public function add($entry) { + #[Override] + public function add(array|callable $entry): void { if ($entry instanceof \Closure) { $this->closureEntries[] = $entry; return; @@ -86,7 +88,7 @@ class NavigationManager implements INavigationManager { $this->updateDefaultEntries(); } - private function updateDefaultEntries() { + private function updateDefaultEntries(): void { $defaultEntryId = $this->getDefaultEntryIdForUser($this->userSession->getUser(), false); foreach ($this->entries as $id => $entry) { if ($entry['type'] === 'link') { @@ -95,9 +97,7 @@ class NavigationManager implements INavigationManager { } } - /** - * @inheritDoc - */ + #[Override] public function getAll(string $type = 'link'): array { $this->init(); @@ -114,8 +114,8 @@ class NavigationManager implements INavigationManager { /** * Sort navigation entries default app is always sorted first, then by order, name and set active flag * - * @param array $list - * @return array + * @param array $list + * @return array */ private function proceedNavigation(array $list, string $type): array { uasort($list, function ($a, $b) { @@ -136,7 +136,7 @@ class NavigationManager implements INavigationManager { if ($type === 'all' || $type === 'link') { // There might be the case that no default app was set, in this case the first app is the default app. - // Otherwise the default app is already the ordered first, so setting the default prop will make no difference. + // Otherwise, the default app is already the ordered first, so setting the default prop will make no difference. foreach ($list as $index => &$navEntry) { if ($navEntry['type'] === 'link') { $navEntry['default'] = true; @@ -165,23 +165,19 @@ class NavigationManager implements INavigationManager { /** * removes all the entries */ - public function clear($loadDefaultLinks = true) { + public function clear(bool $loadDefaultLinks = true): void { $this->entries = []; $this->closureEntries = []; $this->init = !$loadDefaultLinks; } - /** - * @inheritDoc - */ - public function setActiveEntry($appId) { + #[Override] + public function setActiveEntry(string $appId): void { $this->activeEntry = $appId; } - /** - * @inheritDoc - */ - public function getActiveEntry() { + #[Override] + public function getActiveEntry(): ?string { return $this->activeEntry; } @@ -377,7 +373,7 @@ class NavigationManager implements INavigationManager { } } - private function isAdmin() { + private function isAdmin(): bool { $user = $this->userSession->getUser(); if ($user !== null) { return $this->groupManager->isAdmin($user->getUID()); @@ -385,7 +381,7 @@ class NavigationManager implements INavigationManager { return false; } - private function isSubadmin() { + private function isSubadmin(): bool { $user = $this->userSession->getUser(); if ($user !== null && $this->groupManager instanceof Manager) { return $this->groupManager->getSubAdmin()->isSubAdmin($user); @@ -393,15 +389,18 @@ class NavigationManager implements INavigationManager { return false; } + #[Override] public function setUnreadCounter(string $id, int $unreadCounter): void { $this->unreadCounters[$id] = $unreadCounter; } + #[Override] public function get(string $id): ?array { $this->init(); return $this->entries[$id]; } + #[Override] public function getDefaultEntryIdForUser(?IUser $user = null, bool $withFallbacks = true): string { $this->init(); // Disable fallbacks here, as we need to override them with the user defaults if none are configured. @@ -443,6 +442,7 @@ class NavigationManager implements INavigationManager { return $withFallbacks ? 'files' : ''; } + #[Override] public function getDefaultEntryIds(bool $withFallbacks = true): array { $this->init(); $storedIds = explode(',', $this->config->getSystemValueString('defaultapp', $withFallbacks ? 'dashboard,files' : '')); @@ -456,6 +456,7 @@ class NavigationManager implements INavigationManager { return array_filter($ids); } + #[Override] public function setDefaultEntryIds(array $ids): void { $this->init(); $entryIds = array_keys($this->entries); diff --git a/lib/public/INavigationManager.php b/lib/public/INavigationManager.php index 2bd70c04d65..005c35282f4 100644 --- a/lib/public/INavigationManager.php +++ b/lib/public/INavigationManager.php @@ -10,12 +10,31 @@ namespace OCP; +use OCP\AppFramework\Attribute\Consumable; +use OCP\AppFramework\Attribute\ExceptionalImplementable; + /** - * Manages the ownCloud navigation + * Manages the Nextcloud navigation + * * @since 6.0.0 * * @psalm-type NavigationEntry = array{id: string, order: int, href: string, name: string, app?: string, icon?: string, classes?: string, type?: string} + * @psalm-type NavigationEntryOutput = array{ + * id: string, + * order?: int, + * href: string, + * icon: string, + * type: string, + * name: string, + * app?: string, + * default?: bool, + * active: bool, + * classes: string, + * unread: int, + * } */ +#[Consumable(since: '6.0.0')] +#[ExceptionalImplementable(app: 'guest')] interface INavigationManager { /** * Navigation entries of the app navigation @@ -35,18 +54,22 @@ interface INavigationManager { */ public const TYPE_GUEST = 'guest'; + /** + * All navigation entries + * @since 33.0.0 + */ + public const TYPE_ALL = 'all'; + /** * Creates a new navigation entry * - * @param array array|\Closure $entry Array containing: id, name, order, icon and href key - * If a menu entry (type = 'link') is added, you shall also set app to the app that added the entry. - * The use of a closure is preferred, because it will avoid - * loading the routing of your app, unless required. - * @psalm-param NavigationEntry|callable():NavigationEntry $entry + * @param NavigationEntry|callable():NavigationEntry $entry If a menu entry (type = 'link') is added, you shall also set app to the app that + * added the entry. The use of a closure is preferred, because it will avoid loading + * the routing of your app, unless required. * @return void * @since 6.0.0 */ - public function add($entry); + public function add(array|callable $entry): void; /** * Sets the current navigation entry of the currently running app @@ -54,20 +77,20 @@ interface INavigationManager { * @return void * @since 6.0.0 */ - public function setActiveEntry($appId); + public function setActiveEntry(string $appId): void; /** * Get the current navigation entry of the currently running app - * @return string + * @return ?string * @since 20.0.0 */ - public function getActiveEntry(); + public function getActiveEntry(): ?string; /** * Get a list of navigation entries * - * @param string $type type of the navigation entries - * @return array + * @param self::TYPE_APPS|self::TYPE_SETTINGS|self::TYPE_GUEST|self::TYPE_ALL $type type of the navigation entries + * @return array * @since 14.0.0 */ public function getAll(string $type = self::TYPE_APPS): array; @@ -92,7 +115,7 @@ interface INavigationManager { /** * Returns the id of the user's default entry * - * If `user` is not passed, the currently logged in user will be used + * If `user` is not passed, the currently logged-in user will be used * * @param ?IUser $user User to query default entry for * @param bool $withFallbacks Include fallback values if no default entry was configured manually