Premier projet Laravel 5.4 : Ajouter, afficher, mettre à jour et supprimer un article (Part. 6/7)

Share on LinkedInTweet about this on TwitterShare on FacebookShare on RedditShare on Google+

On possède maintenant notre base de données et notre système d’authentification. Ce qu’on va faire, c’est toute la mécanique qui permettra d’ajouter, de modifier, de supprimer et de lire des articles en base de données.

Afficher un article

Dans un premier temps, on va afficher un article et pour ça, on va tout de suite ajouter un lien sur le titre de nos articles dans la liste et renseigner cette nouvelle route:

/* routes/web.php */
/* ... */
Route::get('/posts/{id}', 'PostController@view');
/* ... */
/* resources/vews/posts.blade.php */
/* ... */
<body>

@foreach($posts as $post)
  <div class="post-container">
     <h3>
        <a href="{{ URL::action('PostController@view', $post->id) }}">{{ $post->title }}</a>
     </h3>
     <p>{{ $post->content }}</p>
     <i>{{ $post->user->name }}</i>
  </div>
@endforeach

</body>
/* ... */

Ici, dans le fichier posts.blade.php, avec le Helper URL, on ajoute une action vers le contrôleur PostController qui appelle la fonction view en lui passant l’id de l’article en paramètre.

Il nous faut donc créer cette fonction :

/* app/Http/Controllers/PostController.php */
/* ... */
public function view($id){
   $post = Post::where('id', $id)->firstOrFail();
   return view('post', compact('post'));
}

Dans la signature de notre fonction,on attend bien en paramètre l’id du post qu’on souhaite afficher et retourner dans la vue post, que nous allons ajouter dans le dossier resources/views :

/* resources/views/post.blade.php */
<!doctype html>
<html lang="{{ config('app.locale') }}">
   <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">

      <title>Laravel</title>

      <!-- Fonts -->
      <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">
      <!-- styles -->
      <link href="./css/custom.css" rel="stylesheet" type="text/css">
   </head>
   <body>
      <a href="{{ URL::action('PostController@index') }}">Retour à la liste</a>
      <h1>{{ $post->title }}</h1>
      <p>{{ $post->content }}</p>
      <i>{{ $post->user->name }} {{ $post->user->firstname }}</i>
   </body>
</html>

On peut maintenant cliquer sur le titre du post pour l’afficher dans une page spécifique :

Modifier un article

Pour modifier l’article sur l’url que l’on consulte, on va ajouter un bouton si l’utilisateur est authentifier (pour l’exemple, on part du principe que tout le monde peut modifier un article du moment qu’il est connecté).

Pour créer le formulaire de saisie, on va ajouter une dépendance nommée LaravelCollective afin de pouvoir utiliser la façade Form.

Ajoutons le bouton qui permettra de rediriger vers l’édition de l’article courant :

/* resources/views/post.blade.php */
/* ... */
<body>
   <a href="{{ URL::action('PostController@index') }}">Retour à la liste</a>
   <h1>{{ $post->title }}</h1>
   <p>{{ $post->content }}</p>
   <i>{{ $post->user->name }} {{ $post->user->firstname }}</i>
   <p>
       <a href="{{ URL::action('PostController@edit', $post->id) }}" class="button">Editer</a>
   </p>
</body>
/* ... */

Et les routes correspondantes :

/* routes/web.php */
/* ... */
Route::get('/posts', 'PostController@index');
Route::get('/posts/{id}', 'PostController@view');
Route::get('/posts/{id}/edit', 'PostController@edit');
Route::post('posts/{id}/update', 'PostController@update');
/* ... */

Avec la méthode qui sera appelée dans le contrôleur dans chacun des cas :

/* App/Http/Controllers/PostController.php */
/* ... */
public function edit($id){
   $post = Post::where('id', $id)->firstOrFail();
   return view('post-edit', compact('post'));
}

public function update(Request $request){
   return $request->input();
}
/* ... */

On crée donc une vue pour l’édition dans une vue blade :

