1 PHP Application Todolist MVC

1.1 Présentation du TP

Dans ce TP vous allez réaliser une application web qui utilise le langage PHP. Nous allons suivre pas à pas la construction de cette application de la création de la structure jusqu’à la réalisation de pages. Pour cela nous allons utiliser un framework qui met en oeuvre le cadre de conception MVC. Il y a de nombreuses propositions sur le réseau qui sont utilisées pour le développement d’applications professionnelles :

pour ne citer que deux exemples très connus.

Nous avons choisi pour nos TP le framework le plus abordable(pour un débutant) c’est à dire Laravel. Néanmoins il faut savoir que l’apprentissage de Laravel facilitera la compréhension et la mise en oeuvre d’un projet utilisant le framework Symfony.

Laravel propose une documentation très bien faite, ce sera un outil précieux dans notre travail de développement.

1.1.1 Environnement de travail

Nous allons avoir besoin d’un outil de développement (IDE) qui va accélérer notre production de code.
L’utilisation de PHPStorm n’est pas obligatoire, mais les enseignants utiliseront ce logiciel pour illustrer leurs propos pendant les séances de TPs.

1.1.2 Récupérer une copie du framework Laravel

1.1.2.1 A l’aide de la commande composer :

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

1.1.2.2 A l’aide de la commande laravel :

Dans ce cas il faut dans un premier temps ajouter la commande laravel dans votre environnement personnel (à faire une fois).

composer global require "laravel/installer"

puis ajouter la commande dans votre PATH à l’aide de la commande :

export PATH=$HOME/.composer/vendor/bin:$PATH

Si vous ne voulez pas le faire à chaque fois que vous ouvrez un terminal, il faut ajouter la commande précédente dans votre fichier ~/.bashrc.

La commande laravel est maintenant disponible. Pour créer un nouveau projet Laravel, il faut utiliser la commande

laravel new tp_mvc

1.1.2.3 L’archive disponible

Si le réseau ne supporte pas la charge, demandez à l’enseignant de vous fournir l’archive de départ. Après l’avoir décompressée, vous avez un répertoire qui contient le même résultat que celui obtenu à l’aide des commandes précédentes.

Déplacez vous dans le répertoire créé et tapez la commande suivante :

1.1.2.4 Adaptation du thème

Nous allons modifier le thème fourni par Laravel

  1. Remplacer le fichier package.json avec celui-ci (@fortawesome/fontawesome-free en plus).
  2. Copier l’archive assets.zip et décompressez la dans le répertoire resources.
  3. Copier le fichier bienvenue.blade.php dans le répertoire resources/views.
  4. Remplacer le fichier webpack.mix.js avec celui-ci.
  5. Adaptation à l’environnement de l’IUT

    La gestion du thème est assuré par le fichier webpack.mix.js qui contient les instructions pour agréger les fichiers javascript et générer un fichier de style css. L’utilisation de webpack associé avec webpack.mix.js nécessite de nombreuses librairies qui sont téléchargées depuis internet à l’aide de la commande npm install. Pour accelerer cette phase vous suivrez les instructions suivantes :

    1. Créez un répertoire robert.duchmol dans le répertoire /local (remplacez robert.duchmol par votre prénom et votre nom).
    2. Dans le répertoire créé, décompressez l’archive node_modules.tar.gz ( Note : la décompression de cette archive correspond à l’exécution de la commande npm install).
    3. Dans le répertoire racine de votre projet, créez un lien symbolique vers le répertoire node_modules local à votre machine
    4. Copier le fichier webpack.mix.js dans le répertoire /local/robert.duchmol

  6. Dans le fichier routes/web.php, remplacez la ligne

    par

1.1.3 Lancer un serveur web pour visualiser le travail en cours

Le répertoire tp_mvc sera créé dans le répertoire courant. Sans aucune intervention supplémentaire, vous pouvez tester votre application à l’aide de la commande suivante.

 cd /le/chemin/de/tp_mvc
 php artisan serve
 

