Cours pour apprendre à utiliser le framework Laravel 5.5

Les données


précédentsommairesuivant

I. Migrations et modèles

Dans cette deuxième partie du cours je vais me référer à l'application d'exemple présente sur Github plutôt que d'élaborer des mini-applications pas trop réalistes. On va ainsi progresser dans l'apprentissage de Laravel en décortiquant cette application très complète. Il vous faut donc l'installer en suivant la procédure indiquée…

I-A. Les migrations

Une migration permet de créer et de mettre à jour un schéma de base de données. Autrement dit, vous pouvez créer des tables, des colonnes dans ces tables, en supprimer, créer des index… Tout ce qui concerne la maintenance de vos tables peut être pris en charge par cet outil. Vous avez ainsi un suivi de vos modifications.

I-A-1. La configuration de la base

Vous devez dans un premier temps avoir une base de données. Laravel permet de gérer les bases de type MySQL, Postgres, SQLite et SQL Server. Je ferai tous les exemples avec MySQL mais le code sera aussi valable pour les autres types de bases.

Il faut indiquer où se trouve votre base, son nom, le nom de l'utilisateur et le mot de passe dans le fichier de configuration .env :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

Ici nous avons les valeurs par défaut à l'installation de Laravel. Il faudra évidemment modifier ces valeurs selon votre contexte de développement et définir surtout le nom de la base, le nom de l'utilisateur et le mot de passe. Pour une installation de MySQL en local en général l'utilisateur est root et on n'a pas de mot de passe.

I-A-2. Artisan

Nous avons déjà utilisé Artisan qui permet de faire beaucoup de choses, vous avez un aperçu des commandes en entrant :

 
Sélectionnez
php artisan

Vous avez une longue liste. Pour ce chapitre nous allons nous intéresser uniquement à celles qui concernent les migrations :

Image non disponible

On dispose de six commandes :

  • fresh : supprime toutes les tables et relance la migration (commande apparue avec la version 5.5) ;
  • install : crée et informe la table de référence des migrations ;
  • refresh : réinitialise et relance les migrations ;
  • rollback : annule la dernière migration ;
  • status : donne des informations sur les migrations.

I-A-3. Installation

Si vous regardez dans le dossier database/migrations il y a déjà deux migrations présentes :

Image non disponible
  • table users : c'est une migration de base pour créer une table des utilisateurs ;
  • table password_resets : c'est une migration liée à la précédente qui permet de gérer le renouvellement des mots de passe en toute sécurité.

Puisque ces migrations sont présentes autant les utiliser pour nous entraîner.

Commencez par créer une base MySQL et informez .env, par exemple :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel5
DB_USERNAME=root
DB_PASSWORD=

Lancez alors la commande install :

Image non disponible

On se retrouve alors avec une table migrations dans la base avec cette structure :

Image non disponible

Pour le moment cette table est vide, elle va se remplir au fil des migrations pour les garder en mémoire.

Vous n'aurez jamais à intervenir directement sur cette table qui est là juste pour la gestion effectuée par Laravel.

I-A-4. Constitution d'une migration

Si vous ouvrez le fichier database/migrations/2014_10_12_000000_create_users_table.php vous trouvez ce code :

 
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.
28.
29.
30.
31.
32.
33.
34.
35.
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

On dispose dans cette classe de deux fonctions :

  • up : ici on a le code de création de la table et de ses colonnes ;
  • down : ici on a le code de suppression de la table.

I-A-5. Lancer une migration

Pour lancer toutes les migrations on utilise la commande migrate :

Image non disponible

On voit que les deux migrations présentes ont été exécutées et on trouve les deux tables dans la base :

Image non disponible

Pour comprendre le lien entre migration et création de la table associée voici une illustration pour la table users :

Image non disponible

La méthode timestamps permet la création des deux colonnes created_at et updated_at.

I-A-6. Annuler ou rafraîchir une migration

Pour annuler une migration on utilise la commande rollback :

Image non disponible

Les méthodes down des migrations sont exécutées et les tables sont supprimées.

Pour annuler et relancer en une seule opération on utilise la commande refresh :

Image non disponible

Pour éviter d'avoir à coder ces méthodes down, la version 5.5 a prévu la commande fresh qui supprime automatiquement les tables concernées.

I-A-7. Créer une migration

Il existe une commande d'Artisan pour créer un squelette de migration :

Image non disponible

La migration est créée dans le dossier :

Image non disponible

Avec ce code de 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.
24.
25.
26.
27.
28.
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Test extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        //
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}

Il faut ensuite compléter ce code selon vos besoins !

Le nom du fichier de migration commence par sa date de création, ce qui conditionne son positionnement dans la liste. L'élément important à prendre en compte est que l'ordre des migrations prend une grande importance lorsqu'on a des clés étrangères !

I-A-8. Les migrations de l'application d'exemple

L'application d'exemple comporte de nombreuses migrations :

