Request Lifecycle

Follow an HTTP request from the front controller to the rendered response.

Category: HTTP Stack

1. Front controller (public/index.php) #

  1. Composer autoload + shared application bootstrap via bootstrap/app.php.
  2. $app->boot() registers core services, loads config, and boots modules.
  3. Request::capture() snapshots PHP superglobals.
  4. Router is resolved from the container ($app->make('router')).
  5. Route caching? If storage/cache/routes.php exists (generated by velvet route:cache), it is loaded immediately; otherwise routes/web.php is executed to register routes (and modules can add more during boot()).

2. Router dispatch #

  • Router::dispatch() normalizes the HTTP method (including _method spoofing on POST) and path, then emits router.matching and router.matched events.
  • Route patterns support {slug}, optional {slug?}, and greedy {asset*} parameters. Named routes are tracked for url() generation.
  • The router builds a middleware stack from config/http.php globals + route-specific middleware (added via ->middleware(...)).

3. Middleware pipeline #

VelvetCMS\Http\Middleware\Pipeline executes middleware back-to-front:

  • Global aliases are configured in config/http.php (e.g., 'errors' => ErrorHandlingMiddleware::class).
  • Each middleware receives (Request $request, callable $next) and returns a Response or defers to $next($request).
  • Built-in middleware:
    • ErrorHandlingMiddleware catches Throwable, delegates to the exception handler, and rethrows in app.debug mode.
    • VerifyCsrfToken enforces CSRF tokens on mutating verbs unless a path matches its except patterns.

4. Controller / handler execution #

  • Route handlers can be closures or [ControllerClass::class, 'method']. Controller dependencies are autowired via the application container.
  • Whatever the handler returns is coerced into a Response: strings become HTML, arrays become JSON, everything else is stringified.

5. Response sending #

  • Response::send() sets the HTTP status, writes headers, and echoes the body. Helpers like Response::json(), Response::file(), Response::redirect(), and Response::methodNotAllowed() simplify common patterns.
  • Theme rendering is handled in route closures ($theme->render($page)) so the router itself stays framework-agnostic.

6. Exception handling #

  • The front controller wraps dispatch in the shared ExceptionHandlerInterface implementation (VelvetCMS\Exceptions\Handler).
  • Handler::report() logs errors, triggers exception.reporting, and lets custom reporters short-circuit.
  • Handler::render() fires exception.rendering and falls back to:
    • Debug mode (app.debug=true): JSON or HTML with stack traces.
    • Production: Response::error('Server Error', 500) or JSON equivalent.
  • Middleware can also intercept exceptions earlier (e.g., for API-specific formatting) by inserting before ErrorHandlingMiddleware.

7. Keep it fast in production #

  • Run velvet route:cache during deploys to dump the compiled route array and skip parsing/regex compilation on each request.
  • Pair this with opcode caching (OPcache) and HTTP asset caching headers (see config/theme.php) for best results.

That’s the entire journey: bootstrap, capture, route, middleware, handler, response. Hooks (router.*, exception.*, module boot) let you customize each segment without touching the core.