Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

ch5 - Relation 1 - N

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 22

14 La relation 

1:n
www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977

Pour le moment, nous n’avons manipulé qu’une table avec Eloquent. Dans le pré-
sent chapitre, nous allons en utiliser deux et les mettre en relation. La relation la plus
répandue et la plus simple est celle qui fait correspondre un enregistrement d’une table
à plusieurs enregistrements de l’autre table ; on parle de relation de un à plusieurs ou
encore de relation de type 1:n. Nous verrons également dans ce chapitre comment
créer un middleware.

Exemple d'un blog personnel


Comme exemple pour ce chapitre, je vais prendre le cas d’un petit blog personnel avec :
• un affichage des articles ;
• des visiteurs qui pourront consulter les articles ;
• des utilisateurs enregistrés qui pourront aussi rédiger des articles (donc possibilité de se
connecter et se déconnecter) ;
• des administrateurs qui auront aussi le droit de supprimer des articles.
Pour ne pas trop alourdir le code, je ne prévoierai pas la modification des articles.

Les données

Migrations

Continuons à utiliser la table users des chapitres précédents. Nous allons ajouter une
nouvelle table posts destinée à mémoriser les articles. Si vous avez déjà créé la table
users avec des enregistrements, supprimez-la ; nous allons la recréer.
Nous avons déjà défini la migration de la table users et vous devez avoir le fichier dans
le dossier app/database/migrations. Je vous en rappelle le code :
Deuxième partie – Les bases de données

<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration


{
public function up()

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


{
Schema::create('users', function(Blueprint $table)
{
$table->increments('id');
$table->string('name')->unique();
$table->string('email')->unique();
$table->string('password', 60);
$table->boolean('admin')->default(false);
$table->rememberToken();
$table->timestamps();
});
}

public function down()


{
Schema::drop('users');
}
}

Créons une migration pour la table posts :

php artisan make:migration create_posts_table

Et complétons le code comme suit :

<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration


{
public function up()
{
Schema::create('posts', function(Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('titre', 80);
$table->text('contenu');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('restrict')
->onUpdate('restrict');
});
}

162
Chapitre 14. La relation 1:n

public function down()


{
Schema::table('posts', function(Blueprint $table) {
$table->dropForeign('posts_user_id_foreign');
});
Schema::drop('posts');

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


}
}

Normalement, vous devez avoir trois migrations.

Les trois migrations

Lancez la migration :

php artisan migrate

Vous devez ainsi vous retrouver avec les trois tables dans votre base, ainsi que la table
migrations.

Les quatre tables

Pour que la population que nous allons créer ensuite fonctionne, il faut repartir sur une
! nouvelle migration pour la table users. En effet, on va avoir besoin que la clé de la
table commence à 1.

163
Deuxième partie – Les bases de données

Population

Nous allons remplir nos tables avec des enregistrements pour réaliser nos essais. Créons
pour cela deux fichiers dans le dossier database/seeds. Normalement, vous devez
déjà avoir dans ce dossier le fichier DatabaseSeeder.php.

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


Le fichier DatabaseSeeder

En voici le code :

<?php
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder


{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// $this->call(UserTableSeeder::class);
}
}

La méthode run est destinée à exécuter les fichiers pour la population. Vous avez déjà
la ligne commentée de lancement pour la table users. Nous allons la dé-commenter
et ajouter le code pour la table posts :

<?php
public function run()
{
$this->call(UserTableSeeder::class);
$this->call(PostTableSeeder::class);
}

Placez bien les lignes dans cet ordre ; vous comprendrez bientôt pourquoi c’est
nécessaire.
Ensuite, on va créer le fichier UserTableSeeder.php pour la population de la table
users :

164
Chapitre 14. La relation 1:n

<?php
use Illuminate\Database\Seeder;

class UserTableSeeder extends Seeder


{
public function run()
{

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


DB::table('users')->delete();
for($i=0; $i<10; ++$i)
{
DB::table('users')->insert([
'name'=>'Nom' . $i,
'email'=>'email' . $i . '@blop.fr',
'password'=>bcrypt('password' . $i),
'admin'=>rand(0,1)
]);
}
}
}

Cela crée dix utilisateurs.


On prévoit aussi le fichier PostTableSeeder.php avec le code suivant :

<?php
use Illuminate\Database\Seeder;
use Carbon\Carbon;