Image non disponible

Pour le présent chapitre nous allons nous intéresser à la migration de la table contacts :

 
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.
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateContactsTable extends Migration {

  public function up()
  {
    Schema::create('contacts', function(Blueprint $table) {
      $table->increments('id');
      $table->timestamps();
      $table->string('name');
      $table->string('email');
      $table->text('message');
    });
  }

  public function down()
  {
    Schema::drop('contacts');
  }
}

Pour cette table on a :

  • une colonne clé incrémentée id (increments) ;
  • les colonnes created_at et updated_at créées par la méthode timestamps ;
  • une colonne name de type varchar (string) ;
  • une colonne email de type varchar (string) ;
  • une colonne text de type text (text).

Lorsque vous lancez les migrations la table contacts est créée :

Image non disponible

Cette table est destinée dans l'application à mémoriser les messages laissés par les visiteurs lorsqu'ils accèdent au formulaire avec cet item du menu :

Image non disponible

I-B. La population (seeding)

En plus de proposer des migrations Laravel permet aussi la population (seeding), c'est-à-dire un moyen simple de remplir les tables d'enregistrements. Les classes de la population se trouvent dans le dossier databases/seeds:

Image non disponible

On est libre d'organiser les classes comme on veut dans ce dossier. Dans l'application d'exemple il n'y a qu'une classe.

Lorsqu'on installe Laravel on dispose de la classe DatabaseSeeder avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
<?php

use Illuminate\Database\Seeder;

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

On a un appel commenté à une classe UserTableSeeder qui pourrait être une classe pour remplir la table users.

Dans la fonction run on met tout le code qu'on veut pour remplir les tables. Dans l'application d'exemple on a :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
User::create(
    [
        'name' => 'GreatAdmin',
        'email' => 'admin@la.fr',
        'password' => bcrypt('admin'),
        'role' => 'admin',
        'valid' => true,
        'confirmed' => true,
        'remember_token' => str_random(10),
    ]
);

Ici on crée l'enregistrement d'un utilisateur dans la table users avec l'ORM Eloquent dont je vais parler ci-dessous.

Je reviendrai dans ce cours sur la population quand on aura avancé notre connaissance des outils pour les bases de données. Je vais juste ajouter qu'on lance la population avec cette commande :

 
Sélectionnez
php artisan db:seed

I-C. Eloquent

Laravel propose un ORM (acronyme de object-relational mapping ou en bon français une correspondance objet-relationnel) très performant.

De quoi s'agit-il ?

Tout simplement que tous les éléments de la base de données ont une représentation sous forme d'objets manipulables.

Quel intérêt ?

Tout simplement de simplifier grandement les opérations sur la base comme nous allons le voir dans toute cette partie du cours.

Avec Eloquent une table est représentée par une classe qui étend la classe Model. On peut créer un modèle avec Artisan :

 
Sélectionnez
php artisan make:model Test

On trouve le fichier ici :

Image non disponible

Avec cette trame de base :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Test extends Model
{
    //
}

On peut créer un modèle en même temps que la migration pour la table avec cette syntaxe :

 
Sélectionnez
php artisan make:model Test -m
Image non disponible

Dans l'application d'exemple les modèles sont rassemblés dans un dossier spécifique dans un souci d'organisation :

Image non disponible

Ce modèle Contact correspond par défaut à la table contacts. Eloquent a quelques conventions de ce genre qui simplifient le codage. Si le nom de la table ne répond pas à la convention il faut prévoir une propriété $table pour préciser ce nom.

I-D. Routes et contrôleur

I-D-1. Routes

Pour les contacts dans l'application il faut deux routes :

  • une route pour envoyer le formulaire à l'utilisateur ;
  • une route pour la validation du formulaire.

Si vous regardez dans le fichier routes/web.php vous trouvez cette ligne de code :

 
Sélectionnez
Route::resource('contacts', 'Front\ContactController', ['only' => ['create', 'store']]);

La méthode resource crée par défaut ces sept routes CRUD :

Verbe

URI

Action

Nom de la route

GET

/contacts

index

contacts.index

GET

/contacts/create

create

contacts.create

POST

/contacts

store

contacts.store

GET

/contacts/{contact}

show

contacts.show

GET

/contacts/{contact}/edit

edit

contacts.edit

PUT/PATCH

/contacts/{contact}

update

contacts.update

DELETE

/contacts/{contact}

destroy

contacts.destroy

Il existe une commande d'Artisan pour créer un contrôleur qui digère directement toutes ces routes :

 
Sélectionnez
php artisan make:controller ContactController --resource

Je reviendrai sur ce point dans un chapitre ultérieur. Pour le moment notre contrôleur de contact se contentera de deux méthodes (create et store), c'est pour cette raison qu'on utilise le only dans la syntaxe de la route pour générer seulement les deux routes correspondantes. On aurait aussi pu détailler les deux routes :

 
Sélectionnez
Route::name('contacts.create')->get('contacts', 'Front\ContactController@create');
Route::name('contacts.store')->post('contacts', 'Front\ContactController@store');

