Das AfterBackendPageRenderEvent
greift leider erst nach dem Rendering der aktuellen View
.
Besonders deutlich wird das, wenn man sich den zugehörigen Code im BackendController
ansieht:
$view = $this->viewFactory->create($request);
$this->assignTopbarDetailsToView($request, $view);
$view->assignMultiple([
'modules' => $this->modules,
'modulesCollapsed' => $this->getCollapseStateOfMenu(),
'modulesInformation' => GeneralUtility::jsonEncodeForHtmlAttribute($this->getModulesInformation(), false),
'startupModule' => $this->getStartupModule($request),
'stateTracker' => (string)$this->uriBuilder->buildUriFromRoute('state-tracker'),
'sitename' => $title,
'sitenameFirstInBackendTitle' => ($backendUser->uc['backendTitleFormat'] ?? '') === 'sitenameFirst',
]);
$content = $view->render('Backend/Main');
$content = $this->eventDispatcher->dispatch(new AfterBackendPageRenderEvent($content, $view))->getContent();
$pageRenderer->addBodyContent('<body>' . $content);
return $pageRenderer->renderResponse();
Die Methode getStartupModule
kümmert sich um die Ermittlung des aktuellen Startmodules, welches an die View
weitergereicht wird. Darin enthalten ist auch die Berücksichtigung der startModuleOnFirstLogin
Konfiguration. Diese Option können wir uns also nicht zunutze machen.
Stattdessen können wir aber das Rendering der View
modifizieren. Das Event AfterBackendPageRenderEvent
bietet uns mit getView()
eine Methode, um die aktuelle View
zu erhalten. Dieser können wir nun einen eigenen Wert für startupModule
zuweisen, das Rendering der View
erneut durchführen und den resultierenden "Content" per setContent()
Methode des Events zurück schreiben lassen.
Das sieht dann in unserem Event Listener so aus:
<?php
declare(strict_types=1);
namespace VendorName\Sitepackage\EventListener;
use TYPO3\CMS\Backend\Controller\Event\AfterBackendPageRenderEvent;
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
use TYPO3\CMS\Backend\Routing\UriBuilder;
use VendorName\Sitepackage\Utility\PasswordExpirationUtility;
final class AfterBackendPageRender
{
/**
* @param UriBuilder $uriBuilder
*/
public function __construct(
protected readonly UriBuilder $uriBuilder,
)
{
}
/**
* @param AfterBackendPageRenderEvent $event
* @return void
*/
public function __invoke(AfterBackendPageRenderEvent $event): void
{
if ($GLOBALS['BE_USER'] && PasswordExpirationUtility::isBeUserPasswordExpired()) {
try {
// Prepare the startup module overwrite configuration
$deepLink = $this->uriBuilder->buildUriFromRoute('user_setup');
$startModule = ['user_setup', (string)$deepLink];
// Override startup module in current view
$view = $event->getView();
$view->assign('startupModule', $startModule);
// Re-render view to set the new content
$event->setContent(
$view->render('Backend/Main')
);
} catch (RouteNotFoundException) {
// It might be, that the user does not have access to the
// $startModule, e.g. for modules with workspace restrictions.
}
}
}
}
In der Datei EXT:sitepackage/Configuration/Services.yaml
wurde der Event Listener wie folgt registriert:
VendorName\Sitepackage\EventListener\AfterBackendPageRender:
tags:
- name: event.listener
identifier: 'sitepackage/backend/after-backend-controller-render'