Breaking: The B-ITE jobs controller is final
Description
\FGTCLB\ is
final
. It serves the job list plugin List. Its job service is a
private constructor argument now.
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
Bite 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 the plugin at a subclass
is not reported.
The plugin, its templates and its settings are unchanged. The behaviour is the same on TYPO3 v13 and v14.
Affected Installations
Installations with a class that extends
Bite, registered
for the 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, see Feature: Request and result events for the B-ITE job list:
- Changing the request to B-ITE, its filter, channel, locale, sorting or
paging: a listener of
\FGTCLB\.Academic Bite Jobs\ Event\ Modify Bite Job Postings Request Event - Removing, enriching or grouping the postings: a listener of
\FGTCLB\.Academic Bite Jobs\ Event\ Modify Bite Job Postings Event - Additional view variables: a listener of the plugin view event of academic_base, see Feature: The plugin dispatches the plugin view event.
A subclass that drops postings:
final class BiteJobsController extends \FGTCLB\AcademicBiteJobs\Controller\BiteJobsController
{
public function listAction(): ResponseInterface
{
$jobs = $this->biteJobsService->fetchBiteJobs($this->request);
$this->view->assign('jobs', array_filter($jobs, $this->isPublished(...)));
return $this->htmlResponse();
}
}
does the same as a listener, with one difference: the listener runs before the limit of the content element is applied, so the list still shows as many postings as the limit allows:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\EventListener;
use FGTCLB\AcademicBiteJobs\Event\ModifyBiteJobPostingsEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;
final class SkipUnpublishedPostings
{
#[AsEventListener(identifier: 'my-extension/skip-unpublished-postings')]
public function __invoke(ModifyBiteJobPostingsEvent $event): void
{
$event->setJobPostings(array_values(array_filter(
$event->getJobPostings(),
static fn(array $posting): bool => ($posting['published'] ?? true) !== false,
)));
}
}