qui vous place dans le répertoire racine de votre application web. La commande php artisan serve lance un serveur web qui écoute sur le port 8000 par défaut. Il va permettre de tester le résultat de votre développement. Vous pouvez tester que l’initialisation de votre projet est correcte en tapant l’URL http://localhost:8000 dans votre navigateur.

La commande php artisan sera très souvent utilisée lancez la commande php artisan pour connaitre les options possibles

1.2 L’application web

De ce TP nous allons reprendre la gestion de tâches du TP précédent. Les objectifs sont :

  • Gestion d’un thème à l’aide du moteur de templates blade,
  • Accès au base de données à partir de l’API DB principalement (pour arriver rapidement à l’API Eloquent),
  • Utilisation du service de routage,
  • Gestion des requêtes et des données transmises.

1.3 Partie statique de l’application

1.3.1 Gestion du thème et des templates du moteur blade

Le moteur de templates Blade permet de créer les pages web sous forme de composants :

  • l’en-tête (_head_)
  • le menu (_navbar_)
  • le corps (_body_)
  • le pied (_footer_)

On peut en imaginer d’autres (_sidebar_, …). Les pages d’une application utilisent généralement la même structure, seules les données changes. En partant de ce principe, à l’aide de blade nous allons construire le squelette de la page et y inclure des composants.

Voici le fichier master.blade.php à placer dans le répertoire resources/views/layout (à créer) :

Les balises @include indique l’inclusion d’un autre fichier

Note: Le @include('layout.navbar') permet d’inclure le fichier layout/navbar.blade.php

Le fichier layout/navbar.blade.php :

et le fichier layout/footer.blade.php :

1.3.1.1 Test de notre thème

Pour tester notre thème, nous allons modifier la page resources/views/welcome.blade.php avec le code qui suit.

Note: La balise @yield('content') du fichier layout/master.blade.php sera remplacée par le code qui se trouve entre les balides @section('content') et @endsection

@extends("layout.master")


@section('content')

    <!--Start your project here-->
    <div class="container">
        <div class="row">
            <div class="col-md-3">
                <div class="view overlay  hm-white-light z-depth-1-half">
                    <img src="{{asset('images/logo-iut.png')}}" class="img-fluid" alt="" style="margin-top: 2rem;">
                </div>
                <br>
            </div>

            <!--Main information-->
            <div class="col-md-9">
                <h2 class="h2-responsive">IUT de Lens</h2>
                <hr>
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ultricies euismod arcu. Aliquam
                    imperdiet laoreet nibh, sed posuere dolor feugiat sed. In in dolor et metus cursus ultrices. Nullam
                    blandit eu est a mollis. Cras elit quam, semper id ornare vitae, sodales eget nibh. Nulla dignissim
                    sodales quam, id placerat eros porttitor nec. Proin molestie eros vel tortor tempus, sit amet
                    placerat est pharetra. Vivamus a congue nibh, at lacinia libero. Nullam tristique posuere
                    feugiat.</p>

                <p>Nam fermentum eget lectus commodo luctus. Pellentesque ornare pellentesque justo eget suscipit. Nam
                    pellentesque pulvinar neque sit amet elementum. Aliquam euismod neque sed ipsum scelerisque, sed
                    tempor enim varius. Sed quis scelerisque orci. Ut id vehicula magna. Etiam sed rutrum nunc, a
                    vulputate mi. Phasellus tortor tortor, tempor quis metus et, efficitur congue dui. Suspendisse ac
                    leo eros. Praesent lobortis diam nunc, eget tincidunt ipsum laoreet eget. Proin ut sapien sed neque
                    lacinia accumsan. Vivamus consectetur porta elementum. Etiam id laoreet risus, vitae blandit ipsum.
                    Integer libero libero, sodales et feugiat ut, finibus vel arcu. Ut quis tortor rhoncus, blandit est
                    ut, sodales purus.
                    Sed gravida consectetur ex, non viverra dui venenatis a.</p>

                <a href="http://www.iut-lens.univ-artois.fr" class="btn btn-primary">Plus d'info!</a>
            </div>
        </div>
    </div>
@endsection

Vérifier que le thème fonctionne.

1.3.2 Le routage

