Basic usage¶
This page shows how to create a single module and which components are necessary to process data from TYPO3, prepare it and finally output it in the frontend using a Handlebars template.
The CType header serves as an example.
Note
This example only describes the standard process for creating a new module. Further possibilities are described in the section Extended usage.
Example¶
Note
All examples are written in PHP 7.4.
Preparations
Before the actual components are created, some preliminary work is necessary.
Installation
Install the extension using Composer.
Define dependencies
Add the extension as dependency to your extension as described here.
Services.yamlCreate a basic
Services.yamlfile in your extension. Make sure to read and follow the guidelines described at Dependency injection.TypoScript configuration
Create a TypoScript configuration file and include it in your site's root template. Make sure to include static TypoScript from EXT:fluid_styled_content.
Create a new
DataProcessorEach
DataProcessormust implementFr\Typo3Handlebars\DataProcessing\DataProcessorInterface.There's already a default
DataProcessorin place that provides some basic logic and is required in case you want to develop components like described on this page. Just extend yourDataProcessorfromFr\Typo3Handlebars\DataProcessing\AbstractDataProcessorand implement the abstract methodrender():# Classes/DataProcessing/HeaderProcessor.php namespace Vendor\Extension\DataProcessing; use Fr\Typo3Handlebars\DataProcessing\AbstractDataProcessor; class HeaderProcessor extends AbstractDataProcessor { protected function render(): string { $data = $this->provider->get($this->cObj->data); return $this->presenter->present($data); } }
Attention
Use the correct namespace
It is very important to create the
DataProcessorwith the correct namespace, as all other components will be automatically registered based on it.Register
DataProcessoras serviceThe
HeaderProcessormust now be registered in theServices.yamlin the next step:# Configuration/Services.yaml services: Vendor\Extension\DataProcessing\HeaderProcessor: tags: ['handlebars.processor']
All related components (
DataProvider,Presenter) are now automatically assigned to thisDataProcessorand registered accordingly.Tip
If all
DataProcessorsshare the same configuration, they can also be registered all at once with the following configuration:# Configuration/Services.yaml services: Vendor\Extension\DataProcessing\: resource: '../Classes/DataProcessing/**/*Processor.php' tags: ['handlebars.processor']
Create a new
DataProviderNext, a
DataProvidermust be created that prepares the module's data and makes it available to theDataProcessoragain. EachDataProvidermust implementFr\Typo3Handlebars\Data\DataProviderInterface.# Classes/Data/HeaderProvider.php namespace Vendor\Extension\Data; use Fr\Typo3Handlebars\Data\DataProviderInterface; use Fr\Typo3Handlebars\Data\Response\ProviderResponseInterface; use Vendor\Extension\Data\Response\HeaderProviderResponse; class HeaderProvider implements DataProviderInterface { public function get(array $data): ProviderResponseInterface { return (new HeaderProviderResponse($data['header'])) ->setHeaderLayout((int)$data['header_layout']) ->setHeaderLink($data['header_link']) ->setSubheader($data['subheader']); } }
As you can see, the
DataProviderreturns an instance of a so-calledProviderResponseobject. This holds the prepared data for higher-level transfer within the rendering process. Create it in the associated namespace:# Classes/Data/Response/HeaderProviderResponse.php namespace Vendor\Extension\Data\Response; use Fr\Typo3Handlebars\Data\Response\ProviderResponseInterface; class HeaderProviderResponse implements ProviderResponseInterface { public const LAYOUT_DEFAULT = 0; private string $header; private int $headerLayout = self::LAYOUT_DEFAULT; private string $headerLink = ''; private string $subheader = ''; public function __construct(string $header) { $this->header = $header; $this->validate(); } // Getters and setters... public function toArray(): array { return [ 'header' => $this->header, 'headerLayout' => $this->headerLayout, 'headerLink' => $this->headerLink, 'subheader' => $this->subheader, ]; } private function validate(): void { if ('' === trim($this->header)) { throw new \InvalidArgumentException('Header must not be empty.', 1626108393); } } }
Create a new
PresenterTo complete the rendering process, a new
PresentercalledHeaderPresentermust be created. It must implement theFr\Typo3Handlebars\Presenter\PresenterInterface; furthermore, anFr\Typo3Handlebars\Presenter\AbstractPresenteris already available with the defaultRendereralready specified as a dependency.# Classes/Presenter/HeaderPresenter.php namespace Vendor\Extension\Presenter; use Fr\Typo3Handlebars\Data\Response\ProviderResponseInterface; use Fr\Typo3Handlebars\Exception\UnableToPresentException; use Fr\Typo3Handlebars\Presenter\AbstractPresenter; class HeaderPresenter extends AbstractPresenter { public function present(ProviderResponseInterface $data): string { if (!($data instanceof HeaderProviderResponse)) { throw new UnableToPresentException( 'Received unexpected response from provider.', 1613552315 ); } // Use data from ProviderResponse or implement custom logic $renderData = $data->toArray(); return $this->renderer->render( 'Extensions/FluidStyledContent/Header', $renderData ); } }
Set up TypoScript configuration
Finally, you have to configure via TypoScript that instead of the default Fluid rendering the special Handlebars rendering should be executed for all content elements of the CType
header.For this purpose, each
DataProcessorprovides a methodprocess(string $content, array $configuration)as entry point.# Configuration/TypoScript/setup.typoscript tt_content.header = USER tt_content.header.userFunc = Vendor\Extension\DataProcessing\HeaderProcessor->process
Optional: Create custom
HelpersIf your templates use custom
Helpers, you will need to create them additionally. Read Create a custom Helper to learn what options are available for creating your ownHelpers.Flush caches
Changes were made to the service configuration and also the rendering was overwritten using TypoScript. Therefore, it is now necessary to ensure that the caches are flushed and the service container is reconfigured.
Sources¶
See also
View the sources on GitHub: