---
title: "ModifyPartnerDemandEvent"
manual: "Academic Partners"
version: "main"
permalink: "https://docs.typo3.org/permalink/fgtclb/academic-partners:developers-event-modify-partner-demand-event@main"
source: "Developers/Events/ModifyPartnerDemandEvent.rst"
rendered: "2026-10-26T19:20:19+00:00"
---

# ModifyPartnerDemandEvent {#developers-event-modify-partner-demand-event}

`\FGTCLB\AcademicPartners\Event\ModifyPartnerDemandEvent` hands a listener
the demand of the **Partner List** and the **Partner Map**
before the partners are queried. The demand is the query: what a listener sets
on it decides which partners are listed or drawn, and in which order.

## When it is dispatched {#when-it-is-dispatched}

In `PartnerController::listAction()` and
`PartnerController::mapAction()`, on every request that renders one of the
two content elements, after the demand is built and before the partners are
queried. The demand then holds:

-   the storage pages of [Startingpoint](https://docs.typo3.org/permalink/fgtclb/academic-partners:confval-partner-list-pages@main),
-   the choice of
    [Show hidden records](https://docs.typo3.org/permalink/fgtclb/academic-partners:confval-partner-list-show-hidden-records@main),
-   the sorting and the categories the visitor selected, or, on a request
    without a selection of the visitor, those of
    [Default sorting](https://docs.typo3.org/permalink/fgtclb/academic-partners:confval-partner-list-sorting@main) and
    [Default categories](https://docs.typo3.org/permalink/fgtclb/academic-partners:confval-partner-list-categories@main),
-   and in the list, the page the visitor asked for.

The list reads the page and the arguments its page links carry before this
event. The map restricts the demand to the partners it can draw after this
event. Neither content element dispatches the event for the POST of the filter
form, which is answered with a redirect first, and the partnership content
elements do not dispatch it at all.

## What a listener reads and changes {#what-a-listener-reads-and-changes}

| Method | Returns or does |
| --- | --- |
| `getDemand()` | The `\FGTCLB\AcademicPartners\Domain\Model\Dto\PartnerDemand` the plugin built. A listener changes it in place. |
| `setDemand()` | Replaces the demand. The demand a listener hands back is the one that is queried and assigned to the view as `{demand}`. |
| `getPluginControllerActionContext()` | The request, the site and its language, the content object, the settings of the content element, and the plugin name, `List` or `Map`. |

The demand offers:

| Methods | Meaning |
| --- | --- |
| `getPages()`, `setPages()` | The uids of the pages the partner pages sit on, compared with their `pid`. An empty list means every partner page of the installation. |
| `getFilterCollection()`, `setFilterCollection()` | The categories a partner has to carry, all of them, as a `\FGTCLB\CategoryTypes\Collection\FilterCollection`, or `null` for no category filter. |
| `getShowHiddenRecords()`, `setShowHiddenRecords()` | Whether hidden partner pages are included. |
| `getSorting()`, `setSorting()`, and the field and direction on their own through `getSortingField()`, `setSortingField()`, `getSortingDirection()` and `setSortingDirection()` | The order, one of the values of `\FGTCLB\AcademicPartners\Enumeration\SortingOptions`, for example `title asc`. A value that is none of them is ignored without a word. |
| `getCurrentPage()` | The page of a paginated list. It is read before the event, so setting it has no effect. |

## Example {#example}

A site does not want hidden partners on its maps, whatever an editor switches on
in a content element. The partner list may still show them. A listener switches
`showHiddenRecords` off for the map:

**EXT:my_extension/Classes/EventListener/KeepHiddenPartnersOffTheMap.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\EventListener;

use FGTCLB\AcademicPartners\Event\ModifyPartnerDemandEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;

final class KeepHiddenPartnersOffTheMap
{
    #[AsEventListener(identifier: 'my-extension/keep-hidden-partners-off-the-map')]
    public function __invoke(ModifyPartnerDemandEvent $event): void
    {
        // The plugin name the map is registered with, not the CType.
        if ($event->getPluginControllerActionContext()->getPluginName() !== 'Map') {
            return;
        }
        $event->getDemand()->setShowHiddenRecords(false);
    }
}
```

A listener that restricts the partners to one storage folder instead sets the
pages. `setPages()` becomes `pid IN (...)`, so this is one folder and
not a page tree:

```php
$event->getDemand()->setPages([42]);
```

## Rules and pitfalls {#developers-partner-events-rules}

> [!WARNING]
> **The map still leaves out partners without coordinates.** A partner
> without a coordinate would be drawn at 0/0 rather than be left out, so
> `mapAction()` restricts the demand to drawable partners *after* the
> demand event, together with the switch **Show on map**. A listener
> that hands back a fresh demand, with the restriction off again, therefore
> does not bring them onto the map. This is deliberate and is covered by a
> test.
>
> It is not the only thing a listener cannot undo. The page type is pinned
> unconditionally, `showHiddenRecords` reaches the `disabled` flag
> alone (start and end time, `fe_group` and `deleted` stay in
> effect), and a `uid` tiebreaker is always appended to the ordering.
> Everything else is open: the demand *is* the query here, not a constraint
> added to one, so a listener widens as easily as it narrows and nothing
> guards it. `setShowHiddenRecords(true)` shows hidden partner pages to
> every visitor, `setPages([])` drops the storage restriction the editor
> chose in the content element, and `setSorting()` overrides the
> editor's ordering for every element that renders, though only for a value
> that is one of the `SortingOptions` constants, since anything else is
> ignored without a word. Two listeners that disagree are resolved by the
> order they run in, the last one wins.

**A replaced demand starts from the defaults.** `setDemand()` 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 and the
`showHiddenRecords` choice of the editor, and the two the visitor can set
themselves through the filter form, the `sorting` and the
`filterCollection`. A replacement therefore resets the ordering and the
category filter under them. Mutate the demand where that is enough, and carry
`getPages()`, `getShowHiddenRecords()`, `getFilterCollection()`
and `getSorting()` over where it is not.

**The page is not the listener's.** The page, and the filter and sorting the
page links carry, are read from the demand the request asked for, **before** the
demand event, as the filter redirect reads its URL. A listener that replaces the
demand therefore keeps the page the visitor asked for, and a listener cannot
choose the page. What a listener changes does not travel in the page links: it
acts again on the request a link leads to.

**The form shows what the listener set.** The demand a listener hands back is
the one assigned to the view, so the filter form shows its categories as
selected and its sorting as chosen, and the active filter tags list its
categories.

## Introduced in {#introduced-in}

-   [Feature: Change the partner list and map by event](https://docs.typo3.org/permalink/fgtclb/academic-partners:feature-list-plugin-events@main) introduced the event.
-   [Breaking: The partner controller is final](https://docs.typo3.org/permalink/fgtclb/academic-partners:breaking-1791043406@main) made the controller final, the event replaces a
    subclass that changed the filter or the sorting.
-   [Feature: Partner filter selections have a URL](https://docs.typo3.org/permalink/fgtclb/academic-partners:feature-1790226100@main) moved the filter submission to a redirect, which
    is why the event never sees the POST of the form.
