Contrôleurs
Introduction
Les contrôleurs organisent la logique de gestion des requêtes en classes dédiées,
plutôt que de définir des closures dans les fichiers de routes. Les contrôleurs
sont stockés dans app/Controllers/.
Bow prend en charge deux styles de déclaration :
- Routes définies dans
routes/app.php— les routes pointent vers un contrôleur via la syntaxeController::action(style décrit dans la majeure partie de ce document). - Routage par attributs PHP 8 — les routes sont déclarées directement sur
la classe avec
#[Controller],#[Get],#[Post], etc. (voir Routage par attributs).
Créer un contrôleur
php bow add:controller UserController
Contrôleur simple
namespace App\Controllers;
use App\Models\User;
use Bow\Http\Request;
class UserController
{
public function index()
{
$users = User::all();
return view('users/index', compact('users'));
}
public function show(Request $request, int $id)
{
$user = User::retrieve($id);
return view('users/show', compact('user'));
}
public function store(Request $request)
{
$user = User::create([
'name' => $request->get('name'),
'email' => $request->get('email'),
]);
return redirect('/users/' . $user->id);
}
}
Définir les routes
$app->get('/users', 'UserController::index');
$app->get('/users/:id', 'UserController::show');
$app->post('/users', 'UserController::store');
Injection de dépendances
Les dépendances sont automatiquement injectées dans les constructeurs et méthodes :
namespace App\Controllers;
use App\Services\PaymentService;
use App\Services\NotificationService;
use Bow\Http\Request;
class OrderController
{
public function __construct(
private PaymentService $paymentService,
private NotificationService $notificationService
) {
}
public function store(Request $request)
{
$order = $this->paymentService->processOrder(
$request->only(['product_id', 'quantity'])
);
$this->notificationService->sendOrderConfirmation($order);
return response()->json($order, 201);
}
}
Contrôleur invocable
Pour les contrôleurs à action unique, utilisez __invoke :
namespace App\Controllers;
use App\Services\DashboardService;
use Bow\Http\Request;
class ShowDashboardController
{
public function __construct(
private DashboardService $dashboard
) {
}
public function __invoke(Request $request)
{
return view('dashboard', [
'stats' => $this->dashboard->getStats(),
]);
}
}
$app->get('/dashboard', ShowDashboardController::class);
Espaces de noms
Pour les contrôleurs imbriqués, utilisez le chemin relatif :
// Contrôleur: App\Controllers\Admin\UserController
$app->get('/admin/users', 'Admin\UserController::index');
Générer un contrôleur imbriqué :
php bow add:controller Admin/UserController
Middleware
Appliquez des middlewares sur les routes :
$app->get('/profile', 'ProfileController::show')->middleware('auth');
// Plusieurs middlewares
$app->get('/admin', 'AdminController::index')->middleware(['auth', 'admin']);
Contrôleur REST
Les contrôleurs REST facilitent la création d'APIs RESTful.
Générer un contrôleur REST
php bow generate:resource ArticleController
Structure générée
namespace App\Controllers;
use Bow\Http\Request;
class ArticleController
{
/**
* GET /articles
*/
public function index(): void
{
// Liste des articles
}
/**
* POST /articles
*/
public function store(Request $request): void
{
// Créer un article
}
/**
* GET /articles/:id
*/
public function show(Request $request, mixed $id): void
{
// Afficher un article
}
/**
* PUT /articles/:id
*/
public function update(Request $request, mixed $id): void
{
// Mettre à jour un article
}
/**
* DELETE /articles/:id
*/
public function destroy(Request $request, mixed $id): void
{
// Supprimer un article
}
}
Enregistrer les routes REST
$app->rest('articles', 'ArticleController');
Routes générées
| URL | Méthode | Action | Nom |
|---|---|---|---|
/articles | GET | index | articles.index |
/articles | POST | store | articles.store |
/articles/:id | GET | show | articles.show |
/articles/:id | PUT | update | articles.update |
/articles/:id | DELETE | destroy | articles.destroy |
La méthode update est enregistrée en PUT seulement. Si vous voulez
exposer aussi PATCH (mise à jour partielle), ajoutez une route dédiée :
$app->patch('/articles/:id', 'ArticleController::update')
->where('id', '\d+');
Le nom est construit à partir de str_replace('/', '.', $url) . '.' . $action.
Avec une URL avec slash de tête comme '/api/v1/articles', vous obtiendrez
des noms comme .api.v1.articles.index (point de tête). Passez l'URL sans
slash de tête ('api/v1/articles') pour des noms propres.
Contraintes sur les paramètres
// Contrainte globale
$app->rest('articles', 'ArticleController', ['id' => '\d+']);
// Contraintes par méthode
$app->rest('articles', 'ArticleController', [
'show' => ['id' => '\d+'],
'update' => ['id' => '\d+'],
]);
Ignorer des méthodes
$app->rest('articles', [
'controller' => 'ArticleController',
'ignores' => ['destroy'],
], ['id' => '\d+']);
Contrôleurs avec attributs
Pour éviter de maintenir un fichier de routes central, vous pouvez déclarer les routes directement sur la classe avec les attributs PHP 8 :
namespace App\Controllers;
use Bow\Http\Request;
use Bow\Router\Attributes\{Controller, Get, Post, Put, Delete};
#[Controller(prefix: '/articles', middleware: ['auth'], name: 'articles.')]
final class ArticleController
{
#[Get('/', name: 'index')]
public function index() { /* ... */ }
#[Get('/:id', name: 'show', where: ['id' => '\d+'])]
public function show(Request $request, int $id) { /* ... */ }
#[Post('/', name: 'store', middleware: ['validate'])]
public function store(Request $request) { /* ... */ }
#[Put('/:id', name: 'update')]
public function update(Request $request, int $id) { /* ... */ }
#[Delete('/:id', name: 'destroy')]
public function destroy(Request $request, int $id) { /* ... */ }
}
Il suffit ensuite d'enregistrer la classe dans le fichier de routes :
$app->register(\App\Controllers\ArticleController::class);
// Ou un lot de contrôleurs
$app->register([
\App\Controllers\ArticleController::class,
\App\Controllers\CommentController::class,
]);
Le préfixe name: du #[Controller] est concaténé verbatim au nom de
chaque route — choisissez 'articles.' (avec point) pour obtenir
articles.index, articles.show, etc. Voir Routage > Routage par attributs
pour la liste complète des attributs (#[Patch], #[Options], #[Route]…).
Configuration du namespace
Personnalisez les namespaces des composants dans app/Kernel.php :
public function namespaces(): array
{
return [
'controller' => 'App\\Controllers',
'middleware' => 'App\\Middlewares',
'listener' => 'App\\Listeners',
];
}
| Clé | Utilisée par |
|---|---|
controller | Résolution 'UserController::action' → App\Controllers\UserController, php bow add:controller, generate:resource |
middleware | php bow add:middleware |
listener | php bow add:listener |
Il manque quelque chose ?
Si vous rencontrez des problèmes avec la documentation ou si vous avez des suggestions pour améliorer la documentation ou le projet en général, veuillez déposer une issue pour nous, ou envoyer un tweet mentionnant le compte Twitter @bowframework ou sur directement sur le github.