How an Extbase backend module works
An Extbase backend module runs the same controllers, repositories and validators as a frontend plugin. The framework around them is different: the request comes from the backend router instead of a content element, the configuration comes from a different TypoScript scope, and there is no plugin record to supply storage pages. This page describes those differences.
Registering the module, access control and rendering through
Module are covered in
Registering an Extbase backend module.
On this page
How a backend module request flows through Extbase
The frontend path is described in How a request flows through Extbase. A backend module takes the same six steps. Steps 3 and 4 run the very same code; the others differ:
-
The backend routes the request to the module
There is no page and no content element. TYPO3 registers a backend route for every action listed in the module's controllerActions. The first action of the first controller answers the module's own route; every other action gets a route named after the module identifier, the controller name without its
Controllersuffix and the action, for examplemy_.extension_ conferences. Conference_ show Before Extbase is involved, the backend checks that the current user may access the module and loads the module's stored state for this user.
-
An Extbase request object is built — without an argument namespace
Extbase takes the extension name and the module identifier from the module, and uses the module identifier where a frontend request has the plugin name. The controller and action come from the route.
Arguments are not namespaced. A frontend plugin reads
tx_so that several plugins can share one page. A module owns the whole request, so it reads plain query and POST parameters:myextension_ conferencelist [conference]=42 conference=42. -
The dispatcher resolves the controller
Identical to the frontend.
-
The controller action runs
Identical to the frontend: property mapping, validation and
errorwork exactly as they do in a plugin.Action () -
The action builds the response through the module template
Instead of
$this->html, the action renders through aResponse () Module, which wraps the output in the backend page frame. See Rendering in the module controller.Template -
The response goes straight back to the backend
There is no page to insert the output into. The response is the complete module page. As in the frontend, pending changes to domain objects are persisted after the action returns.
Some things a frontend plugin can rely on do not exist in a module at all:
there is no content element and therefore no
Content, no
FlexForm, and no page cache. Plugin caching, including
non-cacheable actions, has no meaning in
a module; every request runs the action.
Where an Extbase backend module reads its configuration
A module reads the same kind of configuration a plugin does — settings,
persistence and view options — but from the
module
scope instead
of the
plugin
scope:
config.— framework defaults, shared with the frontend.tx_ extbase module.— defaults for every module of the extension.tx_ myextension module.— values for one module. The module identifier is used as it is registered, lowercased. For a module registered astx_ myextension_<module identifier> my_this isextension_ conferences module..tx_ myextension_ my_ extension_ conferences
How the two
module
layers are merged is described in
How the module configuration is assembled.
This is frontend TypoScript. A developer coming from Symfony or Laravel
would expect backend configuration to live in its own files; in TYPO3,
Extbase modules evaluate the frontend TypoScript of the installation, for
historical reasons. That has a cost: the time a module needs to load its
configuration grows with the amount of frontend TypoScript in the
installation, however little of it the module uses. The
TypoScript reference therefore advises custom
modules against
module
TypoScript altogether.
For an Extbase module, TypoScript remains the place for storage pages and persistence, because that is where Extbase reads them. Settings of your own do not have to live there:
- Settings your module reads itself can live in page TSconfig, which the backend evaluates anyway.
- Template overrides always go through page TSconfig. The
Modulea module renders with resolves its templates from the extension and from the templates option, and ignoresTemplate module..tx_*. view
Which TypoScript an Extbase backend module sees
TypoScript belongs to pages, and a backend module does not always have one. Which TypoScript a module is given depends on whether it has page context:
- With page context
- The module shows the page tree and the editor has selected a page. The module sees the TypoScript of that page, exactly as the frontend would: from the TypoScript records along its rootline, or from the site sets of its site.
- Without page context
- The module has no page tree, no page is selected, or the selected page has no TypoScript. The module sees global TypoScript only.
Changed in version 14.0 Breaking: #105728 - Extbase backend modules not in page context rely on global TypoScript only
A module without page context used to search for the first page with a TypoScript record and use its TypoScript. It now uses global TypoScript only. See also the upgrade entry.
Configuration a module needs in every situation — above all its storage
pages — therefore has to be global. Register it with
\TYPO3\
in the extension's ext_localconf.php:
<?php
declare(strict_types=1);
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
defined('TYPO3') or die();
ExtensionManagementUtility::addTypoScriptSetup('
module.tx_myextension.persistence {
storagePid = 42
# Include records stored one level below page 42
recursive = 1
}
');
TypoScript added this way reaches all three cases: the module without page context, pages whose TypoScript comes from records, and pages whose site uses site sets.
Warning
Do not rely on ext_typoscript_setup.typoscript for module configuration. It is loaded for a module without page context and on sites built from TypoScript records, but not on sites that use site sets. A module with a page tree then loses its configuration as soon as the editor selects a page of such a site.
The same split between modules with and without page context decides which language a module works in, see Localization in backend modules.
The storagePid in an Extbase backend module
The defaults are the opposite of the frontend. A frontend plugin without a
configured storagePid searches page 0; other page uids have to come from
configuration, usually the editor's Starting point. A backend module
without a configured storagePid searches the page selected in the page tree,
and only falls back to 0 when there is none.
A module without a page tree therefore searches page 0 until a
storagePid is configured. The full resolution chain is described in
The storagePid resolution chain in a backend module.
The language in an Extbase backend module
A module with page context can take the language rules from the site of the selected page. A module without one works in the default language unless it chooses another explicitly. Both cases are described in Localization in backend modules.
The id parameter in an Extbase backend module
The selected page reaches a module as the id request parameter. This is a
backend convention rather than a guarantee: some Core modules use id for
something else, the file list for example passes a storage and folder path.
Extbase only treats id as a page when it is a positive integer and
otherwise behaves as if no page were selected. A module that passes its own
values in id therefore silently loses its page context.
With the runtime differences in place, the Extbase-specific keys of the module registration are described in Registering an Extbase backend module, and the storage and language rules in the pages linked above.