Purpose: Help an autonomous agent understand and operate the Larium HTTP framework in this repository. This guide explains the runtime graph (DI), request lifecycle (middlewares → routing → actions → responders), shared kernel contracts (auth, validation), CommandBus (CQS), environment/config, and the extension points. Follow this to add features, debug, or automate tasks.
- App types: Web (HTML) and Api (JSON) - two independent applications sharing common infrastructure.
- Web entry:
public/web/index.php- HTML responses via Twig templates. - Api entry:
public/api/index.php- JSON responses. - DI Containers: Each interface has its own provider:
- Web:
src/Ui/Web/Provider/DiContainerProvider.php - Api:
src/Ui/Api/Provider/DiContainerProvider.php
- Web:
- Router: FastRoute wrapped by
Larium\Framework\Bridge\Routing\FastRouteBridge. - Middleware pipeline (same for both applications):
ExceptionMiddleware(outermost) - interface-specificFirewallMiddleware(auth by route patterns) - sharedRoutingMiddleware- frameworkActionResolverMiddleware(innermost) - framework
- Views: Twig via
HtmlResponder(Web), JSON viaJsonResponder(Api).
What happens per request:
- Front controller bootstraps container and framework, wires middleware order.
ExceptionMiddlewareguards everything, normalizes errors to HTML (4xx/5xx).FirewallMiddlewarechecks path against configured patterns and applies authenticator service if needed; attachesuserto request attributes.- Router matches path and HTTP method to an Action class.
- Action executes (CQS-friendly), typically delegates rendering to
HtmlResponder.
- Provider:
src/Ui/Web/Provider/DiContainerProvider.php(implementsLarium\Framework\Provider\ContainerProvider). - Registers:
- Router (FastRoute dispatcher built from
RouterProviderroutes) - Twig Template engine (
Templateabstraction) - Logger (Monolog → stdout)
- Firewall +
FirewallMiddleware - CommandBus (Tactician) with
ContainerLocatorfrom SharedKernel
- Router (FastRoute dispatcher built from
- Extend by adding new service definitions in
addDefinitions([...]).
Key factories:
- Router uses
RouterProviderto register all HTTP routes programmatically. - Template engine points to
src/Ui/Web/templates.
- Router definitions live in
src/Ui/Web/Provider/RouterProvider.php. - Map HTTP paths to Action classes:
$r->get('/', HomeAction::class); - Action contract:
Larium\Framework\Http\Action(invokable withServerRequestInterface). - Typical Action returns
HtmlResponder->getResponse(status, template, data). - Add routes by updating
RouterProvider::register.
ExceptionMiddleware(interface-specific):- Web:
src/Ui/Web/Middleware/ExceptionMiddleware.php- catches all exceptions, maps toerrors/4xx.html.twigorerrors/5xx.html.twig. - Api:
src/Ui/Api/Middleware/ExceptionMiddleware.php- catches all exceptions, returns JSON. - Both delegate to
ExceptionErrorMapper(src/Ui/SharedKernel/Error/ExceptionErrorMapper.php) for centralized exception-to-status/payload mapping. - Logs unexpected errors (status >= 500).
- Web:
FirewallMiddleware(src/Ui/SharedKernel/Middleware/FirewallMiddleware.php):- Uses
SharedKernel\Authentication\Firewallto map URL regex patterns → authenticator service ids. - If a path matches, invokes the authenticator service with the request.
- Attaches the authentication result (e.g., principal) to request attribute
user. - If no match, continues without authentication.
- Note: Shared across both Web and Api applications.
- Uses
- Framework middlewares:
RoutingMiddlewarematches the route.ActionResolverMiddlewareresolves the Action from DI and invokes it.
Order matters. Exception → Firewall → Routing → ActionResolver.
HtmlResponder(src/Ui/Web/Responder/HtmlResponder.php) renders Twig templates and returns PSR-7 responses withtext/html.- Signature:
getResponse(int $status, string $template, array $payload = [], ?Throwable $e = null)
- Signature:
JsonResponder(src/Ui/Api/Responder/JsonResponder.php) renders JSON and returns PSR-7 responses withapplication/json.- Signature:
getResponse(array $payload, int $status)
- Signature:
- Templates:
src/Ui/Web/templates(e.g.,home/index.html.twig,errors/4xx.html.twig,errors/5xx.html.twig). - Set status codes and payload in the responder call.
- Location:
src/Ui/SharedKernel - Middleware:
FirewallMiddleware(Middleware/FirewallMiddleware.php) - shared auth middleware for both interfaces.
- Error Handling:
ExceptionErrorMapper(Error/ExceptionErrorMapper.php) - centralizes exception-to-status/payload mapping.- Returns
['status' => int, 'payload' => array]for consistent error responses. - Handles
AuthenticationException(401),ValidationException(400),HttpNotFoundException(404),HttpMethodNotAllowedException(405), and genericThrowable(500).
- Returns
- Authentication: interfaces and helpers (
Authentication,AuthenticatorService,CredentialCollector,Firewall).Firewallmaps regex patterns to authenticator service ids (defined in each interface's DI).- Admin-only: Authentication is for admin changes only, not user-specific authentication.
- Predefined types: JWT, shared-key, basic-auth (configured in
.env.dist).
- Validation:
Service/Validation/ValidationService.phpthrowsValidationExceptionwith structured errors.- Uses Symfony Validator:
validate(object $object, array $context = [])throwsValidationExceptionwith field-level errors. ValidationException::badRequest(array $errors)creates 400-level exception with['reason' => $message, 'name' => $propertyPath]structure.JsonIntegrityValidationvalidates JSON syntax and returns decoded array, throwsValidationExceptionon parse errors.
- Uses Symfony Validator:
- Request Object Provider:
Service/RequestObjectProvider.phpmaps HTTP requests to DTOs.provide(ServerRequestInterface $request, string $className, array $validationContext): objectauto-detects content type.- Supports JSON (
application/json) and form data (parsed body). - Merges query parameters with body (body values override query on conflicts).
- Handles validation context for DTO validation rules.
- CommandBus (CQS):
- Tactician
CommandBusregistered in DI with middleware pipeline:CommandHandlerMiddleware(ClassNameExtractor, ContainerLocator, HandleInflector)
ContainerLocatoris inSharedKernel/Service/ContainerLocator.phpand mapsFooCommand→FooHandler(andBarQuery→BarQueryHandler).
- Tactician
.envloaded inDiContainerProviderviavlucas/phpdotenv.- Important keys:
APP_NAME,APP_ENV(controls logger level, etc.)- Admin authentication secrets/keys for JWT, shared-key, basic-auth (see
.env.dist)
- Assets copied via composer scripts to
public/web/*/vendor.
- Add a new Web page:
- Create an Action in
src/Ui/Web/Action/. - Add a Twig template under
src/Ui/Web/templates/.... - Register route in
src/Ui/Web/Provider/RouterProvider.php. - Return
HtmlResponder->getResponse($status, $template, $data).
- Create an Action in
- Add a new Api endpoint:
- Create an Action in
src/Ui/Api/Action/. - Register route in
src/Ui/Api/Provider/RouterProvider.php. - Return
JsonResponder->getResponse($payload, $status).
- Create an Action in
- Protect a route (both interfaces):
- In interface-specific
DiContainerProvider, extendFirewallconfig with a regex → authenticator id. - Register the authenticator service (and credential collector if needed).
FirewallMiddlewarewill automatically apply authentication if URL matches pattern.- Note: Authentication is for admin-only routes, not user authentication.
- In interface-specific
- Add a command/query (CQS):
- Create
DoXCommand+DoXHandler(orFindYQuery+FindYQueryHandler). - No manual DI registration needed for concrete handlers: autowiring and
ContainerLocatorresolve them automatically. Register DI bindings only for interfaces (to select specific implementations). - Get
CommandBusfrom the container, callhandle(new DoXCommand(...)).
- Create
- Add a service:
- Define in interface-specific
DiContainerProvider::getContainer()via$builder->addDefinitions([...]). - Each interface's DI container is independent.
- Define in interface-specific
- Map request data to a DTO:
- Create a DTO class with properties and validation attributes (Symfony Validator).
- In your Action, inject
RequestObjectProviderfrom SharedKernel. - Call
$provider->provide($request, MyDto::class, ['validation_context']). - The provider auto-detects JSON vs form data, merges query+body, validates, and returns the DTO.
- Install deps:
composer install - Serve:
php -S 127.0.0.1:8000 -t public - Web interface:
http://127.0.0.1:8000/web/ - Api interface:
http://127.0.0.1:8000/api/ - Lint/tests:
php -l src/Ui/Web/Action/HomeAction.php,./vendor/bin/phpunit(if tests present)
Web Application:
- Entry:
public/web/index.php - DI:
src/Ui/Web/Provider/DiContainerProvider.php - Routes:
src/Ui/Web/Provider/RouterProvider.php - Middlewares:
src/Ui/Web/Middleware/* - Actions:
src/Ui/Web/Action/* - Responder:
src/Ui/Web/Responder/HtmlResponder.php - Templates:
src/Ui/Web/templates/*
Api Application:
- Entry:
public/api/index.php - DI:
src/Ui/Api/Provider/DiContainerProvider.php - Routes:
src/Ui/Api/Provider/RouterProvider.php - Middlewares:
src/Ui/Api/Middleware/* - Actions:
src/Ui/Api/Action/* - Responder:
src/Ui/Api/Responder/JsonResponder.php
Shared Kernel:
- Middleware:
src/Ui/SharedKernel/Middleware/FirewallMiddleware.php - Error:
src/Ui/SharedKernel/Error/ExceptionErrorMapper.php - Request Object Provider:
src/Ui/SharedKernel/Service/RequestObjectProvider.php - Validation Services:
src/Ui/SharedKernel/Service/Validation/* - CommandBus Locator:
src/Ui/SharedKernel/Service/ContainerLocator.php - Authentication:
src/Ui/SharedKernel/Authentication/*
This guide is optimized for automation: the agent should be able to add routes, actions, services, auth rules, and commands by editing the files listed above, keeping middleware order and DI registrations intact.