I-D-2. Contrôleur

Le contrôleur est rangé ici :

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.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
<?php

namespace App\Http\Controllers\Front;

use App\ {
    Http\Controllers\Controller,
    Http\Requests\ContactRequest,
    Models\Contact
};

class ContactController extends Controller
{
    /**
     * Create a new ContactController instance.
     *
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Show the form for creating a new contact.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view ('front.contact');
    }

    /**
     * Store a newly created contact in storage.
     *
     * @param  ContactRequest $request
     * @return \Illuminate\Http\Response
     */
    public function store(ContactRequest $request)
    {
        Contact::create ($request->all ());

        return back ()->with ('ok', __('Your message has been recorded, we will respond as soon as possible.'));
    }
}

La méthode create ne présente aucune nouveauté : elle se contente de renvoyer une vue avec le formulaire.

La méthode store est chargée de mémoriser les informations dans la table contacts. On voit qu'on utilise la méthode create du modèle pour le réaliser. Il suffit de donner comme paramètres à cette méthode les entrées du formulaire.

Remarquez qu'on utilise une requête de formulaire (ContactRequest) pour la validation avec des règles classiques :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
public function rules()
{
    return [
        'name' => 'bail|required|max:255',
        'email' => 'bail|required|email',
        'message' => 'bail|required|max:1000'
    ];
}

I-E. Le modèle en détail

Modifiez ainsi le code dans le contrôleur ContactController :

 
Sélectionnez
dd(Contact::create ($request->all ()));

L'helper dd est bien pratique : il regroupe un var_dump et un die. Ici si on soumet le formulaire on va observer de plus près le modèle créé parce que la méthode create renvoie ce modèle  :

 
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.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
Contact {#302 ▼
 #dispatchesEvents: array:1 [▶️]
 #fillable: array:3 [▼
   0 => "name"
   1 => "email"
   2 => "message"
 ]
 #connection: "mysql"
 #table: null
 #primaryKey: "id"
 #keyType: "int"
 +incrementing: true
 #with: []
 #withCount: []
 #perPage: 15
 +exists: true
 +wasRecentlyCreated: true
 #attributes: array:6 [▼
   "name" => "Durand"
   "email" => "durand@chezlui.fr"
   "message" => "Mon message"
   "updated_at" => "2017-09-11 15:28:59"
   "created_at" => "2017-09-11 15:28:59"
   "id" => 7
 ]
 #original: array:6 [▶️]
 #changes: []
 #casts: []
 #dates: []
 #dateFormat: null
 #appends: []
 #observables: []
 #relations: []
 #touches: []
 +timestamps: true
 #hidden: []
 #visible: []
 #guarded: array:1 [▶️]
}

On a pas mal de propriétés mais surtout des attributs (attributes) et on se rend compte que chacun de ces attributs correspond à une colonne de la table contact :

Image non disponible

I-E-1. Méthode create et assignement de masse

Par sécurité ce type d'assignement de masse (on transmet directement un tableau de valeurs issues du client avec la méthode create) est limité pour la sécurité par une propriété au niveau du modèle qui désigne précisément les noms des colonnes susceptibles d'être modifiées. Si vous regardez dans le fichier app/Models/Contact.php vous trouvez cette propriété :

 
Sélectionnez
protected $fillable = ['name', 'email', 'message'];

Ce sont les seules colonnes qui seront impactées par la méthode create (et équivalentes). Attention à cela lorsque vous avez un bug mystérieux avec des colonnes qui ne se mettent pas à jour !

Mais quel est le risque ?

Imaginez qu'il y ait une autre colonne avec des données sensibles et non prévue dans le formulaire mais qu'un petit malin l'ajoute à la requête, cette colonne serait mise à jour en même temps que les autres !

I-F. Les vues

Je ne vais pas détailler les vues dans ce chapitre consacré aux données. Je signale juste que les vues sont rangées dans des dossiers :

Image non disponible

Le template pour les vues du front est layout.blade.php. Le template utilisé est issu de cette source :

Image non disponible

Je l'ai évidemment adapté pour Laravel mais je consacrerai un chapitre sur le sujet parce que de nombreuses possibilités de Blade ont été utilisées.

Le formulaire de contact a cet aspect :

Image non disponible

I-G. En résumé

  • La base de données doit être configurée pour fonctionner avec Laravel.
  • Les migrations permettent d'intervenir sur le schéma des tables de la base.
  • Eloquent permet une représentation des tables sous forme d'objets pour simplifier les manipulations des enregistrements.
  • L'assignement de masse est limité par la propriété $fillable.

précédentsommairesuivant

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

  

Copyright © 2018 Laravel. Aucune reproduction, même partielle, ne peut être faite de ce site ni 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.