Routing


In the most basic of environments the URLs of a website are given by the organization of folders and sub-folders. In this scenario, visiting the address mydomain.com/hello/world means, starting from the root of the web server, requesting the index.html (or index.php) file located at the path /hello/world.

By using the URL rewriting technique correctly it is possible to change this behavior and implement routing.

In web development, routing refers to a mechanism through which HTTP requests are mapped and routed to the code that will manage them. In short, routing determines what happens when a particular page is requested.

Declare the routes

Routes are declared in src/routes.php file.

The module file will be explored further in the section dedicated to modules.

This is an example of a route declaration. When the user visits the /hello page the message "Hello World!" will be displayed.

root/src/routes.php
router()->get("/hello", function() {
    return "Hello World!";
});

//other ways to declare a route
router()->group("/examples", function($g) {
    $g->get("/closure", function() {});
    $g->get("/string", "\App\MyController\TestController@handler_name"); //Note the @ separator
    $g->get("/string-namespace", "TestController@handler_name")->namespace(\App\MyController\TestController::class); //Note the @ separator
    $g->get("/array", [\App\MyController\TestController::class, "handler_name"]);
});

//shortcut to directly render a view, without a closure
router()->view("/about", "about");

For further information you can consult the numerous resources available on the web.

Router

As anticipated, HTTP requests are mapped and routed to the code that will manage them, this procedure is put into practice by the router. Monti router is built on top of nikic/FastRoute. You can find the complete documentation at repository. Beyond the nikic/FastRoute documentation, Monti offers additional features.

Monti custom features

Shortcut helpers

Shortcut helpers offer shortcuts to the most common operations:

  • url(): returns the URL for a named route;
  • router(): the main interface for defining routes;
  • redirect(): redirects to the given url;
  • csrf_token(): return the CSRF token;
  • csrf_input(): prints a hidden input containing the CSRF token, ready to be embedded in a <form>;
  • method_input(string $method): prints a hidden _method input, used to make an HTML form (which only supports GET/POST) submit as PUT, PATCH or DELETE;

You can find all the details by consulting the Monti API.

Named routes and URL generation

Each declared route can optionally have a unique name, which allows for easy generation of the corresponding URL, improving readability and making the code easier to maintain.

router()->get("/users", ...)->name("users_list");
url("users_list"); // /users

router()->get("/users/{id}", ...)->name("user_profile");
url("user_profile", ["id" => 1]); // /users/1

Middlewares

Middleware is an intermediate layer that sits between the client request and the server response. It receives the request, can examine or modify it, and then passes it to the next step in the chain.

After creating the middleware, you can apply it to one or more routes or to a group with the middleware method.

router()->group("users", function($g) {
    $g->get("list", "Users@list");
    $g->get("{id}", "Users@profile")->name("user_profile")->middleware(\MyNamespace\AnotherMiddleware::class);
})->middleware(\MyNamespace\ToMiddleware\UserIsAuthenticated::class);

You can apply multiple middlewares by chaining the middleware method multiple times. The middlewares will be executed in order from outermost to innermost. In the example above, the UserIsAuthenticated middleware will be applied to the user_profile route first, followed by the AnotherMiddleware middleware.

Read more about middlewares in the dedicated section.

Namespace

The namespace is particularly useful when the route handler is declared in the Controller@method format; it allows you to write the controller without having to specify the entire namespace. It's particularly useful for grouped routes and can be applied to both individual routes and the entire group.

router()->group("users", function($g) {
    $g->get("list", "Users@list");
    $g->get("{id}", "Users@profile");
})->namespace(\MyNamespace\ToClass\Users::class);

More responses types handling

A route can return more than a View: strings, models, arrays, collections, stdClass objects and booleans are all converted to a proper HTTP response automatically. See the Request & Response documentation for the complete list, with an example for each type.

CSRF protection (Cross-Site Request Forgery)

CSRF protection is a security measure that prevents attackers from exploiting a user's authenticated session to perform unauthorized actions. It is essential because it protects web applications from invisible manipulations that could compromise sensitive data or transactions.

To combat this phenomenon, every request that modifies the state (e.g., POST or PATCH requests) must include a unique and unpredictable token, the CSRF Token (or Anti-CSRF). The server verifies that the token is valid and belongs to the user's session, ensuring that only intentional requests from the user are executed.

Use csrf_input() inside a <form> to print the hidden field the verifier expects:

<form method="POST" action="...">
    <?php csrf_input(); ?>
    ...
</form>

HTML forms only support GET and POST. To send a PUT, PATCH or DELETE request from a form, submit it as POST and add a spoofed _method field with method_input() — the router reads it and dispatches to the matching route:

<form method="POST" action="...">
    <?php csrf_input(); ?>
    <?php method_input("PATCH"); ?>
    ...
</form>
The CSRF token is always verified against the real HTTP method the request was sent with (POST, in the example above), not the spoofed one — method_input() only affects routing, the CSRF check is unaffected.

By default, all routes are checked for the CSRF token. You can exclude a URL using the static addCSRFException method of the \App\System\Router\Router class.

\App\System\Router\Router::addCSRFException("/some/url");
//include all URLs that begin with "some/url"
\App\System\Router\Router::addCSRFException("/some/url/*");

For further information you can consult the nikic/FastRoute repository and Monti API.