Catégories
Dev

CRUD sur Laravel 8

Ca veut dire quoi CRUD ? A quoi ça sert et comment ça marche? J’essayerai de vous expliquer tout ça de manière détaillée pour que tout le monde puisse comprendre. Je vais donc expliquer dans un premier temps ce terme étrange, puis je vous proposerais un peu de pratique en faisant un petit site rapide.

CRUD ? Qu’est-ce que c’est?

CRUD et l’acronyme de Create Read Update Delete, en français : créer, lire, mettre à jour et supprimer. Ce sont les fonctions de base de gestion lorsqu’on veut créer un site. Ces actions sont nécéssaire pour tout traitement de donnée. Mettre en place un CRUD dans un site signifie donc avoir ces 4 fonctions.

Qui dit données, dit base de donnée. Ces fonctions sont donc associé à des commandes SQL et on pourrait définir un certain ordre à ces fonctions :

  • La fonction Create est la première action à être effectuer car on ne peux ni lire, ni modifier, ni supprimer quelque chose que l’on a pas. Elle s’effectue grâce à la commande SQL : INSERT. Bien évidement, vous n’utiliserais pas cette commande si vous rentrez vos données manuellement ligne par ligne, colonne par colonne dans votre base de donée.
  • La fonction Read est très souvent ce que l’on fais juste après avoir créer une donnée. Read correspond à la fonction SQL : SELECT. Elle permet tout simplement d’afficher les données.

Vous créez une donnée et en la lisant vous vous rendez compte que vous avez fais une erreur. Deux solutions s’offrent à vous : supprimer la donnée et en recréer une nouvelle ( un peu radical et sauvage ), ou tout simplement la modifier :

  • La fonction Update s’effectue avec la commande SQL UPDATE et viens souvent juste après Read.
  • Et pour finir, Delete qui s’effectue avec DELETE en SQL. Une fois supprimée, la donnée ne peut être récupérer. Sauf dans le cas du soft delete qui fonctionne un peu comme une corbeille. C’est ce que nous utiliserons dans la partie pratique.

Voilà, vous savez désormais ce que veux dire CRUD et en quoi ça consiste.

Mise en pratique

Je vais donc passer à la partie pratique de ce article en vous proposant de créer un site qui permettra de créer, modifier ou supprimer des données. Pour le création de ce site je vais utiliser Bootstrap pour le style, fontawesome pour les îcones et jQuery pour le script. Vous pouvez utiliser les CDN ou les télécharger.

Pour ceux qui n’ont pas Laravel, vous pouvez l’obtenir en suivant la démarche sur cet article.

Pour créer le projet, rentrez dans le terminal :

composer create-project --prefer-dist laravel/laravel MonprojetLaravel

Pour créer un URL :

cd MonprojetLaravel
valet link crudlaravel
valet secure crudlaravel

Votre pourrez voir votre projet avec l’url « crudlaravel.test » .

Conception d’un site avec un CRUD

Laravel utilise un développement en MVC. Nous devons donc créer notre Controller :

php artisan make:controller FilmController

Puis notre Model :

php artisan make:model Film

Vous pouvez Maintenant créer une base de donnée avec les colonnes suivantes : id, affiche, titre, genre, description, created_at, updated_at, deleted_at.

Grâce à Laravel, nous n’aurons pas à créer chaque routes les unes après les autres pour chaque fonctions. Ce sera un gain de temps plutôt minime mais si ça existe, pourquoi se priver ? Nous pouvons donc écrire ceci dans le fichier routes/wep.php :

Route::resource('films', '\App\Http\Controllers\FilmController');

Voilà ! Vos routes principales sont crées.

Tout est en place, il ne reste plus qu’à développer !

Commençons par le Controller avec notre première fonction :

Create

Nous allons créer un formulaire pour créer un nouveau film. Je vais donc commencer par le Controller comme d’habitude :

    public function create(Request $request) {
        $genres = \App\Models\Film::distinct()->get(["genre"]);

        return view('film.create', compact('genres'));
    }
   public function store(Request $request) {
        $film = new \App\Models\Film();
        $film->affiche = $request->input('insertAffiche');
        $film->titre = $request->input('insertTitre');
        $film->genre = $request->input('insertGenre');
        $film->description = $request->input('insertDescription');
        $film->save();

        return redirect('/films/');
    }        
}

Lorsque l’on veut créer une donnée, on la « stock ». C’est pour ça que c’est notre fonction store qui contient touts les variables qui vont créer le nouvel objet. La fonction create, elle, sert envoyer les variables dont nous auront besoin dans la vue create. Je ne vais donc pas m’attarder dessus.

Par contre pour ce qui est de la fonction store :

  • $film = new \App\Models\Film(); signifie que nous voulons créer une nouvelle instance de l’objet Film. Chaque lignes de votre base de donnée est une instance de l’objet Film.
  • Ensuite, $film->affiche indique au programme où il va devoir stocker la valeur qu’on va lui donner. $film->titre contiendra le titre; $film->genre contiendra le genre …
  • $request-> ici, request est le paramètre que nous avons donner à la fonction. Il va nous servir pour récupérer ce que nous allons rentrer dans notre formulaire.
  • input('insertAffiche') correspond au champ du formulaire de notre vue qui possède comme propriété name="insertAffiche". C’est le même fonctionnement pour toutes les autres variables.
  • Puis, $film->save(); indique que la saisie de donnée est terminée et qu’il faut donc insérer tout ça dans la base de donnée. save() est une fonction prédéfinie.
  • Pour finir l’explication de cette fonction, vous aurez constater que nous avons mis return redirect et non return view C’est parce qu’une fois le formulaire envoyé, nous voulons être redirigé sur la page index pour vérifier que tout c’est bien passé comme prévu.

Maintenant que nous avons le Controller, la vue:

<form method="POST" action="/films/">
    @csrf
    <div class="form-row">
        <div class="col-md-4 mb-3">
            <label for="insertTitre">Titre</label>
            <input type="text" name="insertTitre" class="form-control" id="insertTitre" placeholder="Titre du film" required>
        </div>
        <div class="col-md-4 mb-3">
            <label for="insertGenre">Genre</label>
            <select id="insertGenre" name="insertGenre" class="form-control">
                <option selected>Choisir...</option>
                @foreach($genres as $genre)
                    <option value="{{$genre->genre}}">{{$genre->genre}}</option>
                @endforeach
            </select>
        </div>
    </div>
    <div class="form-row">
        <div class="col mb-3">
            <div class="custom-file">
                <input type="file" name="insertAffiche" class="custom-file-input" id="insertAffiche" required>
                <label class="custom-file-label" for="insertAffiche" >Choose file</label>
            </div>
        </div>
    </div>
    <div class="form-row">
        <div class="col mb-3">
            <label for="insertDescription">Résumé du film</label>
            <textarea name="insertDescription" class="form-control" id="insertDescription" rows="5" required></textarea>
        </div>
    </div>
    <button class="btn btn-primary" type="submit">Créer !</button>
</form>

C’est un formulaire comme vous en trouverez plein d’autre il y a juste un élément que vous ne connaissez peut être pas. @csrf est un moyen de sécuriser les données envoyé. Si vous ne le mettez pas, Laravel vous affichera une erreur pour éviter toute fuite de donnée. Vous pouvez voir votre page à l’url suivant : crudlaravel.test/films/create

Nous avons donc maintenant une fonction d’ajout fonctionnelle. Nous pouvons donc passer à la deuxième fonction :

Read

La fonction read va s’appeler index la plupart du temps. Elle permet la visualisation de vos données. Votre Controller devrait ressembler à ça :

public function index(Request $request) {
            $films = \App\Models\Film::all();
        return view('film.index', compact('films'));
    }

Nous demandons ici au Model Film de nous envoyer toutes les données à la vue par l’URL film.index.

Attention ! 'film.index' est le nom de la route ! Vous pouvez travailler avec le nom de la route seulement si il est défini dans votre fichier web.php. Nous, nous avons utilisé Route::resource qui affecte automatiquement un nom aux routes. Vous pouvez les consulter avec cette commande dans le terminal : php artisan route:list

Pour la vue, vous pouvez faire un tableau comme ceci :

