Skip to content

Request Lifecycle

This document traces the complete lifecycle of an HTTP request handled by Alxarafe, from the entry point (index.php) to the rendered response.

Sequence Diagram

mermaid
sequenceDiagram
    participant Client
    participant index.php
    participant Dispatcher
    participant WebDispatcher
    participant Routes
    participant Controller
    participant ViewTrait
    participant Blade
    
    Client->>index.php: HTTP Request
    index.php->>Dispatcher: Dispatcher::run()
    
    Note over Dispatcher: initializeConstants()<br/>ALX_PATH, APP_PATH,<br/>BASE_PATH, BASE_URL
    
    Dispatcher->>Dispatcher: Trans::initialize()
    
    alt URL contains /index.php/api/
        Dispatcher->>Dispatcher: ApiDispatcher::run()
        Note over Dispatcher: API lifecycle (see API docs)
    else Standard web request
        Dispatcher->>WebDispatcher: run(module, controller, method)
    end
    
    WebDispatcher->>WebDispatcher: Debug::initialize()
    WebDispatcher->>Routes: Routes::getAllRoutes()
    
    Note over Routes: Scans Modules\\<br/>namespaces for<br/>*Controller.php files
    
    Routes-->>WebDispatcher: route map
    WebDispatcher->>WebDispatcher: Resolve className from route
    WebDispatcher->>WebDispatcher: Load config, theme, language
    WebDispatcher->>WebDispatcher: Check Auth user preferences
    
    WebDispatcher->>Controller: new ControllerClass()
    
    Note over Controller: GenericController::__construct()<br/>→ Build menus<br/>→ Boot traits (initTraitName)
    Note over Controller: ViewController::__construct()<br/>→ Load config<br/>→ Register template paths<br/>→ Set language
    Note over Controller: Controller::__construct()<br/>→ Auth check (isLogged)<br/>→ Module activation check<br/>→ Authorization check (can)
    
    WebDispatcher->>Controller: setTemplatesPath(paths[])
    WebDispatcher->>Controller: $controller->index()
    
    Controller->>Controller: executeAction()
    
    Note over Controller: Resolve action from<br/>$_GET['action'] or $_POST['action']<br/>Build method name: do{Action}
    
    Controller->>Controller: beforeAction()
    Controller->>Controller: doAction()
    Controller->>Controller: afterAction()
    
    Note over Controller: afterAction() calls<br/>Messages::getMessages()<br/>then $this->render()
    
    Controller->>ViewTrait: render()
    ViewTrait->>Blade: Compile & render template
    Blade-->>Client: HTML Response

Phase 1: Bootstrap (index.php)

The web server directs all requests to public/index.php. A typical entry point:

php
<?php
// public/index.php
require_once __DIR__ . '/../vendor/autoload.php';

define('BASE_PATH', __DIR__);

use Alxarafe\Tools\Dispatcher;

Dispatcher::run();

Alternatively, applications may use WebDispatcher::dispatch() directly for more control:

php
<?php
require_once __DIR__ . '/../vendor/autoload.php';

define('BASE_PATH', __DIR__);

use Alxarafe\Tools\Dispatcher\WebDispatcher;

WebDispatcher::dispatch('MyModule', 'Home', 'index');

Phase 2: Initialization (Dispatcher::run())

Dispatcher::run() performs two initialization steps:

2a. Constant Definition

php
// Dispatcher::initializeConstants()
ALX_PATH  = realpath(__DIR__ . '/../../..')     // Framework root
APP_PATH  = realpath(ALX_PATH . '/../../..')    // Application root
BASE_PATH = APP_PATH . '/public'               // Document root
BASE_URL  = Functions::getUrl()                 // Auto-detected URL

2b. Translation System

php
Trans::initialize();  // Loads YAML language files from src/Lang/

2c. Routing Fork

The dispatcher inspects $_SERVER['PHP_SELF'] for the pattern /index.php/api/:

  • API requestsApiDispatcher::run($controllerPath) → JSON response
  • Web requestsWebDispatcher::run($module, $controller, $method) → HTML response

The module, controller and method are extracted from $_GET parameters:

  • module defaults to 'Admin'
  • controller defaults to 'Info'
  • method defaults to 'index'

Phase 3: Route Resolution (WebDispatcher::run())

3a. Debug Initialization

php
Debug::initialize();  // Sets up DebugBar if in debug mode

3b. Route Discovery

php
$routes = Routes::getAllRoutes();
$endpoint = $routes['Controller'][$module][$controller];
// e.g. "Modules\Admin\Controller\HomeController|/path/to/HomeController.php"

