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 :
- Le token qui sert à se protéger contre les attaques CSRF (ajouté lors de requêtes
PUT
,POST
ouDELETE
lorsque l’on utiliseForm::open()
ouForm::model()
de LaravelCollective) - 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
Vous aimez mes articles ? Offrez-moi un café !
Merci beaucoup pour ton article je suis en formation et je en plein portfolio laravel 5.6 ! Un peux de difficulté pour passé de 5.4 a 5.6 mais très bien fait
Merci encore !