---
title: "Developer corner"
manual: "Ai3 Alt Text"
version: "0.9"
permalink: "https://docs.typo3.org/permalink/wegewerk/ai3_alttext:developer@0.9"
source: "Developer/Index.rst"
rendered: "2026-10-23T16:31:04+00:00"
---

# Developer corner {#developer}

## Architecture overview {#developer-architecture}

ai3-alttext follows the capability pattern introduced by
[`wegewerk/ai3_core`](https://packagist.org/packages/wegewerk/ai3_core). The central pieces are:

| Class | Responsibility |
| --- | --- |
| `ZakAiAlttext` | Extends `AbstractZakAiEndpoint`; resizes the image and calls the `/alttexts` REST endpoint |
| `AlttextCapability` | Registers the alt text capability under the key `alttext` so the core task queue can dispatch jobs to it |
| `AlttextController` (Ajax) | Manages the generation task lifecycle: create, poll status, review, and select a suggestion |
| `FilelistController` (Ajax) | Lists files in a folder and saves approved alt texts back to `sys_file_metadata` |
| `FolderController` (Ajax) | Lists sub-folders and bulk-accepts suggestions recursively |
| `Ai3AlttextAddToBatch` | FormEngine `AbstractNode` that renders the batch button in the file metadata edit form |
| `AfterFormEnginePageInitializedEventListener` | Loads the extension language labels whenever a FormEngine page is initialised |

## ZakAiAlttext API class {#developer-api}

`Wegewerk\Ai3Alttext\Api\ZakAiAlttext` extends
`Wegewerk\Ai3Core\Api\AbstractZakAiEndpoint` (implementing
`ZakAiEndpointInterface`) and exposes a single public method:

**Classes/Api/ZakAiAlttext.php (signature)**

```php
public function generate(array $options = []): string
```

The method accepts an options array:

-   `imagePath` (string, required): Absolute local path to the image file.
-   `caption` (string, optional): Contextual text / caption for the image.
-   `language` (string, optional): Target language code.
-   `previous` (mixed, optional): Previous suggestions to avoid duplication.

The generation flow:

1.  Verifies the image file exists on disk (in `preparePayload()`).
1.  Resizes the image to a maximum of 512 × 512 px using
    `ImageService` and `ImageProcessingService` to keep API
    payload sizes small.
1.  Base64-encodes the resized image into the `image` payload field and POSTs it to the
    `/alttexts` endpoint via `ZakAiClient::postJson()`.
1.  Returns the `alttext` string from the API response, or an empty
    string if the API reports an error.

## Ajax routes {#developer-ajax-routes}

All Ajax endpoints are registered in
[`Configuration/Backend/AjaxRoutes.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/Backend/Index.html#file-extension-configuration-backend-ajaxroutes-php):

| Route identifier | Target |
| --- | --- |
| `ai3_alttext_generation_create_task` | `AlttextController::addAlttextGenerationTaskAction` |
| `ai3_alttext_generation_review` | `AlttextController::reviewAlttextAction` |
| `ai3_alttext_generation_select` | `AlttextController::selectAlttextAction` |
| `ai3_alttext_generation_status` | `AlttextController::checkAlttextGenerationStatusAction` |
| `ai3_filelist` | `FilelistController::listFiles` |
| `ai3_filelist_save_file` | `FilelistController::saveFile` |
| `ai3_filelist_create_task_alttext` | `FilelistController::addAlttextTaskForFile` |
| `ai3_folders` | `FolderController::listFolders` |
| `ai3_folders_acceptAll_recursive` | `FolderController::acceptAllSuggestionsRecursive` |

## Capability registration {#developer-capability}

`AlttextCapability` is registered as a DI-tagged service so that the
[`wegewerk/ai3_core`](https://packagist.org/packages/wegewerk/ai3_core) capability registry picks it up
automatically:

**Configuration/Services.yaml**

```yaml
Wegewerk\Ai3Alttext\Domain\Capabilities\AlttextCapability:
    autowire: false
    arguments:
        $key: 'alttext'
        $title: 'Alt Text'
        $endpoint: '@Wegewerk\Ai3Alttext\Api\ZakAiAlttext'
    tags:
        - name: ai3.capability
```

## FormEngine field control {#developer-formengine}

The field control is registered as a custom FormEngine node in
[`ext_localconf.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/ExtLocalconf.html#file-extension-ext-localconf-php):

**ext_localconf.php**

```php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['formEngine']['nodeRegistry'][1759225979] = [
    'nodeName' => 'ai3AlttextAddToBatch',
    'priority' => 30,
    'class' => \Wegewerk\Ai3Alttext\FormEngine\FieldControl\Ai3AlttextAddToBatch::class,
];
```

The TCA override in
[`Configuration/TCA/Overrides/sys_file_metadata.php`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ExtensionArchitecture/FileStructure/Configuration/TCA/Index.html#file-extension-configuration-tca-overridessomefile-php) attaches
this node to the `alternative` field of `sys_file_metadata` as a
`fieldControl`.

## Event listener {#developer-event-listener}

`AfterFormEnginePageInitializedEventListener` listens to
`AfterFormEnginePageInitializedEvent` and injects the extension
language labels into the page renderer so that the JavaScript modules
can use them via the TYPO3 inline label API.