/* resources/views/post-edit.blade.php */
<!doctype html>
<html lang="{{ config('app.locale') }}">
   <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">

      <title>Laravel</title>

      <!-- Fonts -->
      <link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">
      <!-- styles -->
      <link href="{{ URL::asset('css/custom.css') }}" rel="stylesheet" type="text/css">
   </head>
   <body>
      <a href="{{ URL::action('PostController@index') }}">Retour à la liste</a> - <a href="{{ URL::action('PostController@view', $post->id) }}">Annuler</a>
      <h1>Editer l'article</h1>
 
      {{ Form::model($post, [ 'url' => URL::action('PostController@update', $post ), 'method' => 'post'])}}
         <p>{{ Form::label('title', 'Titre :') }} {{ Form::text('title') }}</p>
         <p>{{ Form::label('content', 'Article :') }} {{ Form::textarea('content') }}</p>
         {{ Form::submit() }}
      {{ Form::close() }}
   </body>
</html>

Note : Si on ne passe pas par la méthode Form::model qui prend donc le modèle en paramètre, on serait obligé de préciser les valeurs des champs :

{{ Form::open([ 'url' => URL::action('PostController@update', $post ), 'method' => 'post'])}}
   {{ Form::label('title', 'Titre :') }} {{ Form::text('title', $post->title) }}
   {{ Form::label('content', 'Article :') }} {{ Form::textarea('content', $post->content) }}
{{ Form::close() }}

Et on ajoute quelques lignes de css pour le rendu des boutons :

/* public/css/custom.css */
/* ... */
.button, input[type="submit"]{
   display: inline-block;
   padding: 8px 20px;
   background-color: #AAAAAA;
   text-decoration: none;
   text-transform: uppercase;
   border: none;
}

.button:hover, .button:focus, .button:active,
 input[type="submit"]:hover, input[type="submit"]:focus, input[type="submit"]:active{
   background-color: #3399FF;
}

Maintenant, si on clique sur valider, on est bien redirigé vers http://localhost/laravel-test/public/posts/1/update mais on affiche de façon brute les données récupérées du formulaire sans les sauvegarder.

public function update(Request $request){ 
   return $request->input(); 
}

On observe 2 choses :

  1. Le token qui sert à se protéger contre les attaques CSRF (ajouté lors de requêtes PUT, POST ou DELETE lorsque l’on utilise Form::open() ou Form::model() de LaravelCollective)
  2. Les données de notre formulaire pour nous permettre d’enregistrer les informations

On va pas parler de CSRF dans cet article, pour le moment on va se contenter de sauvegarder nos données.

Pour sauvegarder les données mises à jour depuis notre formulaire, on va se placer dans notre méthode update du PostController :

/* PostController.php */
/* ... */
public function update($id, Request $request){
   $post = Post::where('id', $id)->firstOrFail(); /* trouve l'entrée en DB */
   $post->update($request->intersect(['title', 'content'])); /*récupère les valeurs suivantes */
   return redirect()->back(); /* redirige vers la vue d'édition */
}

Si on essaye de modifier l’article, on obtient… une erreur…

Comme dans le modèle User.php, on avait renseigner les champs renseignables, on va le faire également dans le modèle Post.php afin qu’Eloquent n’essaie pas de renseigner la colonne user_id puisqu’il s’agit d’une clé étrangère (FK).

/* app/Models/Post.php */
/* ... */
protected $fillable = ['title', 'content'];

Maintenant, si on essaye de modifier un article, on peut constater que la redirection vers le formulaire fonctionne et que si l’on retourne sur la liste notre titre à bien été modifié.

Ajouter un article

Pour ajouter un article, on va ajouter la possibilité de faire non plus un POST mais également un PUT depuis notre formulaire selon si on est en modification ou en ajout.

On va donc ajouter la route, pour accéder au formulaire en GET et pour envoyer le formulaire pour de l’ajout et non de la mise à jour soit en PUT dans notre fichier web.php :

/* routes/web.php */
/* ... */
use Illuminate\Support\Facades\Auth;
/* posts */
Route::get('/posts', 'PostController@index');
Route::get('posts/create', 'PostController@create');
Route::put('posts/create', 'PostController@insert');
Route::get('/posts/{id}', 'PostController@view');
/* ... */

A noter : L’ordre dans lequel on déclare les routes a une importance car si par exemple je déclare 'posts/create' après 'posts/{id}', alors 'create' sera interprété comme une variable {id} ce qui provoquera une erreur !

