Find framework reference pages for controllers, routes, middleware, modules, database, views, and security.

Request Lifecycle

This page explains what happens between an HTTP request and the response a user receives.

Lifecycle Overview

1

Browser or API client

Sends the HTTP request.

2

Front controller

public/index.php loads the app and starts dispatch.

3

Bootstrap

Framework services, environment values, and request handling are prepared.

4

Routes

public/routes.php and app route files register URL handlers.

5

Middleware

Request gates can allow, reject, or wrap the handler.

6

Controller

The matched action coordinates the request.

7

Module or repository

App-owned logic loads data, validates input, or writes persistence.

8

View or response

The app renders HTML or returns a PSR-7 response.

Understanding this flow helps you decide where code belongs.

1. Front Controller

Requests enter through:

public/index.php

The front controller loads environment configuration, creates the container, registers framework services, starts request handling, and dispatches the router.

You normally do not edit this file for features.

2. Route Registration

Application routes start from:

public/routes.php

Small projects can keep routes there. Larger projects should split them:

$blogRoutes = PROJECT_ROOT . '/src/Routes/blog.php';
if (is_file($blogRoutes)) {
    (require $blogRoutes)($router);
}

Generate a route file with:

php coriander make:route blog

3. Middleware

Middleware runs before or around the route handler. Use it for request gates:

  • authentication
  • admin-only sections
  • API limits
  • security headers
  • CSRF protection

Example group:

use Middleware\AdminMiddleware;

$router->group('admin', [new AdminMiddleware()], function ($router): void {
    $router->get('dashboard', fn () => 'Admin dashboard');
});

Middleware should not render complex pages or perform business writes. It should decide whether the request may continue.

4. Controller

Controllers coordinate the request:

final class BlogController
{
    public function index(): void
    {
        $posts = (new BlogRepository())->latest();

        $this->view->render('blog/index', [
            'posts' => $posts,
        ]);
    }
}

Keep controllers readable. If a method becomes a long business workflow, move the workflow into a service under src/Modules.

5. Module Or Repository

Modules hold app-owned logic. Repositories hold persistence details.

namespace Modules\Blog;

use CorianderCore\Core\Database\SQLManager;

final class BlogRepository
{
    public function latest(): array
    {
        $rows = SQLManager::sqlScript(
            'SELECT id, title FROM posts ORDER BY created_at DESC LIMIT 10'
        );

        return $rows === [] ? [] : (array_is_list($rows) ? $rows : [$rows]);
    }
}

This keeps SQL out of views and keeps controllers focused on flow.

6. View Or Response

HTML pages render views from:

public/public_views/

API endpoints return JSON responses instead of HTML views.

Use views for presentation, not data loading. Escape public strings before output.

Write Request Flow

For forms and other writes, use Post/Redirect/Get:

1

POST route

Receives submitted form data.

2

Validation

Checks required fields and input shape.

3

Authorization

Confirms the current user may perform the action.

4

Write service

Writes through a service or repository.

5

Flash

Stores a one-time result message.

6

Redirect

Returns a 302 to the GET page.

This prevents browser refresh from resubmitting the form.

Debugging The Flow

When a route does not work, check in order:

1

Route file

Is the route file required by public/routes.php?

2

URL pattern

Does the pattern match the actual request?

3

Middleware

Is middleware blocking the request?

4

Controller

Is the controller method being called?

5

View

Does the controller render an existing view?

6

Module or repository

Does app-owned logic throw an exception?