<div class="row">
        <div class="col">
            <table class="table">
                <thead class="thead-dark">
                    <tr>
                        <th scope="col">#</th>
                        <th scope="col">Affiche</th>
                        <th scope="col">Titre</th>
                        <th scope="col">Genre</th>
                    </tr>
                </thead>
                <tbody>

                @foreach($films as $film)
                    <tr>
                        <th scope="row">{{$film->id}}</th>
                        <td><a href="/films/{{$film->id}}/"><img src="\images\{{$film->affiche}}" alt="affiche de {{$film->titre}}" style="width: 200px"></a></td>
                        <td><a href="/films/{{$film->id}}/">{{$film->titre}}</a></td>
                        <td>{{$film->genre}}</td>
                    </tr>
                @endforeach

                </tbody>
            </table>
        </div>
    </div>

Nous allons juste créer une vue détails pour faciliter la suppression et la modifiction. Dans le Controller, la fonction du détail sera show :

    public function show(\App\Models\Film $film, Request $request) {
        $autreGenre = \App\Models\Film::where("genre", "!=", $film->genre)->distinct()->get(["genre"]); 
        $filmsMemeGenre = \App\Models\Film::where("genre", "=", $film->genre)->where("id", "!=", $film->id)->get();

        return view('film.details', compact("autreGenre", "film", "filmsMemeGenre"));
    }

Puis la vue de show :

<h1>{{$film->titre}}</h1>

<div class="row contenu">
    <div class="col-4">
        <img src="\images\{{$film->affiche}}" alt="Affiche de {{$film->titre}}" class="imageDetails">
    </div>
    <div class="col-8">
        <h4>Résumé :</h4>
        <p>{{$film->description}}</p>
    </div>
</div>
<div class="row footer">
    <div class="col">
        <p>Dans le genre {{$film->genre}}, vous pourriez aimer</p>
        <ul>
            @foreach($filmsMemeGenre as $gfilm)
                    <li><a href="https://crudlaravel.test/films/{{$gfilm->id}}/">{{$gfilm->titre}}</a></li>
            @endforeach
        </ul>
    </div>



    <div class="col">
        <a href="https://crudlaravel.test/films/" class="bouton"><button type="button" class="btn btn-primary">Retour à l'accueil</button></a>
    </div>
</div>

Create, Read et maintenant, Update.

Update

Cette partie utilise deux fonctions comme Create. Nous avons la fonction edit et la fonction update. La fonction edit va servir à afficher la vue et à transmettre des données si nécessaire. La fonction update, elle, va contenir toute la partie modification de la donnée. Nous pouvons donc créer ces deux fonctions :

    public function edit(\App\Models\Film $film, Request $request) {
        $genres = \App\Models\Film::distinct()->get(["genre"]);

        return view('film.edit', compact('film', 'genres'));
    }

    public function update(\App\Models\Film $film, Request $request) {
        $film->affiche = $request->input('insertAffiche');  
        $film->titre = $request->input('insertTitre');
        $film->genre = $request->input('insertGenre');
        $film->description = $request->input('insertDescription');
        $film->save();

        return redirect('/films/'.$film->id);
    }
}

Vous pouvez constater que ces deux fonctions ressemblent beaucoup aux deux fonctions de Create. Edit va nous servir à renvoyer la vue et la variable genre. Update se comporte exactement comme store à une ligne près : la ligne $film = new \App\Models\Film(); n’est plus présente. En effet, si on modifie un objet, c’est qu’il existe déjà, le new n’a donc rien à faire ici.

Pour la vue, j’ai repris le même code que pour la création à quelques exceptions près :

<form method="POST" action="/films/{{$film->id}}">
    @csrf
    @method('PATCH')
    <div class="form-row">
        <div class="col-md-8 mb-3">
            <label for="insertTitre">Titre</label>
            <input type="text" name="insertTitre" class="form-control" id="insertTitre" placeholder="Titre du film" value="{{$film->titre}}" required>
        </div>
        <div class="col-md-4 mb-3">
            <label for="insertGenre">Genre</label>
            <select id="insertGenre" name="insertGenre" class="form-control">
                <option selected>{{$film->genre}}</option>
                @foreach($genres as $genre)
                    <option value="{{$genre->genre}}">{{$genre->genre}}</option>
                @endforeach
            </select>
        </div>
    </div>
    <div class="form-row">
        <div class="col mb-3">
            <div class="custom-file">
                <input type="file" name="insertAffiche" class="custom-file-input" id="insertAffiche" required>
                <label class="custom-file-label" for="insertAffiche" >Choose file</label>
            </div>
        </div>
    </div>
    <div class="form-row">
        <div class="col mb-3">
            <label for="insertDescription">Résumé du film</label>
            <textarea name="insertDescription" class="form-control" id="insertDescription" rows="5" required>{{$film->description}}</textarea>
        </div>
    </div>
    <button class="btn btn-primary" type="submit">Modifier !</button>
