Create a backend module with Core functionality

This page covers the backend template view, using only Core functionality without Extbase.

Tip

If you want to do extensive data modeling, you may want to use Extbase templating. If you are building a simple backend module, it makes sense to work without Extbase.

Basic controller

When creating a controller without Extbase an instance of ModuleTemplate is required to return the rendered template:

EXT:examples/Classes/Controller/AdminModuleController.php
// the module template will be initialized in handleRequest()
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
use TYPO3\CMS\Core\Imaging\IconFactory;

class AdminModuleController
{
    public function __construct(
        protected readonly ModuleTemplateFactory $moduleTemplateFactory,
        protected readonly IconFactory $iconFactory,
        // ...
    ) {
    }
}

The controller needs to be registered in Configuration/Services.yaml with the tag backend.controller so that dependency injection works:

EXT:examples/Configuration/Services.yaml
services:
   _defaults:
      autowire: true
      autoconfigure: true
      public: false

   T3docs\Examples\:
      resource: '../Classes/*'
      exclude: '../Classes/Domain/Model/*'

   T3docs\Examples\Controller\AdminModuleController:
      tags: ['backend.controller']

Main entry point

The handleRequest() method is the main entry point which triggers only the allowed actions. This makes it possible to include e.g. Javascript for all actions in the controller.

EXT:examples/Classes/Controller/AdminModuleController.php
public function handleRequest(ServerRequestInterface $request): ResponseInterface
{
    $languageService = $GLOBALS['LANG'];
    $languageService->includeLLFile('EXT:examples/Resources/Private/Language/AdminModule/locallang.xlf');

    $this->menuConfig($request);
    $moduleTemplate = $this->moduleTemplateFactory->create($request, 't3docs/examples');
    // setUpDocHeader() is documented below
    $this->setUpDocHeader($moduleTemplate);

    $title = $languageService->sL('LLL:EXT:examples/Resources/Private/Language/AdminModule/locallang_mod.xlf:mlang_tabs_tab');
    switch ($this->MOD_SETTINGS['function']) {
        case 'debug':
            $moduleTemplate->setTitle($title, $languageService->getLL('module.menu.debug'));
            return $this->debugAction($moduleTemplate);
        case 'password':
            $moduleTemplate->setTitle($title, $languageService->getLL('module.menu.password'));
            return $this->passwordAction($moduleTemplate);
        default:
            $moduleTemplate->setTitle($title, $languageService->getLL('module.menu.log'));
            return $this->logAction($moduleTemplate);
    }
}

Actions

Now create an example indexAction() and assign variables to your view as you would normally do.

EXT:examples/Classes/Controller/AdminModuleController.php
public function debugAction(
    ModuleTemplate $view,
    string $cmd = 'cookies'
): ResponseInterface
{
    $cmd = $_POST['tx_examples_admin_examples']['cmd'];
    switch ($cmd) {
        case 'cookies':
            $this->debugCookies();
            break;
    }

    $view->assignMultiple(
        [
            'cookies' => $_COOKIE,
            'lastcommand' => $cmd,
        ]
    );
    return $view->renderResponse('AdminModule/Debug');
}

The DocHeader

To add a DocHeader button use $this->moduleTemplate->getDocHeaderComponent()->getButtonBar() and makeLinkButton() to create the button. Finally use addButton() to add it.

EXT:examples/Classes/Controller/AdminModuleController.php
private function setDocHeader(string $active) {
   $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
   $list = $buttonBar->makeLinkButton()
      ->setHref('<uri-builder-path>')
      ->setTitle('A Title')
      ->setShowLabelText('Link')
      ->setIcon($this->moduleTemplate->getIconFactory()->getIcon('actions-extension-import', Icon::SIZE_SMALL));
   $buttonBar->addButton($list, ButtonBar::BUTTON_POSITION_LEFT, 1);
}

Template example

EXT:examples/Resources/Private/Templates/AdminModule/Debug.html
<html data-namespace-typo3-fluid="true" xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers">

<f:layout name="Module" />

<f:section name="Content">
   <h1><f:translate key="function_debug" extensionName="examples"/></h1>
   <p><f:translate key="function_debug_intro" extensionName="examples"/></p>
   <p><f:debug inline="1">{cookies}</f:debug></p>
</f:section>
</html>

Note

Some Fluid tags do not work in non-Extbase context such as <f:form>.