Créer un controller Laravel : le guide ultime

Avatar de Benjamin Crozat.

Publié le par Benjamin Crozat

Temps de lecture estimé : 7 minutes

Les controllers sont essentiels dans Laravel. Découvrons la commande "php artisan make:controller", ses variations et créons ensemble un CRUD.

Qu’est-ce qu’un controller ?

Si vous avez lu et suivi le tutoriel “Le routing avec Laravel : créez votre première route”, vous avez alors écrit le code associé à votre route dans une fonction anonyme.

Imaginez avoir une centaine de routes ayant chacune une dizaine de lignes de code. Cela peut vite devenir un sacré bordel n’est-ce pas ? 😅 Heureusement, nous pouvons extraire tout cela dans des controllers !

Créez un controller basique avec php artisan make:controller

Créer un controller sous sa forme la plus simple se fait grâce à la commande suivante :

php artisan make:controller PostController

Rendez-vous dans app/Http/Controllers et ouvrez PostController.php afin de voir à quoi cela ressemble.

namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
class PostController extends Controller
{
//
}

Bien entendu, il est possible de gagner plus de temps en générant des controllers plus complexes.

Les controllers invokables

Les controllers invokables sont extrêmement utiles. Admettons que vous scindiez chacune de vos actions CRUD (Create, Read, Update et Delete) dans un controller unique. Au lieu de créer, par exemple, une méthode store dans votre controller StorePostController, vous pourriez plutôt utiliser la méthode magique __invoke de PHP.

Créons un controller invokable :

php artisan make:controller StorePostController --invokable

Constatons le changement dans le controller nouvellement créé.

namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
 
class StorePostController extends Controller
{
/**
* Handle the incoming request.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function __invoke(Request $request)
{
//
}
}

Ensuite, dans votre fichier routes/web.php, vous pouvez faire pointer la route vers votre controller :

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\StorePostController;
 
-Route::post('/posts', [StorePostController::class, 'store']);
+Route::post('/posts', StorePostController::class);

Pratique, n’est-il pas ? 🇬🇧

Les controllers de ressources

Selon vos préférences, vous aurez peut-être envie de regrouper toutes vos méthodes CRUD pour un modèle donné dans un seul controller.

Ne bougez pas, Laravel assure vos arrières !

php artisan make:controller PostController --resource

Ce qui donnera :

namespace App\Http\Controllers;
 
use App\Models\Post;
use Illuminate\Http\Request;
 
class PostController extends Controller
{
 
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
 
/**
* Display the specified resource.
*
* @param \App\Models\Post $post
* @return \Illuminate\Http\Response
*/
public function show(Post $post)
{
//
}
 

Notez que Laravel aura automatiquement deviné quel modèle nous souhaitons utiliser, car il existe déjà et nous respectons les conventions de nommage et d’organisation du framework.

Bien entendu, il est possible de spécifier le chemin vers votre modèle manuellement dans le cas où votre projet aurait une structure plus exotique.

php artisan make:controller PostController --resource --model="App\Model\Post"

Les controllers de ressources d’API (RESTful)

Pour celles et ceux qui développent une API RESTful, sachez que vous pouvez complètement omettre les méthodes create et edit de votre CRUD. En effet, celles-ci servent essentiellement à présenter des formulaires. Formulaires complètement inutiles dans cette circonstance.

php artisan make:controller PostController --api

Les controllers de ressources enfants

Imbriquer vos ressources est une bonne pratique et vous fera également économiser quelques lignes de code.

Disons que nous avons des commentaires associés à chaque post.

use Illuminate\Support\Facades\Route;
 
Route::resource('posts.comments');

Nous pouvons générer en une seule commande un controller prenant en compte cette spécificité.

php artisan make:controller CommentController --resource --parent="App\Model\Post"
namespace App\Http\Controllers;
 
use App\Model\Comment;
use App\Models\Post;
use Illuminate\Http\Request;
 
class CommentController extends Controller
{
 
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Post $post
* @param \App\Model\Comment $comment
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Post $post, Comment $comment)
{
//
}
 
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Post $post
* @param \App\Model\Comment $comment
* @return \Illuminate\Http\Response
*/
public function destroy(Post $post, Comment $comment)
{
//
}
}

Passez à la pratique, créez votre propre CRUD

Maintenant que nous nous sommes amusés avec les commandes Artisan, passons à la pratique et créons un CRUD pour des articles de blog que nous appellerons “posts”.

Créez le modèle et la migration

Première étape, générer les fichiers pour notre modèle et notre migration à avec Artisan :

php artisan make:model Post -m

Exécutons la migration afin de mettre à jour la structure de notre base de données :

php artisan migrate

Créez le contrôleur

Créons un contrôleur de type ressource, associé au modèle nouvellement généré :

php artisan make:controller PostController --resource --model=Post

Créez les routes correspondant au CRUD (Create, Read, Update, Delete)

Laravel encore une fois nous fait gagner un temps considérable en ayant tout prévu. Il nous permet de créer toutes les routes qui permetteront à notre application de gérer les posts en une seule ligne de code.

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
 
Route::resource('posts', PostController::class);

Je vous invite ensuite à utiliser la commande suivante afin de bien vérifier que les routes soient présentes :

php artisan route:list

Créez les vues Blade du CRUD

Il n’y a pas de commandes Artisan officielles pour créer des vues. Mais peu importe. Si vous êtes sur un système Unix, voici la parade :

touch resources/views/posts/{index,show,create,edit}.blade.php

Pratique n’est-ce pas ? 🪄

Limitez les utilisateurs avec une policy

Une fois la policy générée :

php artisan make:policy PostPolicy --model=Post

Allons dans notre contrôleur afin de l’utiliser automatiquement sur toutes les méthodes :

namespace App\Http\Controllers;
 
use App\Models\Post;
 
class PostController extends Controller
{
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
 
 
public function create()
{
return view('posts.create');
}
 
}

Afin de tester l’effet de la policy, nous pourrions simplement changer la méthode create() et renvoyer false.

namespace App\Policies;
 
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
 
class PostPolicy
{
use HandlesAuthorization;
 
 
public function create(User $user)
{
return false;
}
 
}

Enfin, rendez-vous sur votre navigateur et constatez que nous recevons bien un code HTTP 403 (ou 401 si vous n’avez pas encore ajouté à votre app la possibilité d’avoir un compte utilisateur).

Bonus : pour des raisons de sécurité accrue, nous pouvons aussi prétendre que la route n’existe tout simplement pas en renvoyant 404 plutôt que 403 (le comportement par défaut des policies).

namespace App\Policies;
 
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
 
class PostPolicy
{
use HandlesAuthorization;
 
 
public function create(User $user)
{
return $this->denyAsNotFound();
}
 
}

Oups, j’ai failli oublier. Comment faire en sorte qu’un utilisateur privilégié passe outre les restrictions que nous venons de mettre en place ? Là aussi, il y a une méthode pour ça. Ajoutez les lignes suivantes dans votre policy :

namespace App\Policies;
 
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
 
class PostPolicy
{
use HandlesAuthorization;
 
public function before(User $user, $ability)
{
if ($user->email === 'montgomery@burns.com') {
return true;
}
}
 
}

0 commentaire

Besoin d'aide ? Envie de partager ?
Inscrivez-vous ou connectez-vous d'abord.

Ça vous a plu ?
Abonnez-vous à la newsletter !

Recevez régulièrement news, trucs et astuces à propos de Laravel et son ecosystème.

Autres articles à lire