</form>

La méthode utilisé par Laravel pour mettre à jour une donnée est la méthode PATCH ou PUT. Mais pour faire ça, il faut définir la méthode POST dans form action="" method="", puis, @method('PATCH'). Si vous essayez de mettre méthode PATCH directement à coté de l’action, vous aurez une erreur et tout vos champs passeront en GET, donc dans l’url.

Vous pouvez également voir que l’on a toujours le @csrf pour sécuriser l’envoi de donnée.

Pour accéder au formulaire de modification, vous pouvez rajouter ceci dans la vue show dans le titre h1:

<h1>{{$film->titre}} <a href="/films/{{$film->id}}/edit"><i class="fas fa-pencil-alt fa-xs"></i></a> </h1>

Voilà pour le Update. Nous pouvons donc finir avec la fonction Delete.

Delete

Grâce à Route::resource, nous avons une route pour supprimer une donnée. Mais cette suppression est définitive. Laravel nous permet aussi de mettre en place une sorte de corbeille avec la fonctionnalité softdelete. C’est ce que nous allons utiliser. Cette fonction nécessite juste quelques lignes en plus. Nous devons rajouter dans le Model deux lignes : use Illuminate\Database\Eloquent\SoftDeletes; et use SoftDeletes; comme ceci :

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Film extends Model
{
    use HasFactory;
    use SoftDeletes;
}

Vous pouvez maintenant créer une fonction softdelete dans votre Controller :

    public function softdelete(\App\Models\Film $film, Request $request) {

        $film->delete();
        return redirect('/films/');
   
    }

Puis, pour la vue, je vais rajouter une icône qui servira de bouton de suppression à la vue show :

{{$film->titre}} <a href="/films/{{$film->id}}/edit"><i class="fas fa-pencil-alt fa-xs"></i></a>
<a id="delete" href="/films/{{$film->id}}/delete"><i class="fas fa-trash-alt fa-xs"></i></a>

Nous pouvons rajouter un peu de javascript pour envoyer une confirmation de la suppression. Juste avant la fermeture de </body> :

<script>
$(document).ready(function(){

    $("#delete").click(function(e){

        var titre = '{{$film->titre}}';
        resultat = confirm("Etes vous sûr de vouloir supprimer " + titre + " ?");
        if (resultat == false) {
            e.preventDefault();
        } else {
            alert("Le film " + titre + " à bien été supprimé !" );
        }
    });

})
</script>

Pour celles et ceux qui ne connaissent pas le jQuery :

  • $(document) permet de sélectionner un élément, le document ici.
  • .ready est l’évènement qui doit avoir lieu sur l’élément sélectionné.
  • (function(e){...}) indique au programme ce qu’il doit faire.
  • Nous disons donc : quand le document est prêt (ready), exécute la fonction (function) suivante.
  • Ou juste après : quand il y à un clique ( .click() ) sur l’élément qui possède l’id delete ( $('#delete') ), exécute la fonction( function(e){} )suivante

Mais il nous manque une dernière chose pour que la fonction softdelete soit opérationnelle. Dans la liste de nos routes, nous avons une route delete mais pas de softdelete. Il faut donc l’ajouter :

Route::get('/films/{film}/delete', 'App\Http\Controllers\FilmController@softdelete');

Résumé

CRUD c’est l’acronyme des 4 principales fonctions d’un site : Create, Read, Update et Delete.

  • Create qui permet de créer et d’ajouter une donnée.
  • Read permet de lire les données.
  • Update permet de mettre à jour ou de modifier une donnée.
  • Delete sert à effacer une donnée.

A part Delete, elles sont toutes composées de 2 fonctions: create et store, index et show, update et edit.

Deux types de suppressions : Delete et SoftDelete. Le premier étant permanent.

Laisser un commentaire