⬡ Lacelium
⌘K
Version 2.x ▾

Request Lifecycle & Architecture Concepts

Introduction

When using any tool in the "real world", you feel more confident if you understand how that tool works. Application development is no different. When you understand how your framework components work together under the hood, you feel more comfortable and confident using them.

The goal of this document is to give you a high-level overview of how the Lacelium framework works. By getting to know the overall framework better, everything will feel less "magical" and you will be more confident building your applications.

Request Lifecycle Overview

First Steps

The entry point for all requests to a Lacelium application is the public/index.php file. All requests are directed to this file by your web server (Apache or Nginx) configuration.

The index.php file doesn't contain much code. Rather, it is a starting point for loading the rest of the framework. The index.php file loads the Composer generated autoloader definition, and then retrieves an instance of the Lacelium application kernel from src/Core/App.php.

HTTP Kernel & Environment

Next, the incoming request is captured using Symfony's Request::createFromGlobals(). The application kernel boots the environment variables via Dotenv, registers error and exception handlers with Monolog, and configures the default timezone and localization settings.

Service Container & Autowiring

Lacelium uses PHP-DI for automated dependency injection. When a controller or service is instantiated, the container inspects its constructor parameters and automatically instantiates and injects any required dependencies.

namespace App\Http\Controllers;

use App\Services\BillingService;
use Psr\Log\LoggerInterface;

class OrderController extends BaseController
{
    // The container automatically resolves and injects BillingService and Logger:
    public function __construct(
        private BillingService $billing,
        private LoggerInterface $logger
    ) {}
}

Routing & Middleware Pipeline

Once the application is bootstrapped, the HTTP request is passed to the router. The router evaluates the request URI against the route definitions in config/routes.php.

Before reaching the controller, the request traverses the middleware pipeline. Middleware provides a convenient mechanism for inspecting and filtering HTTP requests entering your application. For example, Lacelium includes middleware for verifying CSRF tokens, managing user sessions, and enforcing maintenance mode.

Controller Execution & Response

If the request passes through all assigned middleware, the controller method or route closure is executed. The controller typically performs business logic, queries database models, and returns an HTTP Response object (such as a rendered Twig template or a JsonResponse):

public function index(Request $request): Response
{
    $tasks = Task::all();

    return $this->render('tasks/index.twig', [
        'tasks' => $tasks,
    ]);
}

Response Streaming & Termination

Finally, the $response->send() method sends the HTTP status codes and headers to the browser, followed by the content body. Any registered terminable middleware or background shutdown handlers are then executed.

Core Architecture Principles

  • Decoupled Components: Each subsystem (Cache, Routing, Storage, Database) can be used independently or mocked during automated tests.
  • Service-Oriented Design: Keep controllers slim by placing complex business logic into dedicated service classes in app/Services/.
  • Predictable Conventions: Consistent directory structures and naming patterns ensure any developer familiar with modern PHP can navigate your project immediately.

Next Steps