For Developers
Architecture Overview
The extension follows standard TYPO3 12/13 patterns: PSR-4 autoloading, Symfony DI with autowiring, attribute-based backend controller registration, and Fluid templates.
Classes/
├── Controller/Backend/
│ └── ConfigurationController.php # Backend module controller
├── DataProcessing/
│ └── RekaiSettingsProcessor.php # Fluid data processor
├── Hook/
│ └── PageRendererHook.php # PageRenderer pre-process hook
└── Service/
└── RekAiConfigurationService.php # Read/write extension configuration
RekAiConfigurationService
One is the central service for reading and
writing the extension configuration. Configuration is per site and stored in
config/. The service is available via dependency injection.
Public API
use OneForge\RekAi\Service\RekAiConfigurationService;
use TYPO3\CMS\Core\Site\Entity\Site;
// Via constructor injection (recommended)
public function __construct(
private readonly RekAiConfigurationService $rekAiConfigService,
) {}
All read methods require the concrete TYPO3CMSCore object (not
Site or Null). Obtain it from the current frontend request via
$request->getAttribute('site') or from Site in backend contexts.
Methods
getConfiguration For Site (Site $site): array - Returns the full configuration array for the given site, merged with defaults.
Keys:
loadScripts,scriptUrl,nonCssVersion,autocompleteMode,autocompleteSelector,autocompleteOpenOnClick,autocompleteUseCurrentLanguage,autocompleteNumberOfResults,autocompleteCustomScript. isScript Loading Enabled (Site $site): bool - Returns
truewhen theloadScriptsflag is enabled for the site. isNon Css Version (Site $site): bool - Returns
truewhen thenonCssVersionflag is enabled for the site. getConfigured Script Url (Site $site): string - Returns the configured script URL as a trimmed string, or an empty string if not set.
isValid Script Url (string $script Url): bool - Returns
truewhen the given string is a non-empty, well-formed URL (usesfilter_). Stateless — no site parameter needed.var ($url, FILTER_ VALIDATE_ URL) getAutocomplete Mode (Site $site): int - Returns the autocomplete mode (0, 1, or 2) for the site.
getAutocomplete Selector (Site $site): string - Returns the CSS selector string for autocomplete mode 1.
isAutocomplete Open On Click (Site $site): bool - Returns
truewhen the open-on-click behaviour is enabled. isAutocomplete Use Current Language (Site $site): bool - Returns
truewhen language filtering is enabled. getAutocomplete Number Of Results (Site $site): int - Returns the configured maximum number of autocomplete suggestions.
getAutocomplete Custom Script (Site $site): string - Returns the raw custom autocomplete script for mode 2.
buildAutocomplete Init Script (Site $site): string - Generates and returns the full autocomplete initialisation
<script>block for the site. Returns an empty string when autocomplete mode is 0. saveConfiguration (Site $site, bool $load Scripts, string $script Url, bool $non Css Version, int $mode, string $selector, string $custom Script, bool $open On Click, bool $use Current Language, int $number Of Results): void - Persists all values to the site's
settings.viayaml Site, which also flushes the TYPO3 code cache so the new values take effect immediately.Settings Service:: write Settings ()
PageRendererHook
One is registered via ext_ as a
render-preProcess hook on t3lib_:
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']
['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'][]
= \OneForge\RekAi\Hook\PageRendererHook::class . '->addRekAiScript';
The hook's addRekAiScript() method:
- Reads the current site from
$GLOBALS['TYPO3_REQUEST']->getAttribute('site'). - Returns early if the attribute is not a concrete
Siteinstance (e.g. CLI or backend context). - Reads the configuration for that site via
Rek.Ai Configuration Service - Returns early if
loadScriptsis disabled orscriptUrlis empty. -
Otherwise calls
Pagewith:Renderer:: add Header Data () <script src="https://static.rekai.se/xyz.js" defer></script>Copied!
The src attribute is escaped with htmlspecialchars.
RekaiSettingsProcessor
One implements
TYPO3CMSFrontend. It is configured in the
TypoScript rendering chain for both tt_content.rekai_recommendations and
tt_content.rekai_qna:
dataProcessing {
10 = OneForge\RekAi\DataProcessing\RekaiSettingsProcessor
}
The processor reads the full extension configuration for the current site and assigns it as the
Fluid variable {rekaiSettings}. Both frontend templates use {rekaiSettings.loadScripts}
to guard their widget output. The processor also resolves any selected page UIDs in the
tx_rekai_subtree_pages / tx_rekai_qna_subtree_pages group fields to URL slugs, storing
the result in data.tx_rekai_subtree / data.tx_rekai_qna_subtree respectively.
ConfigurationController
One handles both GET and
POST requests for the backend module. It is registered with the
# attribute and resolves through Symfony DI.
Site resolution — the active site is determined from the rekaiSite key in the POST body
(hidden form field) or GET query parameter, falling back to the first site returned by
Site. URLs for site switching are built via
Backend so they survive TYPO3's backend routing.
GET – renders the form pre-populated with the configuration of the resolved site. When more than one TYPO3 site exists, a site selector dropdown is shown above the form.
POST – validates input (URL must be valid when loadScripts is checked), saves the
configuration for the resolved site via Rek,
queues a flash message, and redirects (PRG pattern) back to the module URL for the same site.
The controller uses Module to create a Module and returns
Module.
TCA & Database Schema
The extension extends tt_content with the following columns:
rekai_recommendations
| Column | Type | Description |
|---|---|---|
tx_rekai_show_header | tinyint(1) | Toggle: show widget header (default 1) |
tx_rekai_headertext | varchar(255) | Text displayed above the recommendations list |
tx_rekai_titlemaxlength | int(11) | Maximum characters for each recommendation title (1–99, default 20) |
tx_rekai_nrofhits | int(11) | Number of recommendation links to render (1–20, default 5) |
tx_rekai_renderstyle | varchar(20) | Layout style: pills, list, or advanced |
tx_rekai_listcols | int(11) | Number of columns for the list render style (1–6, default 2) |
tx_rekai_rootpath_mode | varchar(20) | Scope of candidate pages: '', subpages, or level |
tx_rekai_rootpathlevel | int(11) | Tree level for the level root path mode (1–10, default 1) |
tx_rekai_subtree_pages | text | Page UIDs (serialised group field) resolved to URL slugs at render time; passed as data-subtree |
tx_rekai_excludechildnodes | tinyint(1) | Exclude children of the root path entry point (default 0) |
tx_rekai_extra_attributes | text | Raw HTML data-attribute string appended verbatim to the widget <div> |
rekai_qna
| Column | Type | Description |
|---|---|---|
tx_rekai_qna_branch_mode | varchar(20) | Q&A scope: '' (none), current, subtree, or currentpage |
tx_rekai_qna_subtree_pages | text | Page UIDs resolved to URL slugs; passed as data-subtree when branch mode is subtree |
tx_rekai_qna_nrofhits | int(11) | Maximum Q&A items to display (0 = no limit, default 0) |
tx_rekai_qna_tags | varchar(255) | Comma-separated tag filter; passed as data-tags |
tx_rekai_qna_hide_answer_link_same | tinyint(1) | Hide the answer link when the answer is on the current page (default 0) |
tx_rekai_qna_hide_answer_link | tinyint(1) | Always hide the link to the answer page (default 0) |
tx_rekai_qna_disable_highlight | tinyint(1) | Disable Rek.ai keyword highlighting in answers (default 0) |
Dependency Injection
Configuration/ enables autowiring and autoconfiguration for all classes under
the OneForge\RekAi\ namespace. The backend controller is explicitly declared public: true
so TYPO3's backend routing can resolve it from the container:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
OneForge\RekAi\:
resource: '../Classes/*'
OneForge\RekAi\Controller\Backend\ConfigurationController:
public: true
OneForge\RekAi\Hook\PageRendererHook:
public: true
Extending the Extension
Custom data attributes
If the Rek.ai widget requires additional data-* attributes that are not covered by the
standard TCA fields, use the Extra Attributes field on the content element (see
Advanced (tab)) without touching the extension code.
Custom templates
Override the Fluid template by adding a higher-priority path in your site package's TypoScript:
tt_content.rekai_recommendations.templateRootPaths {
20 = EXT:my_site_package/Resources/Private/Templates/Content/
}
Place your custom Rekai in that directory.
Custom data processor
To pass additional variables to the Fluid template, chain your own data processor after the built-in one:
tt_content.rekai_recommendations.dataProcessing {
20 = Vendor\MyExtension\DataProcessing\MyProcessor
}