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'