146 lines
5.0 KiB
PHP
146 lines
5.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/*
|
|
* This file is part of the TYPO3 CMS project.
|
|
*
|
|
* It is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, either version 2
|
|
* of the License, or any later version.
|
|
*
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE.txt file that was distributed with this source code.
|
|
*
|
|
* The TYPO3 project - inspiring people to share!
|
|
*/
|
|
|
|
namespace TYPO3\CMS\Backend\Breadcrumb;
|
|
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use TYPO3\CMS\Backend\Dto\Breadcrumb\BreadcrumbNode;
|
|
use TYPO3\CMS\Backend\Module\ModuleInterface;
|
|
use TYPO3\CMS\Backend\Module\ModuleResolver;
|
|
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
|
use TYPO3\CMS\Core\Localization\LanguageService;
|
|
use TYPO3\CMS\Core\Resource\StorageRepository;
|
|
|
|
/**
|
|
* Breadcrumb provider for null contexts (virtual pages, empty states).
|
|
*
|
|
* Provides fallback breadcrumbs when no record or resource context is available,
|
|
* such as virtual pages (e.g., id=0) or file storage roots.
|
|
*
|
|
* @internal This class is not part of TYPO3's public API.
|
|
*/
|
|
final readonly class NullContextBreadcrumbProvider implements BreadcrumbProviderInterface
|
|
{
|
|
public function __construct(
|
|
private ModuleResolver $moduleResolver,
|
|
private StorageRepository $storageRepository,
|
|
private UriBuilder $uriBuilder,
|
|
) {}
|
|
|
|
public function supports(?BreadcrumbContext $context): bool
|
|
{
|
|
// This provider handles null contexts
|
|
return $context === null || !$context->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'];
|
|
}
|
|
}
|