Custom reaction type
A custom reaction type may be useful, if the create database record type is not sufficient.
As an example the following scenario is used:
We want to synchronize products from an external system into TYPO3. As the
synchronization may be time-consuming (think of synchronizing images), the
real work is done by a command. Therefore, the reaction receives an ID from
a product which was added or changed. This ID is stored in the
sys_
table.
A command (which is not part of this example) runs regularly and synchronizes every product ID stored in the registry entry into TYPO3.
You can find the implemented reaction type in the EXT:examples extension.
Create the reaction type
To create a custom reaction type, we add a class which implements the EXT:reactions/Classes/Reaction/ReactionInterface.php (GitHub):
<?php
declare(strict_types=1);
namespace T3docs\Examples\Reaction;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamFactoryInterface;
use TYPO3\CMS\Core\Registry;
use TYPO3\CMS\Reactions\Model\ReactionInstruction;
use TYPO3\CMS\Reactions\Reaction\ReactionInterface;
class ExampleReactionType implements ReactionInterface
{
private const REGISTRY_KEY = 'changed_ids';
public function __construct(
private readonly Registry $registry,
private readonly ResponseFactoryInterface $responseFactory,
private readonly StreamFactoryInterface $streamFactory,
) {}
public static function getType(): string
{
return 'example-reaction-type';
}
public static function getDescription(): string
{
return 'Example reaction type';
}
public static function getIconIdentifier(): string
{
return 'tx_examples-dummy';
}
public function react(
ServerRequestInterface $request,
array $payload,
ReactionInstruction $reaction
): ResponseInterface {
$id = $payload['id'] ?? 0;
if ($id <= 0) {
$data = [
'success' => false,
'error' => 'id not given',
];
return $this->jsonResponse($data, 400);
}
$this->updateRegistryEntry($id);
return $this->jsonResponse(['success' => true]);
}
private function updateRegistryEntry(int $id): void
{
$ids = $this->registry->get('tx_examples', self::REGISTRY_KEY) ?? [];
$ids[] = $id;
$ids = array_unique($ids);
$this->registry->set('tx_examples', self::REGISTRY_KEY, $ids);
}
private function jsonResponse(array $data, int $statusCode = 201): ResponseInterface
{
return $this->responseFactory
->createResponse($statusCode)
->withHeader('Content-Type', 'application/json')
->withBody($this->streamFactory->createStream(json_encode($data, JSON_THROW_ON_ERROR)));
}
}
You can use constructor injection to inject necessary dependencies.
Add reaction type to select list in backend module
In a next step we add the newly created reaction type to the list of reaction types in the backend:
<?php
defined('TYPO3') or die();
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem(
'sys_reaction',
'reaction_type',
[
'label' => \T3docs\Examples\Reaction\ExampleReactionType::getDescription(),
'value' => \T3docs\Examples\Reaction\ExampleReactionType::getType(),
'icon' => \T3docs\Examples\Reaction\ExampleReactionType::getIconIdentifier(),
]
);
Now, our newly created type is displayed and can be selected: