Breaking: The program controllers are final
Description
Both controllers of this extension are
final
:
\FGTCLB\serves the program list (Academic Programs\ Controller\ Program Controller Program) and the program finder (List Program).Finder \FGTCLB\serves the program details (Academic Programs\ Controller\ Details Controller Program).Details
Their collaborators are private constructor arguments now. The methods
inject,
inject and
inject are
removed, and
redirect and
plugin of the program controller are private.
All of them existed only so that a subclass could keep calling the old
constructor and the helpers of the shipped actions. The details controller no
longer takes the demand factory, which it never used.
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 one of the two controllers stops loading with a fatal
error,
Class ... cannot extend final class
FGTCLB\ for instance. 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 either 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 three 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
Program or
Details, 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 selection of the program list or the finder before the query:
a listener of
\FGTCLB\. See Feature: Change the program list, finder and page by event.Academic Programs\ Event\ Modify Program Demand Event - Replacing or reordering the programs, changing the offered filter
categories, or additional view variables of the list and the finder: a
listener of
\FGTCLB\.Academic Programs\ Event\ Modify Program List Event - A finder action of the project next to the list: the program finder of this extension, see Feature: A program finder content element and Breaking: The content type academicprograms_programfinder is taken.
- Filter selections that can be bookmarked: the list answers a filter submission with a redirect to a GET URL, see Feature: Program filter selections have a URL.
- Changing the program or adding view variables of the program details: a
listener of the plugin view event of academic_base, see
Feature: The plugins dispatch the plugin view event.
Modifychanges the data of the program page, which a data processor renders, not this plugin.Program Data Event
A subclass that adds a view variable to the details:
final class DetailsController extends \FGTCLB\AcademicPrograms\Controller\DetailsController
{
public function showAction(): ResponseInterface
{
$this->view->assign('applicationPeriods', $this->applicationPeriodRepository->findAll());
return parent::showAction();
}
}
does the same as a listener:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\EventListener;
use FGTCLB\AcademicBase\Event\ModifyPluginViewEvent;
use MyVendor\MyExtension\Domain\Repository\ApplicationPeriodRepository;
use TYPO3\CMS\Core\Attribute\AsEventListener;
final readonly class AddApplicationPeriodsToProgramDetails
{
public function __construct(
private ApplicationPeriodRepository $applicationPeriodRepository,
) {}
#[AsEventListener(identifier: 'my-extension/add-application-periods-to-program-details')]
public function __invoke(ModifyPluginViewEvent $event): void
{
$context = $event->getPluginControllerActionContext();
if ($context->getControllerExtensionName() !== 'AcademicPrograms'
|| $context->getPluginName() !== 'ProgramDetails'
) {
return;
}
$event->getView()->assign('applicationPeriods', $this->applicationPeriodRepository->findAll());
}
}
The plugin view event is dispatched by every plugin of the academic extensions, so the listener checks for the one it means.