Laravel 5.7 par la pratique – Les données
Dans ce chapitre nous allons nous intéresser aux données et construire le schéma de la base pour la gestion de notre galerie photos. Laravel est équipé d’un efficace système de migrations couplé à un constructeur de schéma tout aussi efficace. D’autre part on dispose aussi d’un système de population (seeder) qui permet de remplir facilement les tables. On complétera ça en créant les modèles avec leurs relations.
On va commencer avec des données simples : les utilisateurs, les catégories et les images. On complètera dans les prochaines étapes.
Les utilisateurs
Dans l’installation de base on a déjà une migration pour les utilisateurs :
Avec ce code :
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateUsersTable extends Migration { public function up() { Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } public function down() { Schema::dropIfExists('users'); } }
Comme on doit distinguer les utilisateurs de base, qui peuvent juste ajouter et supprimer leurs photos et les administrateurs qui ont tous les droits il nous faut ajouter quelque chose.
Si on avait plus de distinctions à faire on ferait appel à l’un des nombreux packages qui existent comme bouncer, laratrust, ou laravel-permission. Mais dans notre cas ça serait vraiment excessif et on va se contenter d’ajouter une colonne de type ENUM :
$table->enum('role', ['user', 'admin'])->default('user');
On a donc les deux rôles : user et admin et par défaut c’est user qui est affecté.
On va aussi éviter d’avoir des noms identiques :
$table->string('name')->unique();
On complétera dans un chapitre ultérieur pour le profil mais pour le moment on va se contenter de ça.
Pour notre application on va aussi créer 3 utilisateurs par défaut. Quand on regarde dans le fichier database/seeds/DatabaseSeeder.php on trouve ce code :
public function run() { // $this->call(UsersTableSeeder::class); }
On va dé-commenter la ligne et créer la classe UsersTableSeeder :
php artisan make:seeder UsersTableSeeder
On va changer le code pour celui-ci :
<?php use Illuminate\Database\Seeder; use App\Models\User; use Carbon\Carbon; class UsersTableSeeder extends Seeder { public function run() { User::create([ 'name' => 'Durand', 'email' => 'durand@chezlui.fr', 'role' => 'admin', 'password' => bcrypt('admin'), 'email_verified_at' => Carbon::now(), ]); User::create([ 'name' => 'Dupont', 'email' => 'dupont@chezlui.fr', 'password' => bcrypt('user'), 'email_verified_at' => Carbon::now(), ]); User::create([ 'name' => 'Martin', 'email' => 'martin@chezlui.fr', 'password' => bcrypt('user'), 'email_verified_at' => Carbon::now(), ]); } }
On aura ainsi un administrateur et 2 utilisateurs.
Les modèles
Comme on va créer de nouveaux modèles on va commencer par un peu réorganiser nos dossiers en prévoyant un dossier pour les modèles plutôt que de les empiler à la racine de l’application. Pour le moment on a seulement User :
On crée le dossier Models et on déplace User dedans :
Dans le code on change l’espace de nom :
namespace App\Models;
Un truc plus vicieux facile à oublier est la configuration de l’authentification (config/auth.php) :
'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ], ],
D’autre part il faut aussi actualiser le use dans le contrôleur RegisterController :
use App\Models\User;
Les catégories
Voyons ce dont nous aurons besoin pour la tables des catégories :
- un nom
- un slug
Le slug est une version transformée du nom pour être intégrée dans une url. Si par exemple le nom est Les Maisons il est évident qu’on ne peut pas intégrer ça directement dans une url. On va donc transformer le nom en les-maisons par exemple et là ça ira.
Pour être efficace on va créer le modèle en même temps que la migration :
php artisan make:model Models/Category --migration
Dans le code de la migration changez ainsi la fonction up :
public function up() { Schema::create('categories', function (Blueprint $table) { $table->increments('id'); $table->string('name')->unique(); $table->string('slug')->unique(); $table->timestamps(); }); }
On demande que les deux colonnes name et slug comportent des valeurs uniques, ce qui est logique.
Le modèle
Pour le modèle pour le moment on va juste ajouter les deux colonnes pour l’assignement de masse :
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Category extends Model { protected $fillable = [ 'name', 'slug', ]; }
Les images
Il ne nous reste plus qu’à nous occuper des images, là aussi nous avons besoin du modèle et de la migration :
php artisan make:model Models\Image --migration
Pour les images on va avoir besoin de :
- un nom (pas le nom de la photo mais celui du fichier !)
- une description optionnelle
- un champ booléen pour savoir si le statut est « adulte »
- un entier pour compter les clics sur l’image
- une clé étrangère pour les utilisateurs
- une clé étrangère pour les catégories
Ce qui donne cette migration :
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateImagesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('images', function (Blueprint $table) { $table->increments('id'); $table->integer('category_id')->unsigned(); $table->integer('user_id')->unsigned(); $table->string('name'); $table->string('description')->nullable(); $table->boolean('adult')->default(false); $table->integer ('clicks')->unsigned()->default(0); $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('images'); } }
Remarquez que la colonne description est nullable puisqu’on la veut optionnelle.
La valeur par défaut pour le statut adulte est false.
Pour le nombre de clics on part logiquement de 0 avec un entier non signé.
D’autre part on fait le choix de la suppression en cascade, donc en cas de suppression d’un utilisateur ou d’une catégorie les images correspondantes seront aussi supprimées.
Pour le modèle pour le moment on ne va rien changer.
On migre !
On est maintenant prêts pour faire nos migrations :
php artisan migrate:fresh --seed
Vérifiez que tout est correct. Pour la table users :
Pour la gestion MySQL j’utilise en général dbForge Studio for MySQL Express ou MySQL Workbench.
Avec les 3 utilisateurs prévus :
Et enfin la table images :
Les relations
On va établir ces relations :
- User hasmany Image
- Category hasMany Image
Et évidement les réciproques.
Voici le schéma de la base :
User
/** * Get the images. */ public function images() { return $this->hasMany (Image::class); }
Category
/** * Get the images. */ public function images() { return $this->hasMany (Image::class); }
Image
public function category() { return $this->belongsTo(Category::class); } public function user() { return $this->belongsTo(User::class); }
Conclusion
Dans ce chapitre on a :
- créé toutes les migrations pour la galerie
- créé les modèles avec leurs relations
- créé un dossier spécifique pour les modèles
- créé 3 utilisateurs dont un administrateur
Pour vous simplifier la vie vous pouvez charger le projet dans son état à l’issue de ce chapitre.
9 commentaires
theuglife
est-il possible de recuperer l’id, est le nom pour en faire une valeur par defaut dans la meme table eloquent?
bestmomo
Salut,
Je ne comprends pas la question…
theuglife
Par exemple si je veux automatiser les emails en prenant comme email : nom.prenomid@mondomaine.com
En le mettant comme email par défaut
j’imagine recupérer le dernier id l’incrémanté de 1 avant de faire l’enregistrement.
je cherche un truc plus élégant
Digger
Une petite erreur également dans le fichier de migrations pour les images afin de créer la table.
J’ai du remplacer le $table->integer(‘user_id’)->unsigned(); par $table->bigInteger(‘user_id’)->unsigned();
😉
bestmomo
Merci, en fait je pense que c’était bon avec Laravel 5.7 mais les integer pour les clés ont changé dans les version ultérieures. L’important est de synchroniser le type en la clé et sa clé étrangère.
La Terreur
Bonjour Mr.
Je voudrais par la présente vous dire un sincère merci pour ce cours qui je suis avec grande admiration pour votre personne. Ceci étant, j’ai suivi à la lettre os instructions et tout marche bien que ce soit dans mon éditeur ou dans la console. Mais par erreur de ma part, j’avais dans un premier temps oublié d’ajouter les lignes :
use App\Models\User;
use Carbon\Carbon;
Conséquence: les ajouts ne sont pas effectifs dans ma bdd, et ceci même après mettre rattraper sur mon erreur. Que me suggérez-vous svp!?
Cordialement
EthanSSS
Bonjour,
J’ai relevé une petite erreur dans la partie « Catégories » et « Images »:
Pour être efficace on va créer le modèle en même temps que la migration :
php artisan make:model Models\Category –migration
La commande adéquate est:
php artisan make:model Models/Category –migration
Sinon, cela crée un modèle nommé ModelsCategory, et un fichier de migration nommé 2018_11_19_151118_create_models_categories_table et non 2018_11_19_151118_create_categories_table
A part ça, ce tuto est vraiment parfait pour se (re)mettre à Laravel. Merci pour ce super boulot.
EthanSSS
D’ailleurs, erreur de ma part:
php artisan make:model Models/Category –migration
🙂
bestmomo
Merci,
C’est corrigé 😉