ModifyBiteJobPostingsEvent 

\FGTCLB\AcademicBiteJobs\Event\ModifyBiteJobPostingsEvent is owned by this extension. A listener removes, changes, adds or enriches the postings the job list renders.

When it is dispatched 

The Job List b-ite dispatches the event each time it renders, after the response of B-ITE is decoded and before Maximum number of job offers is applied. It is dispatched after a failed request as well, then with no postings and no response data, so a listener does not need to know how the request went. The request event comes before it.

What a listener reads and changes 

Method Returns
getJobPostings() , setJobPostings() The postings the job list renders, a list with one array per posting as B-ITE answers it. The setter refuses anything else.
getResponseData() The decoded response of the B-ITE API, or an empty array when the request failed or the response was not JSON.
getSettings() The values stored below settings.jobs in the plugin settings of the content element, as in the request event.
getRequest() The request of the page being rendered.
getPluginControllerActionContext() The context of the job list that asked, as in the request event.

The limit of the content element is applied to the postings the listeners hand back, so a listener sees every posting of the response and the job list never renders more than the limit.

Example: a grouping by a custom field 

The second half of the custom field example writes the name of the relation into every posting, so the job list can group by it:

EXT:my_extension/Classes/EventListener/NameTheRelationOfEveryJob.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\EventListener;

use FGTCLB\AcademicBiteJobs\Event\ModifyBiteJobPostingsEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;

final class NameTheRelationOfEveryJob
{
    private const RELATION_NAMES = [
        '01' => 'Appointment procedures',
        '02' => 'Academic staff',
        '03' => 'Non-scientific staff',
        '04' => 'Training positions',
    ];

    #[AsEventListener(identifier: 'my-extension/name-the-relation-of-every-job')]
    public function __invoke(ModifyBiteJobPostingsEvent $event): void
    {
        $jobs = $event->getJobPostings();
        foreach ($jobs as $index => $job) {
            $relation = (string)($job['custom']['zuordnung'] ?? '');
            $jobs[$index]['relationName'] = self::RELATION_NAMES[$relation] ?? '';
        }
        $event->setJobPostings($jobs);
    }
}
Copied!

The grouping itself is TypoScript, see Grouping the jobs:

TypoScript setup
plugin.tx_academicbitejobs.settings.jobs.groupBy = relationName
Copied!

Where the custom field sits in a posting, and which values it has, depends on how it is set up in B-ITE, so read one response of your job listing before relying on the path above. A listener that needs the labels of the values can ask the options API of B-ITE for them.

Rules and pitfalls 

Hand back a list. setJobPostings() throws an \InvalidArgumentException for an array that is not keyed from 0 without gaps, or for a posting that is not an array. A listener that removes postings with array_filter() passes the result through array_values() .

The templates read the keys B-ITE answers with. The views show the title, the url and the endsOn of a posting. A posting a listener adds needs them too, and a value a listener adds appears only where a template override or the grouping reads it.

The rules both events share are on the overview page.

Introduced in