Compose puts a PSR-15 middleware pipeline, a pragmatic service container, and filesystem-driven pages behind a single entry point. This document connects the major pieces so you can understand how a request turns into a response and where to plug in your own code.
Compose\Support\Configuration) that defines services, middleware, template settings, routes, and pages.Starter::start($config) creates the service container, assembles the middleware pipeline, dispatches lifecycle events, and begins listening for HTTP requests.Each layer can be customised—swap middleware, override services, add events—without losing the default behaviour that gets you to “Hello World” immediately.
Starter::start wraps your configuration in Configuration, creates a ServiceContainer, registers framework defaults, and pipes the error handler.PipelineInitEvent fires so listeners can adjust the container before middleware is added.OriginalMessages, and BodyParsingMiddleware are piped first.config['middleware'] is sorted (ksort) and piped in order.NotFoundMiddleware.PipelineReadyEvent fires, enabling listeners to inspect the fully composed container/pipeline.ResponseEvent fires. Exceptions trigger ExceptionEvent and ultimately the error handler.RequestHandlerRunner emits the final response. If no middleware produced one, NotFoundMiddleware renders the default 404 page.Compose\Config defines the framework defaults. You merge your overrides on top:
$config = array_replace_recursive((new Compose\Config())(), [
'pages' => ['dir' => __DIR__ . '/../pages'],
'template' => [
'layout' => 'layouts::app',
'folders' => ['layouts' => __DIR__ . '/../layouts'],
],
'services' => [
Psr\Log\LoggerInterface::class => App\LoggerFactory::class,
],
]);
When the container resolves a service it supports:
ResolvableInterface (autowired).(ContainerInterface $container, string $id).Because the configuration object can be toggled read-only, it’s safe to pass around without worrying about accidental mutation.
/ → pages/index.phtml, /docs/intro → pages/docs/intro.phtml.*.phtml.php script. If present, it runs first and may:
ResponseInterface to short-circuit rendering.pages['folders'], letting you mount sections like 'docs' => __DIR__ . '/../content/docs'.The template renderer supports namespaced template references using the alias::template syntax:
alias) refers to a folder alias defined in template['folders'].template) is the relative path to the script within that folder (extension is appended automatically).'folders' => ['layouts' => __DIR__ . '/../layouts'], calling $this->layout('layouts::app') loads layouts/app.phtml.If no alias is provided ('home' instead of 'app::home'), the renderer looks in the base directory set by template['dir'].
Compose emits PSR-14 events for key lifecycle moments:
PipelineInitEvent and PipelineReadyEvent bookend pipeline composition.RouteEvent, DispatchEvent, ResponseEvent, and ExceptionEvent cover routing and dispatch.BroadcastEvent('pages.match') signals when a page successfully matched.Register subscribers in configuration ('subscribers' => [App\MySubscriber::class]) or grab the listener provider in the starter callback to register closures dynamically. Events let you integrate logging, metrics, or feature toggles without modifying core middleware.
pages.dir at your content directory and registering any services or middleware you need.Starter::start($config, $optionalCallback).Use the other documents for deep dives on specific areas: