Routing
Définissez les URLs de votre application dans roads.php.
Définition de base
Les routes sont définies dans le fichier roads.php à la racine du projet.
use River\Router;
return function(Router $router) {
// Route GET simple
$router->get('/', 'App\Controllers\Home::index');
// Autres méthodes HTTP
$router->post('contact', 'App\Controllers\Contact::send');
$router->put('users/{id}', 'App\Controllers\User::update');
$router->delete('users/{id}', 'App\Controllers\User::delete');
};
Paramètres de route
Vous pouvez capturer des segments de l'URL avec des accolades {param}.
$router->get('blog/{id}', 'App\Controllers\Blog::show');
Dans votre contrôleur, vous récupérez ces paramètres via $this->param('id').
Contraintes (Regex)
Vous pouvez restreindre le format des paramètres avec where() :
$router->get('blog/{id}', 'App\Controllers\Blog::show')
->where('id', '\d+'); // Uniquement des chiffres
$router->get('users/{name}', 'App\Controllers\User::profile')
->where('name', '[a-z-]+'); // Lettres et tirets
Routes Nommées
Nommer vos routes permet de générer des URLs sans dépendre du chemin "en dur".
$router->get('admin/dashboard', 'App\Controllers\Admin::index')
->name('admin.dashboard');
$router->get('blog/{id}', 'App\Controllers\Blog::show')
->where('id', '\d+')
->name('blog.show');
Génération d'URL
$this->url() est disponible à la fois dans les controllers et les templates :
// Dans un controller
return $this->redirect($this->url('admin.dashboard'));
$url = $this->url('blog.show', ['id' => 42]); // → /blog/42
// Dans un template
<a href="<?= $this->url('admin.dashboard') ?>">Dashboard</a>
<a href="<?= $this->url('blog.show', ['id' => $post['id']]) ?>">Lire</a>
$this->url() directement dans les templates pour les liens HTML.
Réservez la génération dans le controller pour les redirections et la logique métier.
Middleware de Route
Vous pouvez appliquer un middleware spécifique à une route :
$router->get('profile', 'App\Controllers\User::profile')
->middleware(App\Middleware\Auth_middleware::class);
Groupes de Routes
Regroupez des routes qui partagent un même préfixe, namespace ou middleware :
$router->group([
'prefix' => 'admin',
'namespace' => 'App\Controllers\Admin',
'middleware' => River\Middleware\Role_middleware::class . ':admin',
], function($r) {
$r->get('users', 'Users_ctrl::index') ->name('admin.users');
$r->get('users/create', 'Users_ctrl::create')->name('admin.users.create');
$r->post('users', 'Users_ctrl::store') ->name('admin.users.store');
$r->get('users/{id}', 'Users_ctrl::show') ->where('id', '\d+')->name('admin.users.show');
$r->post('users/{id}', 'Users_ctrl::update')->where('id', '\d+');
});
| Option | Effet |
|---|---|
prefix | Préfixe URL ajouté à tous les chemins du groupe |
namespace | Namespace PHP préfixé sur les noms de controllers courts |
middleware | Middleware appliqué à toutes les routes du groupe |
Routes par Attributs PHP
Pour les controllers avec de nombreuses routes, déclarez-les directement sur les méthodes avec des attributs PHP 8. Plus besoin de synchroniser roads.php et le controller.
#[Route] — sur une méthode
use River\Attributes\Route;
use River\Attributes\Route_prefix;
#[Route_prefix(prefix: 'admin', middleware: [Role_middleware::class . ':admin,sysadmin'])]
class Users_ctrl extends Controller
{
#[Route('GET', 'users', name: 'admin.users')]
public function index(): Response { ... }
#[Route('GET', 'users/create', name: 'admin.users.create')]
public function create(): Response { ... }
#[Route('POST', 'users', name: 'admin.users.store')]
public function store(): Response { ... }
#[Route('GET', 'users/{id}', name: 'admin.users.show', where: ['id' => '\d+'])]
public function show(): Response { ... }
#[Route('POST', 'users/{id}', where: ['id' => '\d+'])]
public function update(): Response { ... }
}
Dans roads.php, une seule ligne remplace tout le groupe :
// Avant (group manuel)
$router->group(['prefix' => 'admin', ...], function($r) {
$r->get('users', 'Users_ctrl::index')->name('admin.users');
// ... 6 routes de plus
});
// Après (scan automatique)
$router->scan_controller(\App\Controllers\Admin\Users_ctrl::class);
Paramètres de #[Route]
| Paramètre | Type | Description |
|---|---|---|
method | string | Méthode HTTP : 'GET', 'POST', 'PUT', 'DELETE', 'PATCH' |
path | string | Chemin relatif (sans le préfixe du Route_prefix) |
name | string | Nom de la route pour $this->url() (optionnel) |
where | array | Contraintes regex sur les paramètres : ['id' => '\d+'] |
middleware | string|array | Middleware spécifique à cette route (optionnel) |
Paramètres de #[Route_prefix]
| Paramètre | Type | Description |
|---|---|---|
prefix | string | Préfixe URL commun à toutes les routes du controller |
middleware | string|array | Middleware appliqué à toutes les routes du controller |
Plusieurs routes sur la même méthode
#[Route] est répétable : une même méthode peut répondre à plusieurs verbes HTTP.
#[Route('GET', 'resource', name: 'resource.get')]
#[Route('POST', 'resource', name: 'resource.post')]
public function handle(): Response { ... }
Coexistence avec les routes manuelles
scan_controller() est 100% compatible avec les routes déclarées manuellement. Les deux approches peuvent cohabiter dans le même roads.php.
return function(Router $router) {
// Routes manuelles classiques
$router->get('/', 'App\Controllers\Main_ctrl::index')->name('home');
// Controllers déclarés via attributs
$router->scan_controller(\App\Controllers\Admin\Users_ctrl::class);
$router->scan_controller(\App\Controllers\Admin\Products_ctrl::class);
};
roads.php restent plus lisibles.