Routes::getAllRoutes() scans two namespace roots:

RootNamespaceAlways Active
src/Modules/Modules\Yes
APP_PATH/Modules/Modules\Checked via Setting table

For each module directory, it discovers:

  • Controller/*Controller.php → Web controllers
  • Api/*Controller.php → API controllers
  • Migrations/*.php → Database migrations
  • Seeders/*.php → Data seeders
  • Model/*.php → Eloquent models

3c. Friendly URL Matching

Before falling back to $_GET parameters, WebDispatcher::dispatch() first attempts Router::match() against the request URI for friendly URLs.

3d. Theme & Language Resolution

The theme and language are resolved in priority order:

  1. Cookie (alx_theme, alx_lang) — highest priority
  2. Authenticated user preferences (Auth::$user->getTheme(), Auth::$user->language)
  3. Config file (config.json → main.theme, main.language)
  4. Default ('default' theme, 'en' language)

Phase 4: Controller Instantiation

The resolved class is instantiated. The constructor chain runs bottom-up through the inheritance hierarchy:

4a. GenericController::__construct()

  1. Action resolution: $action = $action ?? $_POST['action'] ?? $_GET['action'] ?? 'index'
  2. Menu building: ModuleManager::getArrayMenu() for top menu, MenuManager::get('admin_sidebar') for sidebar
  3. Back URL: Auto-set if action ≠ 'index'
  4. Trait boot: For each trait, call init{TraitName}() if it exists

4b. ViewController::__construct()

  1. Config load: Config::getConfig()
  2. Template path registration: App templates → Theme templates → Framework templates
  3. Language init: Trans::setLang()
  4. Variable injection: $me = controller instance, main_menu, user_menu

4c. Controller::__construct()

  1. Authentication: Auth::isLogged() — redirects to login if not
  2. Module activation: MenuManager::isModuleEnabled() — blocks disabled modules
  3. Authorization: Auth::$user->can($action, $controller, $module) — checks permissions
  4. Username: Sets $this->username from authenticated user

4d. Template Path Setup

After instantiation, WebDispatcher sets the template search order:

php
$templates_path = [
    APP_PATH . '/templates/themes/{theme}/',       // Theme override (App)
    ALX_PATH . '/templates/themes/{theme}/',       // Theme override (Package)
    APP_PATH . '/Modules/{Module}/templates/',     // Module templates (App)
    ALX_PATH . '/src/Modules/{Module}/Templates/', // Module templates (Package)
    APP_PATH . '/templates/',                       // App general templates
    ALX_PATH . '/templates/',                       // Framework default templates
];

Phase 5: Action Execution

5a. Method Call

WebDispatcher calls $controller->index() (or the resolved method).

5b. GenericController::index()executeAction()

  1. Permission re-check for the specific action
  2. Method resolution: 'do' . ucfirst(Str::camel($this->action)) — e.g., action='create'doCreate()
  3. Hook chain:
    • beforeAction() — override for pre-processing
    • doAction() — the actual business logic
    • afterAction() — post-processing and rendering

5c. Return Convention

Each method in the chain returns bool. If any returns false, the chain short-circuits:

php
return $this->beforeAction()
    && $this->$actionMethod()
    && $this->afterAction();

Phase 6: Rendering

6a. ViewController::afterAction()

php
public function afterAction(): bool
{
    $this->alerts = Messages::getMessages();
    echo $this->render();
    return true;
}

6b. Template Resolution

ViewTrait::render() resolves the Blade template name from the controller:

  • Convention: page/{controller_name} (lowercase, snake_case)
  • Example: HomeControllerpage/home

6c. Blade Compilation

The BladeContainer compiles and renders the template with all injected variables ($me, $main_menu, $user_menu, $alerts, etc.).

Phase 7: Error Handling

The entire dispatch is wrapped in a try/catch:

  1. First failure → Redirect to ErrorController::url() with message and trace
  2. Second failure (anti-loop guard) → Render raw HTML error page directly
  3. Emergency fallbackhttp_response_code(500) with minimal styled error

Summary Table

PhaseClassKey Method
Bootstrapindex.phpDispatcher::run()
InitDispatcherinitializeConstants(), Trans::initialize()
RouteWebDispatcherrun(), Routes::getAllRoutes()
InstantiateController hierarchy__construct() chain
ExecuteGenericControllerexecuteAction()beforeAction()doAction()afterAction()
RenderViewController / ViewTraitafterAction()render()
ErrorWebDispatcherdieWithMessage()ErrorController