class PostTableSeeder extends Seeder {


private function randDate()
{
return Carbon::createFromDate(null, rand(1,12), rand(1,28));
}

public function run()


{
DB::table('posts')->delete();
for($i=0; $i<100; ++$i)
{
$date=$this->randDate();
DB::table('posts')->insert([
'titre'=>'Titre' . $i,
'contenu'=>'Contenu' . $i . 'Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum.',
'user_id'=>rand(1,10),
'created_at'=>$date,
'updated_at'=>$date
]);
}
}
}

165
Deuxième partie – Les bases de données

Cela générera cent articles affectés de façon aléatoire aux dix utilisateurs. Nous étu-
dierons bientôt comment s’effectue la liaison entre les deux.

La classe Carbon (http://carbon.nesbot.com/docs/), contenue dans un package chargé


! par Laravel, facilite la manipulation des dates. N’hésitez pas à l’utiliser dès que vous
avez des dates à gérer.

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


Vous devez maintenant avoir les fichiers suivants dans le dossier des populations.

Les fichiers de population

Il suffit d’utiliser la commande d’Artisan pour lancer la population :

php artisan db:seed

Normalement, vous devez obtenir les deux tables remplies à l’issue de cette commande.

Si vous recevez un message vous disant que la classe userTableSeeder ou l’autre


! classe n’est pas trouvée, exécutez la commande composer dumpautoload, puis
relancez la population.

La table users

166
Chapitre 14. La relation 1:n

La relation

On a la situation suivante :
• un utilisateur peut écrire plusieurs articles ;
• un article est écrit par un seul utilisateur.

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


Il faut trouver un moyen de référencer cette relation dans les tables. Le principe est
simple : on prévoit dans la table posts une ligne destinée à recevoir l’identifiant de
l’utilisateur rédacteur de l’article. On appelle cette ligne une clé étrangère parce qu’on
enregistre ici la clé d’une autre table. Voici une représentation visuelle de cette relation.

La clé étrangère

Vous voyez la relation dessinée entre la clé id dans la table users et la clé étrangère
user_id dans la table posts. La migration qu’on a créée informe la base de cette
relation, via le code suivant :

<?php
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('restrict')
->onUpdate('restrict');

Dans la table, on déclare une clé étrangère (foreign) nommée user_id qui réfé-
rence (references) la ligne id dans la table (on) users. En cas de suppression
(onDelete) ou de modification (onUpdate), on a une restriction (restrict). Que
signifient ces deux dernières conditions ?
Imaginez que vous ayez un utilisateur avec l’id 5 associé à deux articles. Dans la
table posts, deux enregistrements ont donc un user_id de valeur 5. Si on sup-
prime l’utilisateur, la clé étrangère de ces deux enregistrements ne correspond plus à
aucun enregistrement dans la table users. En indiquant restrict, on empêche la
suppression d’un utilisateur auquel est associé au moins un article. Il faut commencer
par supprimer ses articles avant de le supprimer lui-même. On dit que la base assure

167
Deuxième partie – Les bases de données

l’intégrité référentielle. Elle n’accepte pas non plus qu’on utilise pour user_id une
valeur qui n’existe pas dans la table users.
Une autre possibilité est cascade à la place de restrict. Dans ce cas, si vous sup-
primez un utilisateur, tous les articles associés sont également effacés. C’est une option
qui est rarement utilisée parce qu’elle peut s’avérer dangereuse, surtout dans une base

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


comportant de multiples tables en relation. Néanmoins, c’est aussi une stratégie très
efficace parce que c’est le moteur de la base de données qui se charge de gérer les
enregistrements en relation ; vous n’avez ainsi pas à vous en soucier au niveau du code.
On pourrait aussi ne pas signaler à la base qu’il existe une relation et la gérer seule-
ment dans notre code. Cependant, c’est encore plus dangereux parce que la moindre
erreur de gestion des enregistrements dans votre code risque d’avoir des conséquences
importantes dans votre base avec de multiples incohérences.

Les modèles

Nous avons déjà un modèle User (app/User.php). Il faudra juste lui ajouter une
méthode pour trouver facilement les articles d’un utilisateur :

<?php
public function posts()
{
return $this->hasMany('App\Post');
}

On déclare ici qu’un utilisateur a plusieurs (hasMany) articles (posts). On aura ainsi
une méthode pratique pour récupérer les articles d’un utilisateur.

! Soyez vigilant avec les espaces de noms !

Il nous faut aussi le modèle Post :

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model


{
protected $fillable=['titre','contenu','user_id'];

public function user()


{
return $this->belongsTo('App\User');
}
}

168
Chapitre 14. La relation 1:n

Ici, la méthode user (au singulier) trouve l’utilisateur auquel appartient (belongsTo)
l’article. C’est donc la réciproque de la méthode précédente.
Voici une schématisation de cette relation avec les deux méthodes.

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977

Les deux méthodes de la relation

Je vous rappelle que si vous ne spécifiez pas de manière explicite le nom de la table
dans un modèle, Laravel le déduit à partir du nom du modèle qu’il met au pluriel (à la
mode anglaise) et avec la première lettre en minuscule.

Les deux méthodes mises en place récupèrent facilement un enregistrement lié. Par
exemple, cherchons tous les articles de l’utilisateur qui a l’id 1 :

<?php
$articles=App\User::find(1)->posts;

De la même manière, on peut trouver l’utilisateur qui a écrit l’article d’id 1 :

<?php
$user=App\Post::find(1)->user;

Vous voyez que le codage devient limpide avec ces méthodes !

Laravel dispose de l’outil tinker qui permet d’entrer des commandes dans la console
et ainsi d’interagir directement avec l’application. Il faut le démarrer avec la commande
php artisan tinker. On peut ensuite l’utiliser directement :

169
Deuxième partie – Les bases de données

php artisan tinker


Psy Shell v0.6.1 (PHP 5.5.12 ÔÇö cli) by Justin Hileman
>>> App\User::find(1)->posts =>Illuminate\Database\Eloquent\Collection
{#661 all: [App\Post {#662 id:47,
created_at: "2015-03-19 12:39:12",
updated_at: "2015-03-19 12:39:12",
titre: "Titre46",

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


contenu: "Contenu46 Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
anim id est laborum.",
user_id: 1,}, ...

Contrôleur et routes

Contrôleur

Tout est en place au niveau des données ; voyons donc un peu comment gérer tout
cela. Créons le contrôleur pour les articles, PostController. Il doit gérer plusieurs
choses :
• recevoir la requête pour afficher les articles du blog et fournir la réponse adaptée ;
• recevoir la requête pour le formulaire destiné à la création d’un nouvel article et y
répondre ;
• recevoir le formulaire soumis (réservé à un utilisateur connecté) et l’enregistrer ;
• recevoir la demande de suppression d’un article (réservé à un administrateur) et
supprimer l’enregistrement correspondant.
Pour simplifier, je ne vais pas prévoir la possibilité de modifier un article.
J’utiliserai un contrôleur de ressource. Voici son code :

<?php
namespace App\Http\Controllers;

use App\Repositories\PostRepository;
use App\Http\Requests\PostRequest;

class PostController extends Controller


{
protected $postRepository;
protected $nbrPerPage=4;

public function __construct(PostRepository $postRepository)


{
$this->middleware('auth', ['except'=>'index']);
$this->middleware('admin', ['only'=>'destroy']);

170
Chapitre 14. La relation 1:n

$this->postRepository=$postRepository;
}

public function index()


{
$posts=$this->postRepository->getPaginate($this->nbrPerPage);
$links=$posts->render();

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


return view('posts.liste', compact('posts', 'links'));
}

public function create()


{
return view('posts.add');
}

public function store(PostRequest $request)


{
$inputs=array_merge($request->all(), ['user_id'=>$request->user()->id]);
$this->postRepository->store($inputs);
return redirect(route('post.index'));
}

public function destroy($id)


{
$this->postRepository->destroy($id);
return redirect()->back();
}
}

Comme à l’accoutumée, j’injecte la requête de formulaire et le gestionnaire.


Notez l’utilisation des middlewares pour filtrer les utilisateurs ; nous y reviendrons
un peu plus loin.

Routes

On a vu dans le chapitre sur les ressources comment créer les routes de ce genre de
contrôleur. Il faut juste indiquer qu’on ne veut pas utiliser les sept méthodes dispo-
nibles, mais seulement certaines :

<?php
Route::resource('post', 'PostController', ['except'=>['show', 'edit',
'update']]);
...

Avec except, j’indique que je ne veux pas de route pour les trois méthodes citées.
Voici ce que cela donne en utilisant Artisan pour visualiser les routes (php arti-
san route:list).

171
Deuxième partie – Les bases de données

Les routes

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


Le gestionnaire des articles
Nous plaçons les fichiers dans le dossier app/Repositories, comme nous l’avons
déjà fait pour la gestion des utilisateurs.

Le gestionnaire des articles

<?php
namespace App\Repositories;

use App\Post;

class PostRepository
{
protected $post;

public function __construct(Post $post)


{
$this->post=$post;
}

public function getPaginate($n)


{
return $this->post->with('user')
->orderBy('posts.created_at', 'desc')
->paginate($n);
}

public function store($inputs)


{
$this->post->create($inputs);
}

public function destroy($id)


{

$this->post->findOrFail($id)->delete();
}
}

Nous discuterons plus loin de l’utilité de toutes ces méthodes.

172
Chapitre 14. La relation 1:n

Les middlewares

Dans le contrôleur, on applique deux middlewares :


• auth : accès réservé aux utilisateurs authentifiés, à part pour la méthode index
pour afficher le blog ;

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


• admin : accès réservé aux administrateurs pour la méthode destroy.
Le premier est déjà prévu dans Laravel, mais le second n’existe pas. Pour le créer, nous
utilisons Artisan :

php artisan make:middleware Admin

Le middleware pour l’administration

On obtient le code suivant, auquel nous ajoutons nos instructions :

<?php
namespace App\Http\Middleware;

use Closure;

class Admin
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->user()->admin)
{
return $next($request);
}
return new RedirectResponse(url('post/liste'));
}
}

Si l’utilisateur n’est pas un administrateur, on redirige sur l’affichage du blog. Remarquez


qu’on ne vérifie pas à ce niveau qu’on a un utilisateur authentifié, parce que dans le
constructeur du contrôleur, le filtre auth est placé avant le filtre admin. Si c’était

173
Deuxième partie – Les bases de données

l’inverse, on tomberait évidemment sur une erreur en cas de tentative d’accès à l’URL
pour la suppression d’un article.
On a créé le middleware, mais cela ne suffit pas ; il faut maintenant un lien entre le
nom qu’on veut donner au filtre et la classe qu’on vient de créer. Regardez dans le
fichier app/Http/Kernel.php qui contient tous les middlewares déclarés et ajoutez
la ligne de code correspondant à admin :

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


<?php
protected $routeMiddleware=[
'auth'=>\App\Http\Middleware\Authenticate::class,
'auth.basic'=>\Illuminate\Auth\Middleware\
AuthenticateWithBasicAuth::class,
'guest'=>\App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle'=>\Illuminate\Routing\Middleware\ThrottleRequests::class,
'admin'=>\App\Http\Middleware\Admin::class,
];

La validation

Voyons la validation. Il faut encore créer une requête de formulaire :

php artisan make:request PostRequest

Elle se place dans le dossier suivant.