Avec la fonction correspondante dans le PostController.php

/* PostController.php */
/* ... */
public function create(){
   $post=newPost();
   return view('post-edit', compact('post'));
}
/* ... */

Il faut qu’on ajoute une condition pour que le formulaire soit en POST ou PUT dans la vue post-edit.blade.php :

/* post-edit.blade.php */ 
/* ... */
{{ Form::model(
       $post, [
          'url'=>$post->id ? URL::action('PostController@update', $post ) : URL::action('PostController@create', $post),
          'method'=>$post->id ? 'POST' : 'PUT'
       ]
    )
 }}
 <p>{{ Form::label('title', 'Titre :') }} {{ Form::text('title') }}</p>
 <p>{{ Form::label('content', 'Article :') }} {{ Form::textarea('content') }}</p>
 {{ Form::submit() }}
 {{ Form::close() }}
/* ... */

Avec l’URL http://localhost/laravel-test/public/posts/create, on accède maintenant au même formulaire mais avec les champs vides, prêt pour l’ajout.

On avait ajouté dans le fichier du routing la route qui correspond à notre méthode PUT du formulaire, maintenant on va créer la méthode que cette route appellera dans le contrôleur :

/* App\Http\Controllers\PostController.php */
/* ... */
public function insert(Request $request){
   if (Auth::check()){
      $post = new Post();
      $inputs = $request->input();
      $inputs['user_id'] = Auth::user()->id;
      $post = Post::create($inputs);
   } 
   return redirect()->back();
}
/* ... */

Comme on le voit, on récupère l’id de l’utilisateur courant pour l’ajouter au tableau des variables à sauvegarder. Mais on avait pas authorisé la modification de l’user_id dans le modele Post.php.

/* App\Models\Post.php */
/* ... */
protected $fillable = [
   'title', 'content', 'user_id'
];

Maintenant je peux créer un article via l’url http://localhost/laravel-test/public/posts/create et le sauvegarder avec succès :

Supprimer un article

La suppression de l’article sera très facile, on va ajouter un bouton dans la vue de l’article, à coté de notre bouton d’édition. Pour ce faire, on va ajouter une route qui pointera vers l’action de suppression :

/* routes\Web.php */
/* ... */ 
Route::post('posts/{id}/update', 'PostController@update');
Route::delete('posts/{id}/delete', 'PostController@delete');
/* ... */

Et ajouter le bouton sous form de formulaire avec une méthode DELETE :

/* resources\views\post.blade.php */
/* ... */
<body>
   <a href="{{ URL::action('PostController@index') }}">Retour à la liste</a>
   <h1>{{ $post->title }}</h1>
   <p>{{ $post->content }}</p>
   <i>{{ $post->user->name }} {{ $post->user->firstname }}</i>
   <p>
      <a href="{{ URL::action('PostController@edit', $post->id) }}" class="button">Editer</a>
      {{ Form::model(
               $post, [ 
                  'url' => URL::action('PostController@delete', $post ),
                  'method' => 'DELETE'
               ]
         )
      }}
      {{ Form::submit('Delete', ['class' => 'button']) }}
      {{ Form::close() }}
   </p>
</body>
/* ... */

Et la méthode dans le controleur tout simplement :

public function delete($id){
   Post::destroy($id);
   return redirect()->action('PostController@index');
}

Et voilà pour la gestion de nos articles ! Ce petit tutoriel en 7 parties permet de se rendre compte de ce qu’est Laravel. Des optimisations sont possibles, au niveau des routes, la validation, des vues en ajoutant un layout etc… et des articles viendront compléter ces points, pour le moment, on a pu découvrir comment fonctionnait le framework en restant simple et le plus accessible possible. Je vous invite à me faire vos retours dans les commentaires par exemple afin que je puisse améliorer mon contenu 😉

Dans la dernière partie de ce tutoriel de découverte, on déploiera en production !

Doc officielle de Laravel et les failles CSRF : https://laravel.com/docs/4.2/html#csrf-protection
Doc officielle de Laravel Collective sur les Formulaires : https://laravelcollective.com/docs/master/html
Téléchargez les sources : laravel-test-6.zip

Share on LinkedInTweet about this on TwitterShare on FacebookShare on RedditShare on Google+

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *