---
title: "ModifyProfileImageMetadataEvent"
manual: "Academic Profiles"
version: "main"
permalink: "https://docs.typo3.org/permalink/fgtclb/academic-persons:developers-image-metadata@main"
source: "Developers/Events/ModifyProfileImageMetadataEvent.rst"
rendered: "2026-10-15T10:24:29+00:00"
---

# ModifyProfileImageMetadataEvent {#developers-image-metadata}

`\FGTCLB\AcademicPersons\Event\ModifyProfileImageMetadataEvent` is
dispatched immediately before this extension writes the metadata of a profile
image, and a listener decides what is written: whatever it leaves in
`getMetadata()` is the field map that goes to the database, and an empty
map writes nothing at all.

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

It is dispatched for each of the two records that carry image metadata, and
`getTargetTable()` says which one:

| `getTargetTable()` | Written when | Fields |
| --- | --- | --- |
| `sys_file_metadata` | a profile image is uploaded in the frontend, once, for the file that upload created, and only for the fields that record has empty | `title`, `alternative` and, with [`typo3/cms-filemetadata`](https://packagist.org/packages/typo3/cms-filemetadata), `copyright` |
| `sys_file_reference` | a DataHandler save writes the name or the image of a profile record: a backend save, a localization, an import or the translation synchronisation. And after every profile update the frontend editing or the frontend user commands announce, whatever changed | `title` and `alternative` |

The upload of the frontend editing of
[`fgtclb/academic-persons-edit`](https://packagist.org/packages/fgtclb/academic-persons-edit) dispatches the event for the file
first and then for the reference. A profile without an image gets no event,
and the upload for a profile without a name gets none for the file. The
default values are the composed name of the profile record: title, first,
middle and last name.

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

| Method | What it does |
| --- | --- |
| `getTargetTable()` | `sys_file_metadata` or `sys_file_reference`, the record that is written. |
| `getMetadata()`, `setMetadata()` | The fields that are written, column name to value. |
| `getFile()` | The file the image is stored in. |
| `getFileReference()` | The image relation of the profile. |
| `getProfileUid()` | The uid of the profile record the image belongs to. |
| `getRequest()` | The request the write happens in, or `null`. |

**Both records are handed over, whichever of them is written.**
`getFile()` is the file, whose own metadata record is
`$event->getFile()->getMetaData()`, and `getFileReference()` is the
image relation of the profile, `null` only for a profile that has none.
`getProfileUid()` is the profile record the image belongs to, a
translation for an image of its own, and `getRequest()` the request the
write happens in: the frontend request for an upload or a frontend edit, the
backend request for a save, and `null` on the command line or where the
caller has no request to pass on.

Fields the target table does not declare are dropped before the write, so a
listener may set a column unconditionally: where the installation does not have
it, the value goes nowhere. `copyright` is one such column. It belongs to
`sys_file_metadata` and [`typo3/cms-filemetadata`](https://packagist.org/packages/typo3/cms-filemetadata), and the
relation row has no equivalent.

## Example {#example}

An installation that requires a note on the right of use for every image, with
[`fgtclb/file-required-attributes`](https://packagist.org/packages/fgtclb/file-required-attributes), fills it when a profile image is
uploaded:

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

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\EventListener;

use FGTCLB\AcademicPersons\Event\ModifyProfileImageMetadataEvent;
use TYPO3\CMS\Core\Attribute\AsEventListener;

final class AddImageRightOfUse
{
    #[AsEventListener(identifier: 'my-extension/add-image-right-of-use')]
    public function __invoke(ModifyProfileImageMetadataEvent $event): void
    {
        if ($event->getTargetTable() !== 'sys_file_metadata') {
            return;
        }
        $metadata = $event->getMetadata();
        $metadata['right_of_use'] = 'Portrait, own use only';
        $event->setMetadata($metadata);
    }
}
```

## Rules and pitfalls {#rules-and-pitfalls}

> [!WARNING]
> **System fields are refused.** The identity of the record, the relation it
> is part of, its localization, its workspace columns and its enable columns
> are dropped and a warning is written to the log: `uid`, `pid`,
> `file`, `uid_local`, `uid_foreign`, `tablenames`,
> `fieldname`, `sys_language_uid`, `l10n_parent`,
> `t3ver_*`, `deleted`, `hidden` and the rest of their kind. This
> event writes metadata. Repointing a relation or moving a record is the
> `DataHandler`'s business.

The two dispatches are not interchangeable. The metadata record of the file is
written **once**, which makes it the place for a value that has to survive,
the required attributes of [`typo3/cms-filemetadata`](https://packagist.org/packages/typo3/cms-filemetadata) or
[`fgtclb/file-required-attributes`](https://packagist.org/packages/fgtclb/file-required-attributes), for instance. The reference row is
rewritten on **every** save of the profile, so a listener that wants to own a
field there has to set it on every dispatch. One request may write the
reference more than once, an upload in the default language does, so a
listener sets the same value each time it is called.

> [!WARNING]
> A listener runs inside the write of the profile record, for a backend save
> from within a `DataHandler` hook. Keep it short and do not write
> profile records from it.

When the file or the relation cannot be loaded, the metadata is written without
the event, and a warning is logged.

## Introduced in {#introduced-in}

-   [Feature: Decide what a profile image's metadata will be](https://docs.typo3.org/permalink/fgtclb/academic-persons:feature-modify-profile-image-metadata-event@main) introduced the event.
-   [Important: Backend saves announce profile updates](https://docs.typo3.org/permalink/fgtclb/academic-persons:important-backend-saves-announce-profile-updates@main) describes why a
    backend save writes the reference through the DataHandler hook only.