La requête de formulaire

On complète le code :

<?php
namespace App\Http\Requests;

use App\Http\Requests\Request;

class PostRequest extends Request


{
public function authorize()
{
return true;
}

public function rules()


{

174
Chapitre 14. La relation 1:n

return [
'titre'=>'required|max:80',
'contenu'=>'required'
];
}
}

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


Le fonctionnement

Liste des articles

La liste des articles est obtenue avec l’URL .../post (verbe get) qui arrive sur la méthode
index du contrôleur :

<?php
public function index()
{
$posts=$this->postRepository->getPaginate($this->nbrPerPage);
$links=$posts->render();
return view('posts.liste', compact('posts', 'links'));
}

Ici, on envoie le nombre d’articles par page (placé dans la propriété $nbrPerPage) à
la méthode getPaginate du gestionnaire :

<?php
public function getPaginate($n)
{
return $this->post->with('user')
->orderBy('posts.created_at', 'desc')
->paginate($n);
}

On veut les articles avec (with) l’utilisateur (user), dans l’ordre des dates de création
(posts.created_at) descendant (desc) avec une pagination de n articles ($n).

Il existe la méthode latest (et oldest pour l’inverse) qui simplifie la syntaxe :

<?php
return $this->post->with('user')
->latest('posts.created_at')
->paginate($n);

175
Deuxième partie – Les bases de données

Ajout d’un article

La demande du formulaire de création d’un article s’effectue avec l’URL .../post/create


(verbe get). Le contrôleur renvoie directement la vue :

<?php

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


public function create()
{
return view('posts.add');
}

Le retour du formulaire se fait avec l’URL .../post (verbe post).


On arrive sur la méthode store du contrôleur :

<?php
public function store(PostRequest $request)
{
$inputs=array_merge($request->all(), ['user_id'=>$request->user()->id]);
$this->postRepository->store($inputs);
return redirect(route('post.index'));
}

On injecte la requête de formulaire et on récupère les informations sur le titre et le


contenu. On sait que l’utilisateur est forcément connecté, alors on récupère son iden-
tifiant avec la requête. Si la validation se passe bien, on envoie à la méthode store
du repository :

<?php
public function store($inputs)
{
$this->post->create($inputs);
}

Suppression d’un article

On supprime un article avec l’URL .../post/id (verbe delete), où id représente l’iden-


tifiant de l’article à supprimer. On tombe sur la méthode destroy du contrôleur :

<?php
public function destroy($id)
{
$this->postRepository->destroy($id);
return redirect()->back();
}

Cette dernière envoie à la méthode destroy du repository :

176
Chapitre 14. La relation 1:n

<?php
public function destroy($id)
{
$this->post->findOrFail($id)->delete();
}

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


Là, on supprime l’article avec la méthode delete du modèle.

Les vues

Template

On va un peu modifier notre template (resources/views/template.blade.


php) :

<!DOCTYPE html>
<html lang="fr">
<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>Mon joli site</title>
{!! Html::style('https://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/
bootstrap.min.css') !!}
{!! Html::style('https://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/
bootstrap-theme.min.css') !!}
<!--[if lt IE 9]>
{{ Html::style('https://oss.maxcdn.com/libs/html5shiv/3.7.2/html5shiv.
js') }}
{{ Html::style('https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.
min.js') }}
<![endif]-->
<style>textarea{resize:none;}</style>
</head>
<body>
<header class="jumbotron">
<div class="container">
<h1 class="page-header">{!! link_to_route('post.index', 'Mon joli
blog') !!}</h1>
@yield('header')
</div>
</header>
<div class="container">
@yield('contenu')
</div>
</body>
</html>

177
Deuxième partie – Les bases de données

Vue pour afficher les articles

Nous avons besoin d’une vue pour afficher les articles du blog et quelques boutons pour
la gestion (resources/views/posts/liste.blade.php) :

@extends('template')

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


@section('header')
@if(Auth::check())
<div class="btn-group pull-right">
{!! link_to_route('post.create', 'Créer un article', [],
['class'=>'btn btn-info']) !!}
{!! link_to('logout', 'Deconnexion', ['class'=>'btn btn-warning']) !!}
</div>
@else
{!! link_to('login', 'Se connecter', ['class'=>'btn btn-info pull-
right']) !!}
@endif
@endsection

@section('contenu')
@if(isset($info))
<div class="row alert alert-info">{{$info}}</div>
@endif
{!!$links!!}
@foreach($posts as $post)
<article class="row bg-primary">
<div class="col-md-12">
<header>
<h1>{{$post->titre}}</h1>
</header>
<hr>
<section>
<p>{{$post->contenu}}</p>
@if(Auth::check() and Auth::user()->admin)
{!! Form::open(['method'=>'DELETE', 'route'=>['post.destroy',
$post->id]]) !!}
{!! Form::submit('Supprimer cet article', ['class'=>'btn
btn-danger btn-xs', 'onclick'=>'return confirm(\'Vraiment supprimer cet
article ?\')']) !!}
{!! Form::close() !!}
@endif
<em class="pull-right">
<span class="glyphicon glyphicon-pencil"></span> {{$ post->user-
>name }} le {!! $post->created_at->format('d-m-Y') !!}
</em>
</section>
</div>
</article>
<br>
@endforeach
{!!$links!!}
@endsection

Voici l’aspect obtenu pour un utilisateur non connecté.

178
Chapitre 14. La relation 1:n

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977

L’aspect du blog

Le bouton Se connecter envoie sur l’URL .../login, ce qui doit aboutir sur le formulaire
de connexion si vous avez tout en place comme nous l’avons prévu précédemment.

Le formulaire de connexion

Pour mémoire, j’utilise ici les vues par défaut de Laravel. Vous êtes évidemment libres
de franciser ces vues ou, encore mieux, les adapter au langage de l’utilisateur (nous
verrons cet aspect dans un chapitre ultérieur).

Pour que votre application fonctionne bien avec le AuthController, il faut modifier
la propriété redirectTo dans ce contrôleur :

<?php
protected $redirectTo='post';

Ainsi, vous serez bien redirigé vers le blog en cas de connexion.

179
Deuxième partie – Les bases de données

De la même manière, il faut prévoir une redirection après déconnexion dans le même
contrôleur :

<?php
protected $redirectAfterLogout='post';

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


La génération des articles dans la vue se fait avec un foreach :

@foreach($posts as $post)
...
@endforeach

Si vous vous connectez avec un utilisateur qui n’est pas administrateur (regardez dans votre
table pour en trouver un car, comme la population est aléatoire, on ne sait pas à l’avance
qui l’est et qui ne l’est pas). Vous retournez au blog avec deux boutons supplémentaires.

Les boutons pour un utilisateur de base

On utilise une condition pour adapter la page :

@if(Auth::check())
...
@else
...
@endif

La méthode check de la classe Auth permet de savoir si l’utilisateur est connecté.

Il existe l’helper auth() qui vous évite le recours à la façade :


@if(auth()->check())

Le premier bouton, Créer un article, génère l’URL .../post/create, ce qui a pour effet
d’obtenir le formulaire de création.
Le second bouton, Déconnexion, génère l’URL .../logout, qui correspond aussi à ce que
nous avons vu dans le chapitre précédent.
Si l’utilisateur connecté est un administrateur, alors il a en plus pour chaque article un
bouton de suppression.

180
Chapitre 14. La relation 1:n

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


Le bouton de suppression

On utilise encore une condition pour détecter un administrateur :

@if(Auth::check() and Auth::user()->admin)


...
@endif

Il faut que l’utilisateur soit connecté (check) et qu’il soit un administrateur


(user()->admin).
J’ai prévu une confirmation de la suppression avec un peu de JavaScript.

Vue pour créer un article


Voici maintenant la vue pour le formulaire de création d’un article (resources/
views/posts/add.blade.php) :

@extends('template')

@section('contenu')
<br>
<div class="col-sm-offset-3 col-sm-6">
<div class="panel panel-info">
<div class="panel-heading">Ajout d'un article</div>
<div class="panel-body">
{!! Form::open(['route'=>'post.store']) !!}
<div class="form-group {!! $errors->has('titre') ? 'has-
error' : '' !!}">
{!! Form::text('titre', null, ['class'=>'form-control',
'placeholder'=>'Titre']) !!}
{!! $errors->first('titre', '<small class="help-block">:message</
small>') !!}
</div>
<div class="form-group {!! $errors->has('contenu') ? 'has-
error' : '' !!}">
{!! Form::textarea ('contenu', null, ['class'=>'form-control',
'placeholder'=>'Contenu']) !!}

181
Deuxième partie – Les bases de données

{!! $errors->first('contenu', '<small class="help-


block">:message</small>') !!}
</div>
{!! Form::submit('Envoyer !', ['class'=>'btn btn-info pull-
right']) !!}
{!! Form::close() !!}
</div>

www.bibliovox.com:Fondation Mohammed VI:2110057491:88834657:105.155.23.201:1587499977


</div>
<a href="javascript:history.back()" class="btn btn-primary">
<span class="glyphicon glyphicon-circle-arrow-left"></span>Retour
</a>
</div>
@endsection

Il n’y a rien de bien nouveau dans cette vue. Voici son apparence.

Formulaire de création d’un article

On peut entrer le titre et le contenu, qui seront ensuite validés dans le contrôleur et
enregistrés si tout se passe bien.
Il arrive parfois que les vues ne se génèrent pas correctement. Laravel utilise un cache
pour les vues en storage/framework/views. Vous pouvez sans problème
! supprimer tous les fichiers (mais pas .gitignore !) pour obliger Laravel à générer
de nouvelles vues. Il existe une commande Artisan pour le faire : php artisan
view:clear.

En résumé
• Une relation de type 1:n nécessite la création d’une clé étrangère côté n.
• On peut remplir les tables d’enregistrements avec la population.
• Une relation dans la base nécessite la mise en place de méthodes spéciales dans les
modèles.
• Avec les middlewares, il est facile de gérer l’accès aux méthodes des contrôleurs.

182

Vous aimerez peut-être aussi