Nous allons maintenant ajouter les pages suivantes :

  • La page d’accueil
  • La page A Propos
  • La page Contact

Pour cela nous allons devoir modifier les règles de routage. Ces pages sont des pages de données que l’on peut considérer comme statique (très peu souvent modifiées). Nous allons les gérer à l’aide d’un contrôleur WelcomeController. Pour créer le contrôleur WelcomeController, il est possible d’utiliser la commande

Cette commande va créer le fichier WelcomeController.php dans le répertoire app/Http/Controllers, il contient

1.3.2.1 La page d’accueil

La page d’accueil va afficher la déclaration universelle des droits de l’homme à partir d’un fichier au format markdown. Nous allons avoir besoin d’une librairie tiers michelf/php-markdown, Pour la récupérer vous utiliserez la commande

Le fichier droitsDeLHomme.md contient le code markdown de la déclaration universelle des droits de l’homme. Il faut ajouter le fichier droitsDeLHomme.md dans le répertoire public/md (qu’il faut créer)

Nous allons créer la classe MarkdownService qui contient la méthode parse qui transforme un fichier markdown en html. Voici le code de cette classe :

L’affichage de la page d’accueil se fera à partir de la règle

La fonction index du contrôleur va déclencher la transformation du code markdown en code html.

Note: La méthode index utilise le template welcome.index qui correspond au fichier resources/views/welcome/index.blade.php. Le template utilise une balise de type {!! $var !!} pour pouvoir afficher du code html.

