Breaking: The project controller is final
Description
\FGTCLB\ is
final
.
It serves both project list plugins, Project and Project.
Its collaborators are private constructor arguments now. The methods
inject and
inject are removed, and
redirect and
plugin
are private. All of them existed only so that a subclass could keep calling the
old constructor and the helpers of the shipped action.
Every plugin controller of the academic extensions is final in 3.0. A plugin is extended through its events, not through a subclass of its controller.
Impact
A class that extends
Project stops loading with a fatal
error,
Class ... cannot extend final class
FGTCLB\. That happens as soon as
anything loads the subclass, a plugin registered with it renders, or the
container is built with it.
An XCLASS of the controller fails the same way. The upgrade check
academic: of EXT:academic_base reports it as
an error. A
configure call that points one of the two plugins
at a subclass is not reported.
The plugins, their templates and their settings are unchanged. The behaviour is the same on TYPO3 v13 and v14.
Affected Installations
Installations with a class that extends
Project, registered
for a plugin through
Extension, as an XCLASS,
or in the service container.
Migration
Remove the subclass, and the
configure call or the XCLASS
registration that points at it, so the shipped controller serves the plugin
again. Move each override to its replacement:
- Changing the filter, the status or the sorting before the query: a
listener of
\FGTCLB\, which adjusts or replaces the demand. See Feature: Change the project lists by event.Academic Projects\ Event\ Modify Project Demand Event - A replaced or reduced result, other filter categories, or additional view
variables: a listener of
\FGTCLB\.Academic Projects\ Event\ Modify Project List Event - Filter selections that can be bookmarked: the list answers a filter submission with a redirect to a GET URL, see Feature: Project filter selections have a URL.
A subclass that adds a view variable:
final class ProjectController extends \FGTCLB\AcademicProjects\Controller\ProjectController
{
public function listAction(?array $demand = null): ResponseInterface
{
$this->view->assign('fundingBodies', $this->fundingBodyRepository->findAll());
return parent::listAction($demand);
}
}
does the same as a listener:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\EventListener;
use FGTCLB\AcademicProjects\Event\ModifyProjectListEvent;
use MyVendor\MyExtension\Domain\Repository\FundingBodyRepository;
use TYPO3\CMS\Core\Attribute\AsEventListener;
final readonly class AddFundingBodiesToProjectList
{
public function __construct(
private FundingBodyRepository $fundingBodyRepository,
) {}
#[AsEventListener(identifier: 'my-extension/add-funding-bodies-to-project-list')]
public function __invoke(ModifyProjectListEvent $event): void
{
$event->getView()->assign('fundingBodies', $this->fundingBodyRepository->findAll());
}
}
The listener acts on both plugins. It reads
$event->get where it
means only one of them.