hasContext(); } public function generate(?BreadcrumbContext $context, ?ServerRequestInterface $request): array { $breadcrumb = []; $currentModule = $this->moduleResolver->resolveModule($request); if ($currentModule !== null) { // Add parent modules first (for third-level modules) $breadcrumb = $this->buildModuleHierarchy($currentModule); } // Handle file storage tree if ($currentModule?->getNavigationComponent() === '@typo3/backend/tree/file-storage-tree-container') { $id = $request?->getQueryParams()['id'] ?? null; $label = $this->getLanguageService()->sL($currentModule->getTitle()); $icon = 'apps-filetree-folder'; if ($id !== null && $storage = $this->storageRepository->findByCombinedIdentifier($id)) { $label = $storage->getName(); if (!$storage->isOnline() || !$storage->isBrowsable()) { $icon = 'apps-filetree-folder-locked'; } } $breadcrumb[] = new BreadcrumbNode( identifier: (string)$id, label: $label, icon: $icon, ); } // Handle page tree (default for null context or no module) if ($currentModule === null || $currentModule->getNavigationComponent() === '@typo3/backend/tree/page-tree-element') { $breadcrumb[] = new BreadcrumbNode( identifier: '0', label: (string)$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'], icon: 'apps-pagetree-root', ); } return $breadcrumb; } public function getPriority(): int { // Low priority - only handles null contexts as fallback return 0; } /** * Builds the module hierarchy including parent modules. * * For third-level modules, this returns [parent, current]. * For second-level modules, this returns [current]. * For standalone modules, this returns [current]. * * @return BreadcrumbNode[] */ private function buildModuleHierarchy(ModuleInterface $currentModule): array { $modules = []; $moduleChain = []; // Build chain from current to root $module = $currentModule; while ($module !== null) { $moduleChain[] = $module; $module = $module->getParentModule(); } // Reverse to get root-to-current order and skip the top-level parent (main menu item) $moduleChain = array_reverse($moduleChain); // Skip the first item if we have more than one (first is the main menu container like "web") if (count($moduleChain) > 1) { array_shift($moduleChain); } // Build breadcrumb nodes for each module in the chain foreach ($moduleChain as $module) { $modules[] = new BreadcrumbNode( identifier: $module->getIdentifier(), label: $this->getLanguageService()->sL($module->getTitle()), icon: $module->getIconIdentifier(), url: (string)$this->uriBuilder->buildUriFromRoute($module->getIdentifier(), $module->getNavigationComponent() === '@typo3/backend/tree/page-tree-element' ? ['id' => '0'] : []), forceShowIcon: true, ); } return $modules; } private function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } }