Tutoriel pour apprendre à créer une application Laravel

Les utilisateurs

L'administrateur de l'application peut gérer les utilisateurs :

  • consulter les paramètres ;
  • modifier les paramètres (en particulier « Vu ») ;
  • créer un utilisateur ;
  • renommer les rôles ;
  • supprimer un utilisateur.

Ce tutoriel est destiné à décrire comment tout cela est géré dans l'application.

9 commentaires Donner une note à l'article (5)

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

L'administrateur dispose d'un bloc sur son tableau de bord pour les utilisateurs :

Image non disponible

Nous avons déjà vu le code pour les articles et les messages, je n'insiste donc pas.

L'administrateur dispose également d'un menu latéral pour les utilisateurs :

Image non disponible

II. Le panneau

Le panneau des utilisateurs apparaît ainsi :

Image non disponible

C'est la méthode index du contrôleur UserController qui l'affiche :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
/**
 * Display a listing of the resource.
 *
 * @return Response
 */
public function index()
{
    return $this->indexSort('total');
}

On voit qu'il est fait appel à une autre fonction du contrôleur :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
/**
 * Display a listing of the resource.
 *
 * @param  string  $role
 * @return Response
 */
public function indexSort($role)
{
    $counts = $this->user_gestion->counts();
    $users = $this->user_gestion->index(4, $role); 
    $links = $users->setPath('')->render();
    $roles = $this->role_gestion->all();
 
    return view('back.users.index', compact('users', 'links', 'counts', 'roles'));        
}

Cette méthode est utilisée pour l'affichage en filtrant le rôle. Dans notre cas le fait de passer « total » revient à afficher tous les utilisateurs. Pour filtrer les rôles, on a ce panneau de boutons qui conduit directement à la fonction vue ci-dessus :

Image non disponible

On peut sélectionner par exemple seulement les rédacteurs :

Image non disponible

C'est la méthode index du repository UserRepository qui assure la gestion des données :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
/**
 * Get users collection.
 *
 * @param  int  $n
 * @param  string  $role
 * @return Illuminate\Support\Collection
 */
public function index($n, $role)
{
    if($role != 'total')
    {
        return $this->model
        ->with('role')
        ->whereHas('role', function($q) use($role) {
            $q->whereSlug($role);
        })      
        ->oldest('seen')
        ->latest()
        ->paginate($n);          
    }
 
    return $this->model
    ->with('role')       
    ->oldest('seen')
    ->latest()
    ->paginate($n);
}

C'est cette vue qui est utilisée :

Image non disponible

La partie du code qui gère le tableau est celle-ci :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
<div class="table-responsive">
    <table class="table">
        <thead>
            <tr>
                <th>{{ trans('back/users.name') }}</th>
                <th>{{ trans('back/users.role') }}</th>
                <th>{{ trans('back/users.seen') }}</th>
                <th></th>
                <th></th>
            </tr>
        </thead>
        <tbody>
          @include('back.users.table')
    </tbody>
    </table>
</div>

On voit qu'on inclut une autre vue (back/users/table.blade.php) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
@foreach ($users as $user)
    <tr {!! !$user->seen? 'class="warning"' : '' !!}>
        <td class="text-primary"><strong>{{ $user->username }}</strong></td>
        <td>{{ $user->role->title }}</td>
        <td>{!! Form::checkbox('seen', $user->id, $user->seen) !!}</td>
        <td>{!! link_to_route('user.show', trans('back/users.see'), [$user->id], ['class' => 'btn btn-success btn-block btn']) !!}</td>
        <td>{!! link_to_route('user.edit', trans('back/users.edit'), [$user->id], ['class' => 'btn btn-warning btn-block']) !!}</td>
        <td>
            {!! Form::open(['method' => 'DELETE', 'route' => ['user.destroy', $user->id]]) !!}
            {!! Form::destroy(trans('back/users.destroy'), trans('back/users.destroy-warning')) !!}
            {!! Form::close() !!}
        </td>
    </tr>
@endforeach

III. Marquer « Vu »

Lorsqu'un utilisateur est nouvellement inscrit, il apparaît comme non vu sur le panneau, avec la case décochée et le fond jauni pour attirer le regard :

Image non disponible

Cette action est gérée en JavaScript côté client avec envoi de la requête en Ajax :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
// Seen gestion
$(document).on('change', ':checkbox', function() {    
  $(this).parents('tr').toggleClass('warning');
  $(this).hide().parent().append('<i class="fa fa-refresh fa-spin"></i>');
  var token = $('input[name="_token"]').val();
  $.ajax({
    url: '{!! url('userseen') !!}' + '/' + this.value,
    type: 'PUT',
    data: "seen=" + this.checked + "&_token=" + token
  })
  .done(function() {
    $('.fa-spin').remove();
    $('input[type="checkbox"]:hidden').show();
  })
  .fail(function() {
    $('.fa-spin').remove();
    var chk = $('input[type="checkbox"]:hidden');
    chk.show().prop('checked', chk.is(':checked') ? null:'checked').parents('tr').toggleClass('warning');
    alert('{{ trans('back/users.fail') }}');
  });
});

Avec une petite animation d'attente :

Image non disponible

C'est la méthode updateSeen du contrôleur UserController qui est chargée de la requête :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
/**
 * Update the specified resource in storage.
 *
 * @param  Illuminate\Http\Request $request
 * @param  App\Models\User $user
 * @return Response
 */
public function updateSeen(
    Request $request, 
    $user)
{
    $this->user_gestion->update($request->all(), $user);
 
    return response()->json();
}

Il est fait appel à la méthode update du repository UserRepository :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
/**
 * Update a user.
 *
 * @param  array  $inputs
 * @param  App\Models\User $user
 * @return void
 */
public function update($inputs, $user)
{        
    $user->confirmed = isset($inputs['confirmed']);
 
    $this->save($user, $inputs);
}

Ce sera la même méthode pour modifier d'autres champs.

Notez qu'il est fait appel à la liaison du modèle au niveau des routes (route model binding). Regardez dans le service provider app/Providers/RouteServiceProvider :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @param  \Illuminate\Routing\Router  $router
 * @return void
 */
public function boot(Router $router)
{
    parent::boot($router);
 
    $router->model('user', 'App\Models\User');
}

Chaque fois qu'on utilise « user » comme paramètre de route Laravel crée automatiquement le modèle correspondant. C'est pour ça qu'on a directement le modèle comme paramètre dans la fonction updateSeen vue ci-dessus. Ça sera la même chose pour d'autres fonctions que nous allons voir plus loin.

Le contrôleur renvoie une réponse JSON et le JavaScript agit en conséquence.

IV. Voir une fiche

Pour consulter les informations d'un utilisateur, l'administrateur clique sur ce bouton :

Image non disponible

C'est la méthode show du contrôleur UserController qui est chargée de la requête :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
/**
 * Display the specified resource.
 *
 * @param  App\Models\User
 * @return Response
 */
public function show(User $user)
{
    return view('back.users.show',  compact('user'));
}

Le contrôleur génère la vue :

Image non disponible

Avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
@extends('back.template')
 
@section('main')
 
    @include('back.partials.entete', ['title' => trans('back/users.dashboard'), 'icone' => 'user', 'fil' => link_to('user', trans('back/users.Users')) . ' / ' . trans('back/users.card')])
 
    <p>{{ trans('back/users.name') . ' : ' .  $user->username }}</p>
    <p>{{ trans('back/users.email') . ' : ' .  $user->email }}</p>
    <p>{{ trans('back/users.role') . ' : ' .  $user->role->title }}</p>
 
@stop

Avec ce rendu :

Image non disponible

V. Créer un utilisateur

L'administrateur peut créer un utilisateur en cliquant sur ce bouton :

Image non disponible

C'est la méthode create du contrôleur UserController qui est chargée de la requête :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
/**
 * Show the form for creating a new resource.
 *
 * @return Response
 */
public function create()
{
    return view('back.users.create', $this->role_gestion->getAllSelect());
}

Il est fait appel à la méthode getAllSelect du repository RoleRepository :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
/**
 * Get roles collection.
 *
 * @param  App\Models\User
 * @return Array
 */
public function getAllSelect()
{
    $select = $this->all()->lists('title', 'id');
 
    return compact('select');
}

En effet, on a besoin de la liste des rôles pour le formulaire.

Le contrôleur génère la vue :

Image non disponible

Avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
@extends('back.template')
 
@section('main')
 
    <!-- Entête de page -->
    @include('back.partials.entete', ['title' => trans('back/users.dashboard'), 'icone' => 'user', 'fil' => link_to('user', trans('back/users.Users')) . ' / ' . trans('back/users.creation')])
 
    <div class="col-sm-12">
        {!! Form::open(['url' => 'user', 'method' => 'post', 'class' => 'form-horizontal panel']) !!}  
            {!! Form::control('text', 0, 'username', $errors, trans('back/users.name')) !!}
            {!! Form::control('email', 0, 'email', $errors, trans('back/users.email')) !!}
            {!! Form::control('password', 0, 'password', $errors, trans('back/users.password')) !!}
            {!! Form::control('password', 0, 'password_confirmation', $errors, trans('back/users.confirm-password')) !!}
            {!! Form::selection('role', $select, null, trans('back/users.role')) !!}
            {!! Form::submit(trans('front/form.send')) !!}
        {!! Form::close() !!}
    </div>
 
@stop

Ce qui donne ce formulaire :

Image non disponible

La méthode store du contrôleur UserController est chargée de gérer la soumission :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
/**
 * Store a newly created resource in storage.
 *
 * @param  App\requests\UserCreateRequest $request
 *
 * @return Response
 */
public function store(
    UserCreateRequest $request)
{
    $this->user_gestion->store($request->all());
 
    return redirect('user')->with('ok', trans('back/users.created'));
}

La validation est assurée par la requête de formulaire UserCreateRequest :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<?php namespace App\Http\Requests;
 
class UserCreateRequest extends Request {
 
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'username' => 'required|max:30|alpha|unique:users',
            'email' => 'required|email|unique:users',
            'password' => 'required|confirmed|min:8'
        ];
    }
 
}

Si la validation se passe bien le contrôleur appelle la méthode store du repository UserRepository pour la mise à jour dans la base :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
/**
 * Create a user.
 *
 * @param  array  $inputs
 * @param  int    $confirmation_code
 * @return App\Models\User 
 */
public function store($inputs, $confirmation_code = null)
{
    $user = new $this->model;
 
    $user->password = bcrypt($inputs['password']);
 
    if($confirmation_code) {
        $user->confirmation_code = $confirmation_code;
    } else {
        $user->confirmed = true;
    }
 
    $this->save($user, $inputs);
 
    return $user;
}

Puis le contrôleur affiche à nouveau la liste avec un message :

Image non disponible

Sinon on reçoit les messages d'erreur correspondants :

Image non disponible

VI. Modifier un utilisateur

L'administrateur peut modifier les informations d'un utilisateur en cliquant sur ce bouton :

Image non disponible

C'est la méthode edit du contrôleur UserController qui est chargée de la requête :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
/**
 * Show the form for editing the specified resource.
 *
 * @param  App\Models\User
 * @return Response
 */
public function edit(User $user)
{
    return view('back.users.edit', array_merge(compact('user'), $this->role_gestion->getAllSelect()));
}

Le contrôleur génère la vue :

Image non disponible

Avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
@extends('back.template')
 
@section('main')
 
    <!-- Entête de page -->
    @include('back.partials.entete', ['title' => trans('back/users.dashboard'), 'icone' => 'user', 'fil' => link_to('user', trans('back/users.Users')) . ' / ' . trans('back/users.edition')])
 
    <div class="col-sm-12">
        {!! Form::model($user, ['route' => ['user.update', $user->id], 'method' => 'put', 'class' => 'form-horizontal panel']) !!}
            {!! Form::control('text', 0, 'username', $errors, trans('back/users.name')) !!}
            {!! Form::control('email', 0, 'email', $errors, trans('back/users.email')) !!}
            {!! Form::selection('role', $select, $user->role_id, trans('back/users.role')) !!}
            {!! Form::submit(trans('front/form.send')) !!}
        {!! Form::close() !!}
    </div>
 
@stop

Avec ce rendu :

Image non disponible

Le même formulaire que celui de la création, mais sans le mot de passe et avec une case à cocher pour la confirmation.

La méthode update du contrôleur UserController est chargée de gérer la soumission :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
/**
 * Update the specified resource in storage.
 *
 * @param  App\requests\UserUpdateRequest $request
 * @param  App\Models\User
 * @return Response
 */
public function update(
    UserUpdateRequest $request,
    $user)
{
    $this->user_gestion->update($request->all(), $user);
 
    return redirect('user')->with('ok', trans('back/users.updated'));
}

La validation est assurée par la requête de formulaire UserUpdateRequest :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<?php namespace App\Http\Requests;
 
class UserUpdateRequest extends Request {
 
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        $id = $this->user->id;
        return $rules = [
            'username' => 'required|max:30|alpha|unique:users,username,' . $id, 
            'email' => 'required|email|unique:users,email,' . $id
        ];
    }
 
}

Très proche de celle de la création, mais sans le mot de passe et aussi en récupérant l'identifiant de l'utilisateur dans la requête pour la règle d'unicité du nom.

Si la validation se passe bien le contrôleur appelle la méthode update du repository UserRepository pour la mise à jour dans la base :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
/**
 * Update a user.
 *
 * @param  array  $inputs
 * @param  App\Models\User $user
 * @return void
 */
public function update($inputs, $user)
{        
    $user->confirmed = isset($inputs['confirmed']);
 
    $this->save($user, $inputs);
}

Puis le contrôleur affiche à nouveau la liste avec un message :

Image non disponible

Sinon on renvoie et on affiche les messages d'erreur de saisie.

VII. Supprimer un utilisateur

L'administrateur peut modifier les informations d'un utilisateur en cliquant sur ce bouton :

Image non disponible

C'est la méthode destroy du contrôleur UserController qui est chargée de la requête :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
/**
 * Remove the specified resource from storage.
 *
 * @param  App\Models\user $user
 * @return Response
 */
public function destroy(User $user)
{
    $this->user_gestion->destroyUser($user);
 
    return redirect('user')->with('ok', trans('back/users.destroyed'));
}

Côté client on affiche quand même un petit message en JavaScript par sécurité :

Image non disponible

Il est fait appel à la méthode destroyUser du repository UserRepository :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
/**
 * Destroy a user.
 *
 * @param  App\Models\User $user
 * @return void
 */
public function destroyUser(User $user)
{
    $user->comments()->delete();
     
    $user->delete();
}

On commence par supprimer les commentaires éventuels de l'utilisateur et ensuite on le supprime.

On affiche un message de confirmation pour l'administrateur :

Image non disponible

VIII. Noms des rôles

Si l'administrateur veut modifier le nom des rôles, il doit passer par le menu latéral :

Image non disponible

C'est la méthode getRoles du contrôleur UserController qui est chargée de la requête :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
/**
 * Display the roles form
 *
 * @return Response
 */
public function getRoles()
{
    $roles = $this->role_gestion->all();
 
    return view('back.users.roles', compact('roles'));
}

Il est fait appel à la méthode all du repository RoleRepository :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
/**
 * Get all roles.
 *
 * @return Illuminate\Support\Collection
 */
public function all()
{
    return $this->role->all();
}

On récupère toutes les informations des rôles.

Le contrôleur génère la vue :

Image non disponible

Avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
@extends('back.template')
 
@section('main')
 
    @include('back.partials.entete', ['title' => trans('back/roles.dashboard'), 'icone' => 'user', 'fil' => link_to('user', trans('back/users.Users')) . ' / ' . trans('back/roles.roles')])
 
    <div class="col-sm-12">
        @if(session()->has('ok'))
            @include('partials/error', ['type' => 'success', 'message' => session('ok')])
        @endif
        {!! Form::open(['url' => 'user/roles', 'method' => 'post', 'class' => 'form-horizontal panel']) !!}    
            @foreach ($roles as $role) 
                {!! Form::control('text', 0, $role->slug, $errors, trans('back/roles.' . $role->slug), $role->title) !!}
            @endforeach
            {!! Form::submit(trans('front/form.send')) !!}
        {!! Form::close() !!}
    </div>
 
@stop

Et ce rendu :

Image non disponible

On peut donc ici changer les noms.

La méthode postRoles du contrôleur UserController est chargée de gérer la soumission :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
/**
 * Update roles
 *
 * @param  App\requests\RoleRequest $request
 * @return Response
 */
public function postRoles(RoleRequest $request)
{
    $this->role_gestion->update($request->except('_token'));
     
    return redirect('user/roles')->with('ok', trans('back/roles.ok'));
}

La validation est assurée par la requête de formulaire RoleRequest :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<?php namespace App\Http\Requests;
 
class RoleRequest extends Request {
 
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'admin' => 'required|alpha|max:50',
            'redac' => 'required|alpha|max:50',
            'user'  => 'required|alpha|max:50'
        ];
    }
 
}

Si la validation se passe bien, le contrôleur fait appel à la méthode update du repository RoleRepository :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
/**
 * Update roles.
 *
 * @param  array  $inputs
 * @return void
 */
public function update($inputs)
{
    foreach ($inputs as $key => $value)
    {
        $role = $this->role->where('slug', $key)->firstOrFail();
        $role->title = $value;
        $role->save();
    }
}

On parcourt tous les rôles pour les mettre à jour.

Le contrôleur régénère la vue en la complétant avec un message :

Image non disponible

On a ainsi fait le tour de la gestion des utilisateurs et de leurs rôles.

IX. Remerciements

Nous remercions Maurice Chavelli qui nous autorise à publier ce tutoriel.

Nous tenons également à remercier Winjerome pour la mise au gabarit et Claude Leloup pour la relecture.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2017 Laravel. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.