Créer une application avec Laravel 5.5 – 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.
Les utilisateurs
Dans l’installation de base on a déjà une migration pour les utilisateurs :
<?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->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 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 deux 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; class UsersTableSeeder extends Seeder { public function run() { User::create([ 'name' => 'Durand', 'email' => 'durand@chezlui.fr', 'role' => 'admin', 'password' => bcrypt('admin'), ]); User::create([ 'name' => 'Dupont', 'email' => 'dupont@chezlui.fr', 'password' => bcrypt('user'), ]); } }
On aura ainsi un administrateur et un utilisateur.
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, ], ],
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 :
- un nom (pas le nom de la photo mais celui du fichier !)
- une description optionnelle
- 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->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::table('images', function(Blueprint $table) { $table->dropForeign('images_category_id_foreign'); }); Schema::table('images', function(Blueprint $table) { $table->dropForeign('images_user_id_foreign'); }); Schema::dropIfExists('images'); } }
Remarquez que la colonne description est nullable puisqu’on la veut optionnelle.
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 :
Avec les deux utilisateurs prévus :
La table categories :
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
public function images() { return $this->hasMany(Image::class); }
Category
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éé deux utilisateurs dont un administrateur
Pour vous simplifier la vie vous pouvez charger le projet dans son état à l’issue de ce chapitre.
6 commentaires
dsigner
Bonjour à tous, je suis très attentivement ce tuto, neanmonoins je suis fasse ç une erreur:
L’orsque je lance la commande ‘php artisan migrate:fresh –seeder’ voici les réponses que j’obtiens:
Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrating: 2018_08_09_100629_create_categories_table
Migrated: 2018_08_09_100629_create_categories_table
Migrating: 2018_08_09_103052_create_images_table
Migrated: 2018_08_09_103052_create_images_table
Seeding: UsersTableSeeder
In UsersTableSeeder.php line 14:
Class ‘User’ not found
bestmomo
Salut,
Si la classe User n’est pas trouvée c’est peut-être qu’il manque le use App\Models\User; dans le seeder ou alors que la classe en question n’est pas présente dans cet emplacement.
dsigner
Effectivement c’est vous qui aviez raison, après vérification j’ai remarqué qu’il manquait le « use App\Models\User » dans le seeder. Maintenant ça fonctionne, merci pour votre aide.
Juluismont
Un grand merci pour cette documentation spécifique pas-à-pas, Congrats!
Un petit modif aussi à apporter au fichier App\provoders\AppServiceProvider.php si éventuellement vous avez cette erreur :
« In Connection.php line 664:
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQ
L: alter table `users` add unique `users_email_unique`(`email`))
In Connection.php line 458:
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes »
en lançant les migrations avec : php artisan migrate:fresh –seed
MODIFIER le App\provoders\AppServiceProvider.php comme ceci :
php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
Schema::defaultStringLength(191);
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}
En fait ceci a marché pour moi, si cela peut aider quelqu'un.
LIEN : https://stackoverflow.com/questions/23786359/laravel-migration-unique-key-is-too-long-even-if-specified
bestmomo
Salut,
Une solution plus simple est de mettre à niveau MySQL.
romaindrx
Bonjour,
Tout d’abord un grand merci pour ce genre de documentation. A ma perception il manque des details (descriptions) mais vraiment un beau travail.
Dans mon cas j’ai rencontrer quelques glitch par exemple pour ce genre de commande :
php artisan make:model Models\Image –migration ne fonctionne pas dans mon terminal (mac OS, iterm),
mais avec comme ceci tout fonctionne : php artisan make:model Models/Image –migration. (le slash du path) du coup toutes les commandes je les tapes comme ci.
Je vais continuer a apprendre et me regaler, merci encore!