Note: La route (http://localhost:8000) déclenche l’exécution de la méthode index dans le contrôleur WelcomeController. Il faudra donc modifier la route qui est indiqué dans le fichier routes/web.php.

Ajouter le fichier MarkdownService.php dans le répertoire app (trouvez le bon endroit !).

Ajouter la fonction index dans le contrôleur WelcomeController.

Créer le template ìndex dans le fichier resources/views/welcome/index.blade.php.

1.3.2.2 La page A Propos et Contact

Récupérer le code des pages apropos.blade.php et contact.blade.php.

Modifier le contrôleur WelcomeController.

Modifier le fichier des routes (le fichier routes/web.php) en accord avec le contrôleur WelcomeController.

Note: Les liens dans le fichier navbar.blade.php doivent être cohérents avec les routes que vous avez ajoutées.

1.4 Partie dynamique de l’application

1.4.1 Couche modèle de l’application

Nous allons maintenant réutiliser la base de données utilisée dans le TP précédent.

1.4.1.1 Connexion avec la base de données de votre SGBD

Laravel propose une connexion simplifiée avec un système de base de données. Le fichier de configuration .env permet de spécifier

  • le système de gestion de base de données (mysql, pgsql, …)
  • le nom de la base de données
  • l’identifiant de l’utilisateur
  • le mot de passe de l’utilisateur

Voici un extrait du fichier .env qui concerne les informations de connexion avec un SGBD :

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lar_tache
DB_USERNAME=duchmol
DB_PASSWORD=secret

Les informations indiquées dans le fichier .env surchargent les informations données dans le fichier config/database.php.

Modifier le fichier .env pour établir une connexion entre votre application web et votre SGBD

Note: Pour que les modification dans le fichier .env soient prises en compte, il faut relancer le serveur de développement. php artisan serve

1.4.1.2 Création de la table taches

Laravel propose une commande qui permet de créer l’infrastructure de gestion de la persistance de données dans une base de données.

Pour chaque table cette infrastructure se compose de trois éléments :

  1. Une description des colonnes de la table;
  2. Un modèle qui sera utilisé pour échanger entre l’application et la base de données;
  3. Un contrôleur qui fait le lien entre la vue et le modèle.

Pour créer l’infrastructure il faut exécuter la commande :

php artisan make:model Tache -mcr

Note: il est possible de créer chaque élément de l’infrastructure indépendamment des autres

php artisan make:model Tache
php artisan make:migration --create=taches create_taches_table (-m)
php artisan make:controller TacheController --resource (-cr)

Note: il est possible d’utiliser des tables d’une base de données qui existent déjà. Dans ce cas il suffit de créer uniquement le modèle et le contrôleur.

php artisan make:model Tache
php artisan make:controller TacheController

Si le nom de la table n’est pas celui attendu (nom du modèle avec un pluriel et sans majuscule modèle Tache -> table taches) il faut le spécifier, de la même façon pour la valeur de la clé primaire et l’ajout optionnel de la date de création et de modification d’un enregistrement.

namespace App;
use Illuminate\Database\Eloquent\Model;
class Tache extends Model {
  protected $table = 'mes_taches';
  public $primaryKey = 'ma_cle';
  public $timestamps = false;
}

Utiliser la commande pour créer l’infrastructure de la table taches

1.4.1.3 Création des colonnes de la table taches

Laravel dispose d’une commande qui permet de modifier les tables de la base de données.

php artisan migrate

Cependant avant d’utiliser cette commande il faut indiquer le contenu de la ou des tables. Pour cela il faut éditer le contenu du fichier database/migrations/xxx_create_taches_table.php et plus particulièrement la fonction up() (voir la documentation pour obtenir plus d’information sur les types de colonne disponibles).

Si vous souhaitez réinitialiser votre tables dans la base de données, Laravel propose la commande

php artisan migrate:refresh

Note: Le mécanisme de migration est géré par Laravel à l’aide d’une table migration qui est ajoutée dans votre base de données. Si vous avez des erreurs lors de la migration, et que vous ne voulez pas revenir en arrière, la suppression de cette table peut vous aider à repartir de zéro.

Note: Si vous avez l’erreur suivante :

    [PDOException]                                                                                      
    SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length  
    is 767 bytes   

Il faut ajouter le code suivant dans la classe AppServiceProvider.php (répertoire app/Providers)

use Illuminate\Support\Facades\Schema;

public function boot() {
  Schema::defaultStringLength(191);
}

Modifier la fonction up() et utiliser la commande qui permet de créer la table taches

1.4.1.4 Ajout d’un contenu à la table taches

Laravel propose un mécanisme ‘seed’ qui permet d’ajouter un contenu aux tables de votre base de données. Nous allons utiliser ce mécanisme en association avec la librairie Faker pour générer un contenu aléatoire dans la table taches.

Note: Ce mécanisme est généralement utilisé pour mettre en place plus facilement un jeu de données pour tester votre application. Il vous faudra récupérer la librairie qui contient la classe Faker à l’aide de la commande : composer require --dev fzaninotto/faker Ici on a utilisé require --dev comme commande car la librairie ne sera utilisée que pendant la phase de développement et de tests.

Dans un premier temps nous allons définir le domaine aléatoire de chaque colonne de la table taches. A l’aide de la librairie Faker, on peut définir simplement une fabrique d’enregistrements.

Le code qui suit placé dans le fichier database/factories/TacheFactory.php permet de créer un enregistrement pour la table taches.

Dans un deuxième temps nous allons utiliser cette création aléatoire de données pour ajouter des données dans la table taches. Pour cela nous allons créer une classe TacheTableSeeder dans le répertoire database/seeds.

La classe a le contenu suivant:

L’exécution de la méthode run va créer les enregistrements (10 ici) et les ajouter à la table taches de la base de données.

Laravel propose une commande pour déclencher la génération et l’ajout de données aléatoire (et ou de tests) dans la base de données.

php artisan migrate:refresh --seed

qui a pour effet de ré-initialiser la base de données et d’y ajouter des données.

Cette commande lance l’exécution de la méthode run de la classe DatabaseSeeder dans le répertoire database/seeds. Pour que notre classe TacheTableSeeder soit utilisée, il faut ajouter la ligne

         $this->call(TacheTableSeeder::class);

dans la méthode run de la classe DatabaseSeeder.

Note: Pour que la classe TacheTableSeeder soit visible, il faut réinitialiser composer à l’aide de la commande suivante :

composer dumpautoload

Ajouter 20 tâches aléatoires dans la table taches

1.4.1.5 Tests et utilisation de l’API DB

Dans la suite de ce TP nous allons utiliser l’API DB proposée par Laravel et en particulier les requêtes au format Query Builder. La documentation vous donne un aperçu des possibilités de l’API. Pour tester le bon fonctionnement de l’accès à notre modèle à partir de l’API, le plus simple est d’écrire un fichier de tests.

Pour cela nous allons utiliser une base de données de tests. Nous allons ajouter une configuration de base de données supplémentaire dans le fichier config/database.php. Nous allons ajouter une connexion sqlite_testing qui permet de faire les tests dans une base de données sqlite en mémoire. Après modification :

La configuration

La classe DBTest dans le répertoire tests/Unit permet de tester les quatre opérations de base (Création, Selection, Modification, Suppression):

<?php

namespace Tests\Unit;

use App\Tache;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Tests\TestCase;

class DBTest extends TestCase {

    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication() {
        // Utilisation de l'environnement de test
        putenv('DB_DEFAULT=sqlite_testing');

        $app = require __DIR__.'/../../bootstrap/app.php';

        $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();

        return $app;
    }

    public function setUp() {
        parent::setUp();
        Artisan::call('migrate');
        // Création des données de tests
        factory(Tache::class)->create(
            [
                'expiration' => "2017-08-31",
                'categorie' => 'Urgent',
                'description' => 'Teste la table tache',
                'accomplie' => 'N',
            ]
        );
        factory(Tache::class, 5)->create(['categorie' => 'Urgent']);
        factory(Tache::class, 5)->create(['categorie' => 'Bidon']);
    }


    public function testModelTest() {
        $taches = factory(Tache::class, 3)->make();
        $this->assertEquals(count($taches), 3);
    }

    public function testAccesDBTest() {
        $taches = DB::table('taches')->get();
        $this->assertEquals(count($taches), 11);
    }

    public function testAccesDBWithIDTest() {
        $tache = DB::table('taches')->where('id', 1)->first();

        $this->assertEquals($tache->expiration, '2017-08-31');
        $this->assertEquals($tache->categorie, 'Urgent');
        $this->assertEquals($tache->description, 'Teste la table tache');
        $this->assertEquals($tache->accomplie, 'N');
    }

    public function testUpdateDBWithIDTest() {
        DB::table('taches')->where('id', 1)->update(
            [
                'categorie' => 'A Faire',
                'description' => 'Teste modif de la table tache',
                'accomplie' => 'O',
            ]
        );
        $tache = DB::table('taches')->where('id', 1)->first();

        $this->assertEquals($tache->expiration, '2017-08-31');
        $this->assertEquals($tache->categorie, 'A Faire');
        $this->assertEquals($tache->description, 'Teste modif de la table tache');
        $this->assertEquals($tache->accomplie, 'O');
    }

    public function testDeleteDBWithIDTest() {
        DB::table('taches')->where('id', '>', 1)->delete();
        $taches = DB::table('taches')->get();
        $this->assertEquals(count($taches), 1);
    }


    public function tearDown() {
        Artisan::call('migrate:reset');
        parent::tearDown();
    }
}

Tester le bon fonctionnement de l’API DB

En utilisant la documentation Query Builder et en analysant le fichier de tests, comment fait-on pour récupérer les tâches dans la table taches

Comment modifier un enregistrement de la table taches à l’aide de l’API DB

Comment supprimer un enregistrement de la table taches à l’aide de l’API DB

1.4.2 Couche vue contrôleur de l’application web

Laravel propose une commande qui crée un contrôleur ‘CRUD’ (_Create_, Read, Update, Delete) pour gérer les données d’une table. Ici nous allons donc créer un contrôleur CRUD pour gérer les tâches.

php artisan make:controller TacheController --resource

crée un fichier TacheController dans le répertoire app/Http/Controllers qui contient les méthodes permettant de gérer la table taches.

Note: Vous avez peut être déjà créé le controleur dans une question précédente, dans ce cas il faut le supprimer et relancer la commande pour disposer de toutes les méthodes.

Le tableau tirer de la documentation laravel controllers résume les méthodes et l’utilisation qui en est faite.

Commande URI Action Route Name
GET /taches index taches.index
GET /taches/create create taches.create
POST /taches store taches.store
GET /taches/{tache} show taches.show
GET /taches/{tache}/edit edit taches.edit
PUT/PATCH /taches/{tache} update taches.update
DELETE /taches/{tache} destroy taches.destroy

Dans le fichier routes/web.php la règle

Route::resource('taches', 'TacheController');

permet de relier, en une fois, les couples commandes, URI et les actions.

1.4.2.1 Les directives

Laravel permet de simplifier l’écriture des templates blade en utilisant des directives. Dans la suite du TP nous allons utiliser deux directives :

  • accomplie qui renvoie un boolean qui vaut false si l’expression $expr est vide ou contient la chaîne de caractères “N” et true sinon;
  • frdatetime qui renvoie la date donnée en paramètre en français.

Le code qui suit doit être ajouter dans la fonction boot de la classe AppServiceProvider dans le répertoire app/Providers.

Créer le contrôleur TacheController

Ajouter les routes dans le fichier le fichier routes/web.php

Ajouter les directives dans le fichier AppServiceProvider

1.4.3 Liste des tâches

Nous avons créé le contrôleur TacheController ainsi que les règles qui déclenchent la méthode à partir de l’URI, pour afficher la liste des tâches, il reste à

  1. Ajouter le contenu nécessaire dans la méthode index du contrôleur TacheController;
  2. Placer une vue qui affiche la liste des tâches.

Les tâches vont être affichées dans un tableau une ligne du tableau correspond à une tâche. La ligne contiendra

  • La date (on utilisera la directive frdatetime pour avoir le bon format),
  • La catégorie,
  • La description,
  • un icone qui indique si la tâche a été réalisée ou non
  • un groupe de 2 boutons
    • Un bouton de modification
    • Un bouton de suppression

La structure générale de la page tache/index.blade.php est la suivante

{{-- A partir du layout master --}}
@extends("layout.master")

{{-- insertion de la section 'content' --}}
@section('content')
    <h1>Liste des tâches</h1>

    <div>
        {{-- Bouton pour pouvoir ajouter une nouvelle tâche --}}
        <p><a href="taches/create" class="btn btn-primary" role="button">Ajouter une tâche</a></p>
    </div>
    {{-- On affiche un tableau si il y a des tâches ...  --}}
    @if(!(count($taches) === 0))
        <table class="table">
            <thead style="background-color: #ddd; font-weight: bold;">
            <tr>
                <td class="header">Expiration</td>
                <td class="header">Catégorie</td>
                <td class="header">Description</td>
                <td class="header">Réalisée</td>
                <td>Modification/Suppression</td>
            </tr>
            </thead>
            <tbody>
            @foreach ($taches as $tache)
                <tr>
                    <td>{{-- affichage de la date --}}</td>
                    <td>{{-- affichage de la catégorie --}}</td>
                    <td>{{-- affichage de la description --}}</td>
                    <td> {{-- affichage d'un icon qui indique si la tâche est accomplie ou pas --}}
                        @if($tache->accomplie == 'O')
                            <span class="far fa-check-square fa-2x"
                                  aria-hidden="true"></span>
                        @else
                            <span class="far fa-square fa-2x"
                                  aria-hidden="true"></span>                    
                        @endif
                    </td>
                    <td>{{-- affichage d'un bouton pour la modification et un bouton pour la suppression --}}
                        <div class="btn-group">
                            <a href="taches/{{$tache->id}}/edit" class="btn btn-warning" role="button">
                              <span class="far fa-edit fa-2x" aria-hidden="true"></span>
                            </a>
                            <a href="taches/{{$tache->id}}" class="btn btn-danger" role="button">
                              <span class="far fa-trash-alt fa-2x" aria-hidden="true"></span>
                            </a>
                        </div>
                    </td>
                </tr>
            @endforeach
            </tbody>
        </table>
    @else
        <div class="alert alert-warning" role="alert">Aucune tâche dans la base</div>
    @endif
@endsection

Voici une figure qui représente la liste attendue :

Réaliser la page permettant d’affichier la liste des tâches

Il vous faudra pour cela compléter les fichiers : TacheController.php (la méthode index) et index.blade.php

1.4.4 Création d’une tâche

Ici, c’est la méthode create du contrôleur TacheController qui doit être déclenchée pour afficher l’écran de saisie d’une tâche. Une fois la saisie effectuée par l’utilisateur, il faut déclenchée la méthode store qui doit vérifier que les données saisies sont valides et les stocker dans la base de données.

Voici un exemple de page html qui contient un formulaire de saisie d’une tâche :

@extends("layout.master")

@section('content')
    {{-- Affiche les erreurs --}}
    @if ($errors->any())
        <div class="alert alert-danger"  style="margin-top: 2rem">
            <ul>
                @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif
    {{--
         formulaire de saisie d'une tâche
         la fonction 'route' utilise un nom de route
         'csrf_field' ajoute un champ caché qui permet de vérifier
           que le formulaire vient du serveur.
      --}}

    <form action="{{route('taches.store')}}" method="POST">
        {!! csrf_field() !!}
        <div class="text-center" style="margin-top: 2rem">
            <h3><i class="far fa-edit"></i> Création d'une tâche</h3>
            <hr class="mt-2 mb-2">
        </div>
        <div class="form-group row">
            <label class="col-md-3 form-control-label" for="expiration"><strong>Date d'expiration
                    : </strong></label>
            <div class="col-md-3">
                <div class="input-group date">
                            <span class="input-group-addon">
                                <i class="far fa-calendar"></i>
                            </span>
                    <input type="date" class="form-control" name="expiration" id="expiration"
                           value="{{ old('expiration') }}" class="form-control"
                           placeholder="aaaa-mm-jj">
                </div>
            </div>
        </div>
        <div class="form-group row">
        {{-- la catégorie  --}}
            <label class="col-md-3 form-control-label" for="categorie"></label>
            <div class="col-md-4">
                {{-- input de la catégorie --}}
            </div>
            <label class="col-md-2 form-control-label" for="select">
                <strong>Accomplie ?</strong>
            </label>
            <div class="btn-group btn-group-toggle" data-toggle="buttons" class="col-md-2">
                <label class="btn btn-outline-primary @accomplie(old('accomplie')) active @endaccomplie">
                    <input type="radio" name="accomplie"  value = "O" id="accomplie-on"> Oui
                </label>
                <label class="btn btn-outline-primary @accomplie(old('accomplie')) @else active @endaccomplie">
                    <input type="radio" name="accomplie" value = "N" id="accomplie-off"> Non
                </label>
            </div>
        </div>

        <div class="form-group row">
            <label class="col-md-3 form-control-label" for="textarea-input">Description :</label>
            <div class="col-md-9">
                        <textarea name="description" id="description" rows="6" class="form-control"
                                  value="{{ old('description') }}" placeholder="Description.."></textarea>
            </div>
        </div>

        <div class="text-center">
            <button class="btn btn-success" type="submit">Valide</button>
        </div>
    </form>
@endsection

La ligne

{!! csrf_field() !!}

permet de vérifier que le formulaire provient bien du serveur.

Les premières lignes vont permettre d’afficher les erreurs constatées lors de la précédente saisie. La variable errors est gérée par Laravel et contient le résultat de la vérification des données saisies. On verra dans la suite du TP comment on spécifie des règles de validation des données saisies.

Note: Vous aurez noté que le formulaire renvoie le traitement du formulaire vers la route nommée taches.store en utilisant la commande POST. Ce qui provoquera l’exécution de la méthode store du controleur TacheController (voir le tableau de correspondance entre les couples commandes, URI et les actions).

1.4.4.1 La fonction old

Laravel met à votre disposition (stocke dans une variable flash) les valeurs saisies dans un formulaire pour pouvoir les ré-injecter dans le même formulaire en cas d’erreur (voir la documentation old input).

Note: En effet, en cas d’erreur dans la saisie d’un formulaire (voir la suite du TP), Laravel redirige la requête vers la page qui contient le formulaire. La fonction old, vous aide à extraire les valeurs précédemment saisies pour les afficher dans le formulaire. Sans ce mécanisme, du fait de la redirection (nouvelle requête), les données saisies seraient perdues (il faudrait les stocker dans une session).

Mettre en place la saisie d’une tâche

1.4.4.2 La validation et le stockage d’une tâche

Comme vu précédemment, la fin de la saisie du formulaire déclenche l’exécution de la fonction store du contrôleur TacheController. Cette fonction va valider les données saisies et seulement si toutes les données sont correctes alors la sauvegarde dans la base de données est effectuée. En cas d’erreur, Laravel renvoie automatiquement vers la page contenant le formulaire, le programmeur peut alors indiquer les erreurs à l’utilisateur en utilisant la variable errors.

Laravel propose un mécanisme de validation qui fonctionne à l’aide de règles de validation. Pour plus de précisions voir la documentation sur les règles de validation. Il est possible d’indiquer :

  • qu’un champ est obligatoire
  • que le champ doit avoir une valeur numérique, alphabétique, suivre le format d’une expression régulière, …
  • qu’un champ est une adresse mail
  • qu’un champ doit avoir entre plus de n caractères et/ou moins de m caractères, …

L’extrait de programme suivant donne un exemple de règles pour valider la saisie d’une tâche.

Si la fonction s’exécute sans erreur alors le code qui suit est exécuté, sinon la requête est redirigée vers la page contenant le formulaire.

Voici le code complet de la fonction store :

Le paramètre request de type Request contient les informations de la requête (voir la documentation HTTP requests) et en particulier les données saisies dans le formulaire. L’instruction

    $input = $request->only(['expiration', 'categorie', 'description', 'accomplie']);

stocke dans la variable $input de type tableau associatif les champs contenant les informations de la tâche à créer. L’instruction qui suit (dans le code qui précède), déclenche l’insertion d’un nouvel enregistrement dans la table taches.

Mettre en place la validation et le stockage d’une tâche

1.4.5 La modification d’une tâche

Pour modifier une tâche, il faut commencer par récupérer son numéro. Celui-ci sera fourni à partir de la route

/taches/{tache}/edit

qui va déclencher la méthode edit du contrôleur. Cette méthode accepte un paramètre qui est le numéro de la tâche

public function edit($id) {...}

La modification d’une tâche utilise à peu de chose près, le même formulaire de saisie.

Les différences sont

  • Il faut fournir les données de la tâche à modifier, donc dans le contrôleur, il faut consulter la base de données pour récupérer les données de la tâche à modifier
  • Fournir les données à la vue (tache/edit.blade.php)

Voici le code de la page tache/edit.blade.php

Note : La ligne

  {!! method_field('PUT') !!}

est utilisée car la balise form en HTML ne permet pas d’indiquer PUT, PATCH, DELETE comme valeur pour l’attribut method. Laravel utilise un champ caché dans le formulaire pour l’indiquer au service de routage du serveur qui traitera la requête comme une requête avec la commande PUT.

Le nom de la route taches.update est utilisée avec un paramètre id de valeur $tache->id.

Le formulaire après validation doit déclencher la fonction update du contrôleur, qui comme la fonction store doit valider la saisie avant de modifier la base de données.

Mettre en place la modification d’une tâche

1.4.6 La suppression d’une tâche

Pour supprimer une tâche, il faut exécuter l’instruction suivante

            DB::table('taches')->where('id', $id)->delete();

Mais il est d’usage de demander une validation à l’utilisateur avant la suppression définitive des données. Pour cela nous allons dans un premier temps afficher les données de la tâche en utilisant la fonction show du contrôleur et demander à l’utilisateur de valider la suppression.

Voici le code de la page tache/show.blade.php

Note : Même chose que précédemment pour la ligne

  {!! method_field('DELETE') !!}

qui indique au service de routage une requête de suppression.

On exécutera la fonction destroy du contrôleur qui dans le cas d’une validation de la suppression exécutera l’instruction précédente et en cas d’annulation ne fera rien. La dernière instruction redirigera vers l’affichage de la liste des tâches.

        return redirect('/taches');

Mettre en place la suppression d’une tâche


 

IUT de Lens Département Informatique

2018