ModifyProgramDemandEvent
\FGTCLB\ hands a
listener the demand a program list or a program finder is about to be queried
with. The demand a listener hands back is the one that is queried, and in the
list the one assigned to the view as
{demand}
.
When it is dispatched
Program dispatches the event once per rendering, in two
actions:
listof the Course List, after the demand is built from the settings of the content element and the selection of the visitor, and before the programs are queried.Action () finderof the Course Finder, after the demand is built from the settings of the content element, and before the programs the finder offers its categories for are queried. The finder has no selection of the visitor to read.Action ()
The list answers a submission of its filter and sorting form with a redirect to a URL carrying the selection, before the event. The event fires on the request that follows, with the selection in the query string (or the route), not in the parsed body, see Feature: Program filter selections have a URL. The finder submits to the list on its target page, so a finder submission reaches the event of that list, not the one of the finder.
ModifyProgramListEvent follows once the programs are queried.
What a listener reads and changes
| Method | What it does |
|---|---|
get | The demand,
\FGTCLB\.
It is an object, so a change to it takes effect without
set. |
set | Replaces the demand that is queried. |
get | The context of the rendering,
\FGTCLB\:
the request, the site and its language, the content object of the
element, the settings of the content element, the plugin name and
the action name. |
What the query reads from the demand:
| Getter and setter | Meaning |
|---|---|
get,
set | The uids of the pages the program pages sit directly below: the Startingpoint of the element with its Recursive levels already resolved. Empty means every program page of the installation. |
get,
set | The selected categories, those of the visitor or the
Default categories of the element, as a
\FGTCLB\, or
null
for none. A program has to carry every one of them. |
get,
set | Whether each selected category also finds the programs that carry one of its subcategories, the field Include subcategories of the element. |
get,
set, and the field and the
direction on their own | The ordering, one of the values of
\FGTCLB\, for
example title asc. |
get,
set | Whether hidden program pages are listed, the field Show hidden records of the element. |
The plugin name on the context is the name the plugin was registered with,
not the content element type:
Program for the list and
Program for the finder. It is how one listener serves both and
acts on one:
if ($event->getPluginControllerActionContext()->getPluginName() !== 'ProgramList') {
return;
}
Example
A site lists only full-time programs in its program lists, whatever else the
visitor selects. Full-time is the category with the uid 42 of the category
type program_. The listener adds it to the categories of the demand:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\EventListener;
use FGTCLB\AcademicPrograms\Event\ModifyProgramDemandEvent;
use FGTCLB\CategoryTypes\Collection\FilterCollection;
use FGTCLB\CategoryTypes\Domain\Repository\CategoryRepository;
use TYPO3\CMS\Core\Attribute\AsEventListener;
final readonly class ListOnlyFullTimePrograms
{
public function __construct(
private CategoryRepository $categoryRepository,
) {}
#[AsEventListener(identifier: 'my-extension/list-only-full-time-programs')]
public function __invoke(ModifyProgramDemandEvent $event): void
{
$demand = $event->getDemand();
// The categories the visitor selected, and the full-time category 42.
$uids = [42];
foreach ($demand->getFilterCollection()?->getFilterCategories() ?? [] as $category) {
$uids[] = $category->getUid();
}
$demand->setFilterCollection(new FilterCollection(
$this->categoryRepository->findByGroupAndUidList('programs', $uids),
));
}
}
The listener changes the demand it was handed rather than building a new one, so the storage, the sorting and the other choices of the editor and the visitor stay. It acts on the list and the finder alike: the finder then disables every category no full-time program carries.
Rules and pitfalls
Warning
A demand listener widens as easily as it narrows. The demand is the
query here, not a constraint added to one, and nothing guards it:
set shows hidden program pages to every
visitor,
set drops the storage restriction the editor
chose in the content element, and
set overrides the
editor's ordering for every element that renders, though only for a
value that is one of the
Sorting constants, since anything
else is ignored without a word. Two listeners that disagree are resolved by
the order they run in, and the last one wins.
What a listener cannot undo: the page type is pinned unconditionally,
show reaches the
disabled
flag alone (start- and
endtime,
fe_ and
deleted
stay in effect), and a
uid
tiebreaker is always appended to the ordering.
Subcategories are added when the programs are queried. With the field
Include subcategories of the element switched on, the demand holds
the categories as they were selected, and the query widens each of them by its
subcategories (see Matching subcategories). A category a listener
adds is widened the same way, and a listener that calls
set changes how every selected category matches.
A category a listener adds is shown as an active filter. The active filter
tags of Active filters, reset link and result count read the demand the list was
queried with, as the selects of the filter form do. A category a listener adds
to every request is therefore a tag the visitor cannot remove, since the
listener adds it again on the page the tag leads to, and every other tag link
carries it. A listener that forces a category should leave the tags switched
off, or override Partials/. A collection a
listener builds without the type identifiers of the group, through
new Category and
attach, still filters the list
but gets no tags, because the tags are grouped by type.
A replaced demand starts from the defaults.
set is there for
a listener that builds its own demand, and such a demand carries none of what
the plugin put in the one it was handed: the storage pages, the
show choice of the editor, the subcategory option, and the
two the visitor can set themselves through the filter form, the sorting and
the
filter. A replacement therefore resets the ordering and
the category filter under them. Mutate the demand where that is enough, and
carry
get,
get,
get,
get and the sorting
over where it is not.
A field the project adds to the filter form does not reach the event. The redirect after a submission carries the selection the plugin accepted and nothing else, so a listener cannot read a field of its own from the request that follows.
Introduced in
- Feature: Change the program list, finder and page by event added the event in 3.0.
- Breaking: The program controllers are final made the controllers final and names the event as the replacement of a subclass that changed the demand.
- Feature: Program filter selections have a URL answers a filter submission with a redirect, so the event fires on the request that follows it.