Custom Operation Handlers
The dispatcher routes each request through a handler pipeline — a prioritised
list of objects that implement OperationHandlerInterface. Built-in handlers
cover list, show, create, update, delete, and userinfo.
Third-party extensions can add new operation types or replace built-in behaviour
by registering their own handlers.
Interface
namespace MaikSchneider\TcaApi\OperationHandler;
use MaikSchneider\TcaApi\Configuration\ApiDefinition;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
interface OperationHandlerInterface
{
public function supports(
ServerRequestInterface $request,
string $operation,
ApiDefinition $config
): bool;
public function handle(
ServerRequestInterface $request,
ApiDefinition $config
): ResponseInterface;
public function getPriority(): int;
}
supports()— returntrueif this handler should process the request.handle()— execute the operation and return a PSR-7 response.getPriority()— higher values are checked first. Built-in handlers use priority10.
Writing a custom handler
namespace My\Extension\OperationHandler;
use MaikSchneider\TcaApi\Configuration\ApiDefinition;
use MaikSchneider\TcaApi\OperationHandler\OperationHandlerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
final class PublishHandler implements OperationHandlerInterface
{
public function supports(
ServerRequestInterface $request,
string $operation,
ApiDefinition $config
): bool {
return $operation === 'publish'
&& $config->table === 'tx_myext_domain_model_article';
}
public function handle(
ServerRequestInterface $request,
ApiDefinition $config
): ResponseInterface {
$uid = (int) $request->getAttribute('tca_api.uid');
// … publish logic …
}
public function getPriority(): int
{
return 10;
}
}
Registering handlers
No ext_ changes are needed. TCA_API's
Configuration/ contains an _instanceof rule that
automatically tags every class implementing OperationHandlerInterface with
tca_api.operation_handler. The HandlerRegistry collects all tagged
services via Symfony's AutowireIterator and sorts them by priority.
All that is required is that the handler class is discoverable by the DI
container. If your extension uses the standard service auto-discovery pattern
(resource: '../Classes/*'), nothing else is needed. The dispatcher iterates
handlers highest priority first and dispatches to the first match.
To override a built-in handler, return a priority higher than 10:
public function getPriority(): int
{
return 20; // checked before the built-in handler (priority 10)
}