Routes

Controllers

Controllers are classes that are responsible for returning Centum\Interfaces\Http\ResponseInterface objects. When a user visits a URL or submits a form, the Router will direct the request to the appropriate Controller method, which will then generate and return a Response.

Controllers must implement Centum\Interfaces\Router\ControllerInterface.

A Controller can be as simple as the following example, which returns plain text:

namespace App\Web\Controllers;

use Centum\Http\Response;
use Centum\Interfaces\Http\ResponseInterface;
use Centum\Interfaces\Router\ControllerInterface;

class LoginController implements ControllerInterface
{
    public function form(): ResponseInterface
    {
        return new Response("this is the login page");
    }
}

However, Controllers can do far more: they can use dependency injection to receive services, apply filters and middlewares, and perform tasks such as form validation. These advanced features will be explained in later sections, but it is important to know that these things are possible.

Centum\Http\Response\HtmlResponse can be used for HTML responses and Centum\Http\Response\JsonResponse can be used for JSON responses.

Route Groups

Routes are not added to the Router directly. Instead, to keep the Router class simple and organised, Routes are stored inside Group objects. Grouping routes together helps you organise related routes (for example, all the routes for user accounts or all the routes for an admin area).

Centum\Router\Group implements Centum\Interfaces\Router\GroupInterface.

You can create a new group using the group() method on the Router:

use Centum\Interfaces\Router\RouterInterface;

/** @var RouterInterface $router */

$group = $router->group();

Each group can contain as many routes as you want, and using groups allows you to apply middlewares to every route inside that group at once. We will go deeper into this in the Middlewares section.

HTTP Methods

When defining a route, you must tell the Router which HTTP method the route should respond to. This ensures that different kinds of requests (like viewing a page versus submitting data) are correctly separated. The standard HTTP methods are defined in RFC 7231 and RFC 5789.

Each of these methods has a corresponding method on the Group object:

HTTP Method Group Method
GET $group->get($uri, $class, $method)
POST $group->post($uri, $class, $method)
HEAD $group->head($uri, $class, $method)
PUT $group->put($uri, $class, $method)
DELETE $group->delete($uri, $class, $method)
TRACE $group->trace($uri, $class, $method)
OPTIONS $group->options($uri, $class, $method)
CONNECT $group->connect($uri, $class, $method)
PATCH $group->patch($uri, $class, $method)

For example, if we want to display a login form at /login using the form() method from our LoginController, we would add a GET route for it like this:

use App\Web\Controllers\LoginController;

$group->get("/login", LoginController::class, "form");

Same URL, Different Methods

It is common to have the same URL respond differently based on the HTTP method. A typical example is having a login page that displays a form on GET /login and processes the submitted form data on POST /login.

Here is a controller that handles both cases:

namespace App\Web\Controllers;

use Centum\Http\Response;
use Centum\Interfaces\Http\ResponseInterface;
use Centum\Interfaces\Router\ControllerInterface;

class LoginController implements ControllerInterface
{
    public function form(): ResponseInterface
    {
        return new Response("This is a GET request.");
    }

    public function submit(): ResponseInterface
    {
        return new Response("This is a POST request.");
    }
}

And here is how you would register both routes with the Router:

use App\Web\Controllers\LoginController;

$group->get("/login", LoginController::class, "form");
$group->post("/login", LoginController::class, "submit");

When the user visits /login with a GET request, the form() method will run. When the user submits the form with a POST request to /login, the submit() method will run.

There is also a shorthand method called submission() for this common pattern. It assumes your controller uses the form() and submit() method names:

use App\Web\Controllers\LoginController;

$group->submission("/login", LoginController::class);

Precedence

Routes are processed in the order they are added. This means the Router will check the first route you defined, then the second, and so on, stopping at the first route that matches the incoming request.

For example, in this code, the GET / request will always match AController because it is defined before BController:

$group->get("/", AController::class, "index");
$group->get("/", BController::class, "index");

Be careful not to accidentally define duplicate routes, as the later ones will never run.

Trailing Slashes

Centum automatically removes trailing slashes from incoming request URLs. This means that requests to /login and /login/ will be treated as the same route (/login). Because of this, you should always define your route URIs without a trailing slash (unless the route is simply /).