koch/koch-staticroute

Maintainers

Package info

bitbucket.org/kochkommunikation/koch-staticroute/

Homepage

Type:typo3-cms-extension

pkg:composer/koch/koch-staticroute

Statistics

Installs: 16

Dependents: 0

Suggesters: 0

13.4.1 2026-03-23 08:19 UTC

This package is auto-updated.

Last update: 2026-04-23 08:27:53 UTC


README

Lightweight TYPO3 extension for registering static route controllers that bypass the page tree. Routes are resolved via a PSR-15 frontend middleware using Symfony Routing. No TypoScript, no page record, no Extbase.

Requirements

  • PHP >= 8.2
  • TYPO3 v13.4+
  • symfony/routing ^7.0

Installation

composer require koch/koch-staticroute

Architecture

A PSR-15 middleware intercepts requests prefixed with /route-static after site-resolver and before page-resolver. It matches the path against a Symfony RouteCollection built from all services implementing StaticControllerInterface. On match, route parameters are merged into $request->getQueryParams() and the controller's handle() method is called. On no match, the request falls through to TYPO3's page resolver.

Writing a Controller

Implement StaticControllerInterface and add two attributes:

  • #[AsTaggedItem(index: '...')] — unique route name, used as the service locator key
  • #[StaticRoute(...)] — route pattern, requirements, defaults, allowed HTTP methods
<?php
declare(strict_types=1);

namespace Vendor\MyExt\Controller;

use Koch\StaticRoute\Attribute\StaticRoute;
use Koch\StaticRoute\Controller\StaticControllerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem;
use TYPO3\CMS\Core\Http\JsonResponse;

#[AsTaggedItem(index: 'webhook-stripe')]
#[StaticRoute(
    pattern: '/webhook/stripe/{action}',
    requirements: ['action' => 'charge|refund|dispute'],
    defaults: ['action' => 'charge'],
    methods: ['POST'],
)]
final class StripeWebhookController implements StaticControllerInterface
{
    public function handle(ServerRequestInterface $request): ResponseInterface
    {
        $action = $request->getQueryParams()['action'] ?? 'charge';

        return new JsonResponse(['status' => 'ok', 'action' => $action]);
    }
}

No manual service registration required — autoconfigure: true in your Services.yaml is sufficient.

Route Parameters

Matched route parameters are merged into query params. Given the pattern /webhook/stripe/{action}, a request to POST /route-static/webhook/stripe/refund results in:

$request->getQueryParams()['action']; // 'refund'

Existing query parameters are preserved. Route parameters take precedence on key collision.

Generating URIs

Inject StaticRouteUriBuilder to generate URLs for registered routes:

use Koch\StaticRoute\Service\StaticRouteUriBuilder;

final readonly class MyService
{
    public function __construct(
        private StaticRouteUriBuilder $uriBuilder,
    ) {}

    public function getWebhookUrl(): string
    {
        return $this->uriBuilder->buildUri('webhook-stripe', ['action' => 'refund']);
        // → /route-static/webhook/stripe/refund
    }
}

Pass a ServerRequestInterface and absolute: true for fully qualified URLs:

$this->uriBuilder->buildUri('webhook-stripe', ['action' => 'refund'], $request, absolute: true);
// → https://example.com/route-static/webhook/stripe/refund

Attribute Reference

#[AsTaggedItem(index: string)]

Symfony DI attribute. The index value is the unique route name used to identify the controller in the service locator and for URI generation. Duplicate indexes within the same tag are rejected at container compile time.

#[StaticRoute]

ParameterTypeDefaultDescription
patternstringRoute pattern after /route-static, e.g. /api/{id}
requirementsarray<string,string>[]Symfony route requirements, e.g. ['id' => '\d+']
defaultsarray<string,mixed>[]Default values for optional parameters
methodslist<string>[]Allowed HTTP methods, empty = all

File Structure

Classes/
  Attribute/StaticRoute.php
  Controller/StaticControllerInterface.php
  Frontend/Middleware/StaticRouteResolveMiddleware.php
  Routing/StaticRouteCollectionFactory.php
  Service/StaticRouteUriBuilder.php
Configuration/
  RequestMiddlewares.php
  Services.yaml
composer.json