🏊🏊♂️🏊♀️
NS’App v1.0
## Pour éviter les erreurs de clé étrangère lors de la création des tables
Ordre d’exécution des migrations
- roles
- users
- uploads
- pages
- exercises
- plans
- workouts
- swim_sets
- myliste
- workout_exercises
- workout_swim_sets
- plan_workouts
- myliste_items
-- Migrations & Modèles
Poisson Rouge « Cours »: — Eloquent ORM (Object-Relational Mapping) est le système de gestion de base de données intégré à Laravel. Il permet d’interagir avec la base de données en utilisant des objets PHP plutôt que des requêtes SQL brutes
- ## chaque table de la base de données est représentée par un modèle PHP, ce qui facilite les manipulations de données
Création des Modèles et Relations (Eloquent ORM)
Modèles et Migrations
php artisan make:model Exercise -m
php artisan make:model Page -m
php artisan make:model Plan -m
php artisan make:model PlanWorkout -m
php artisan make:model Role -m
php artisan make:model SwimSet -m
php artisan make:model Upload -m
php artisan make:model User -m
php artisan make:model Workout -m
php artisan make:model WorkoutExercise -m
php artisan make:model WorkoutSwimSet -m
php artisan make:model MyList -m
php artisan make:model MyListItem -m
Poisson Rouge : – Astuce / Exemple : #php artisan make:model Exercise -m –>> genere les modeles et les migrations; #php artisan make:model Exercise -mf –>> genere les modeles et les factories et #php artisan make:model Exercise -mc –>> genere les modeles et les controlleurs
Définir les Relations « One to Many »
Poisson Rouge : — Exemple : Un utilisateur peut avoir plusieurs posts
// App/Models/User.php
public function posts() {
return $this->hasMany(Post::class, 'post_author');
}
// App/Models/Post.php
public function author() {
return $this->belongsTo(User::class, 'post_author');
}
Exemple : Une catégorie a plusieurs posts
// App/Models/Category.php
public function posts() {
return $this->hasMany(Post::class, 'category_id');
}
// App/Models/Post.php
public function category() {
return $this->belongsTo(Category::class, 'category_id');
}
-- Role "M + M"
Role
Migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('roles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->unique(); // Added unique constraint
$table->timestamps(); // Use Laravel's default timestamps
});
// Add foreign key constraint to users table AFTER roles table creation
Schema::table('users', function (Blueprint $table) {
$table->foreignId('role_id')->nullable()->constrained('roles')->onDelete('set null');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
// Drop foreign key constraint before dropping the roles table
Schema::table('users', function (Blueprint $table) {
$table->dropForeign(['role_id']);
});
Schema::dropIfExists('roles');
}
};
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the users for the role.
*/
public function users()
{
return $this->hasMany(User::class);
}
}
-- User "M + M"
User
Migration
// ...
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
// Si role_id n'existe pas, l'ajouter
if (!Schema::hasColumn('users', 'role_id')) {
$table->foreignId('role_id')->nullable()->constrained('roles')->onDelete('set null');
}
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropForeign(['role_id']); // Supprimer la contrainte
});
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable; // Important pour l'authentification
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'username',
'email',
'password',
'first_name',
'last_name',
'role_id', // Assurez-vous que role_id est dans fillable
];
/**
* The attributes that should be hidden for serialization.
*
* @var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed', // Hashage du mot de passe
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the role associated with the user.
*/
public function role()
{
return $this->belongsTo(Role::class);
}
// ... autres relations (exercises, pages, plans, workouts, mylistes)
public function exercises()
{
return $this->hasMany(Exercise::class);
}
public function pages()
{
return $this->hasMany(Page::class);
}
public function plans()
{
return $this->hasMany(Plan::class);
}
public function workouts()
{
return $this->hasMany(Workout::class);
}
public function mylistes()
{
return $this->hasMany(Myliste::class);
}
}
-- Upload "M + M"
Upload
Migration
public function up(): void
{
Schema::create('uploads', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('filename');
$table->string('path');
$table->string('type')->nullable();
$table->foreignId('user_id')->nullable()->constrained('users')->onDelete('set null'); // Clé étrangère
$table->timestamps();
});
// Dans les migrations des tables exercises et pages, ajouter les clés étrangères vers uploads
Schema::table('exercises', function (Blueprint $table) {
$table->foreignId('upload_id')->nullable()->constrained('uploads')->onDelete('set null');
});
Schema::table('pages', function (Blueprint $table) {
$table->foreignId('upload_id')->nullable()->constrained('uploads')->onDelete('set null');
});
}
public function down(): void
{
// Supprimer les clés étrangères dans les tables exercises et pages
Schema::table('exercises', function (Blueprint $table) {
$table->dropForeign(['upload_id']);
});
Schema::table('pages', function (Blueprint $table) {
$table->dropForeign(['upload_id']);
});
Schema::dropIfExists('uploads');
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Upload extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'filename',
'path',
'type',
'user_id',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the user that uploaded the file.
*/
public function user()
{
return $this->belongsTo(User::class);
}
// ... autres relations (exercises, pages)
public function exercises()
{
return $this->hasMany(Exercise::class);
}
public function pages()
{
return $this->hasMany(Page::class);
}
}
-- Page "M + M"
Page
Migration
public function up(): void
{
Schema::create('pages', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->longText('content');
$table->string('page_category')->nullable();
$table->foreignId('upload_id')->nullable()->constrained('uploads')->onDelete('set null'); // Clé étrangère vers uploads
$table->foreignId('user_id')->constrained('users')->onDelete('cascade'); // Clé étrangère vers users
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('pages');
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Page extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'title',
'content',
'page_category',
'upload_id',
'user_id',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the user that created the page.
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* Get the upload associated with the page.
*/
public function upload()
{
return $this->belongsTo(Upload::class);
}
}
-- Exercise "M + M"
Exercise
Migration
public function up(): void
{
Schema::create('exercises', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->text('description')->nullable();
$table->string('exercise_level')->nullable();
$table->string('exercise_category')->nullable();
$table->foreignId('upload_id')->nullable()->constrained('uploads')->onDelete('set null'); // Clé étrangère vers uploads
$table->foreignId('user_id')->constrained('users')->onDelete('cascade'); // Clé étrangère vers users
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('exercises');
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Exercise extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'title',
'description',
'exercise_level',
'exercise_category',
'upload_id',
'user_id',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the user that created the exercise.
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* Get the upload associated with the exercise.
*/
public function upload()
{
return $this->belongsTo(Upload::class);
}
/**
* Get the swim sets for the exercise.
*/
public function swimSets()
{
return $this->hasMany(SwimSet::class);
}
/**
* The workouts that belong to the exercise.
*/
public function workouts()
{
return $this->belongsToMany(Workout::class, 'workout_exercises');
}
}
-- Plan "M + M"
Plan
Migration
public function up(): void
{
Schema::create('plans', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->text('description')->nullable();
$table->string('plan_category')->nullable();
$table->foreignId('user_id')->constrained('users')->onDelete('cascade'); // Clé étrangère vers users
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('plans');
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Plan extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'title',
'description',
'plan_category',
'user_id',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the user that created the plan.
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* The workouts that belong to the plan.
*/
public function workouts()
{
return $this->belongsToMany(Workout::class, 'plan_workouts');
}
}
-- PlanWorkout "M + M"
PlanWorkout
Migration
public function up(): void
{
Schema::create('plan_workouts', function (Blueprint $table) {
$table->foreignId('plan_id')->constrained('plans')->onDelete('cascade');
$table->foreignId('workout_id')->constrained('workouts')->onDelete('cascade');
$table->primary(['plan_id', 'workout_id']); // Clé primaire composite
$table->timestamps(); // Ajout des timestamps pour suivre la création et la modification des associations.
});
}
public function down(): void
{
Schema::dropIfExists('plan_workouts');
}
Modèle
Pas de modèle
Relations dans les modèles Plan et Workout Many-to-Many à définir dans les modèles Plan et Workout :
// Dans Plan
public function workouts()
{
return $this->belongsToMany(Workout::class, 'plan_workouts');
}
//Dans Workout
public function plans()
{
return $this->belongsToMany(Plan::class, 'plan_workouts');
}
-- SwimSet "M + M"
SwimSet
Migration
public function up(): void
{
Schema::create('swim_sets', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreignId('workout_id')->nullable()->constrained('workouts')->onDelete('cascade'); // Clé étrangère vers workouts
$table->foreignId('exercise_id')->nullable()->constrained('exercises')->onDelete('set null'); // Clé étrangère vers exercises
$table->integer('set_distance')->nullable();
$table->integer('set_repetition')->nullable();
$table->integer('rest_time')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('swim_sets');
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class SwimSet extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'workout_id',
'exercise_id',
'set_distance',
'set_repetition',
'rest_time',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the workout that the swim set belongs to.
*/
public function workout()
{
return $this->belongsTo(Workout::class);
}
/**
* Get the exercise that the swim set uses.
*/
public function exercise()
{
return $this->belongsTo(Exercise::class);
}
}
-- Workout "M + M"
Workout
Migration
public function up(): void
{
Schema::create('workouts', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->text('description')->nullable();
$table->string('workout_category')->nullable();
$table->foreignId('user_id')->constrained('users')->onDelete('cascade'); // Clé étrangère vers users
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('workouts');
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Workout extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'title',
'description',
'workout_category',
'user_id',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the user that created the workout.
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* The exercises that belong to the workout.
*/
public function exercises()
{
return $this->belongsToMany(Exercise::class, 'workout_exercises');
}
/**
* The plans that the workout is included in.
*/
public function plans()
{
return $this->belongsToMany(Plan::class, 'plan_workouts');
}
/**
* Get the swim sets for the workout.
*/
public function swimSets()
{
return $this->hasMany(SwimSet::class);
}
}
-- WorkoutExercises "M + M"
workout_exercises
Migration
public function up(): void
{
Schema::create('workout_exercises', function (Blueprint $table) {
$table->foreignId('workout_id')->constrained('workouts')->onDelete('cascade');
$table->foreignId('exercise_id')->constrained('exercises')->onDelete('cascade');
$table->primary(['workout_id', 'exercise_id']); // Clé primaire composite
$table->timestamps(); // Ajout des timestamps pour suivre la création et la modification des associations.
});
}
public function down(): void
{
Schema::dropIfExists('workout_exercises');
}
Modèle
Pas de modèle
Relations Workout et Exercise Many-to-Many dans modèles Workout et Exercise
//Dans Workout.php
public function exercises()
{
return $this->belongsToMany(Exercise::class, 'workout_exercises');
}
// Dans Exercise.php
public function workouts()
{
return $this->belongsToMany(Workout::class, 'workout_exercises');
}
-- WorkoutSwimSets "M + M"
workout_swim_sets
Migration
public function up(): void
{
Schema::create('workout_swim_sets', function (Blueprint $table) {
$table->foreignId('workout_id')->constrained('workouts')->onDelete('cascade');
$table->foreignId('swim_set_id')->constrained('swim_sets')->onDelete('cascade');
$table->primary(['workout_id', 'swim_set_id']); // Clé primaire composite
$table->timestamps(); // Ajout des timestamps pour suivre la création et la modification des associations.
});
}
public function down(): void
{
Schema::dropIfExists('workout_swim_sets');
}
Modèle
Pas de modèle Relations Many-to-Many définies Workout et SwimSet
//Dans Workout.php :
public function swimSets()
{
return $this->belongsToMany(SwimSet::class, 'workout_swim_sets');
}
// Dans SwimSet.php
public function workouts()
{
return $this->belongsToMany(Workout::class, 'workout_swim_sets');
}
-- Myliste "M + M"
myliste
Migration
public function up(): void
{
Schema::create('myliste', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreignId('user_id')->constrained('users')->onDelete('cascade'); // Clé étrangère vers users
$table->string('title');
$table->text('description')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('myliste');
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Myliste extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array<int, string="">
*/
protected $fillable = [
'user_id',
'title',
'description',
];
/**
* The attributes that should be cast.
*
* @var array<string, string="">
*/
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Get the user that owns the myliste.
*/
public function user()
{
return $this->belongsTo(User::class);
}
/**
* Get the items in the myliste.
*/
public function mylisteItems()
{
return $this->hasMany(MylisteItem::class); // Relation avec MylisteItem
}
}
-- MylisteItems "M + M"
Role
Migration
public function up(): void
{
Schema::create('myliste_items', function (Blueprint $table) {
$table->bigIncrements('id');
$table->foreignId('myliste_id')->constrained('myliste')->onDelete('cascade'); // Clé étrangère vers myliste
$table->bigInteger('item_id'); // ID de l'élément (polymorphique)
$table->string('item_type'); // Type de l'élément (polymorphique)
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('myliste_items');
}
Modèle
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class MylisteItem extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'myliste_id',
'item_id',
'item_type',
];
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'created_at' => 'datetime',
];
/**
* Get the myliste that the item belongs to.
*/
public function myliste()
{
return $this->belongsTo(Myliste::class);
}
// Les relations polymorphiques seront définies ici (voir explication plus bas)
}
// La table myliste_items utilise une relation pour lier (exercices, séances, plans) ===>> item_id peut référencer l’ID d’un exercice, d’une séance ou d’un plan, et item_type indique le type de modèle.
//Dans le modèle MylisteItem :
/**
* Get the item (exercise, workout, or plan).
*/
public function item()
{
return $this->morphTo();
}
//dans les modèles Exercise, Workout et Plan :
public function mylisteItems()
{
return $this->morphMany(MylisteItem::class, 'item');
}
-- Exécuter Les Migrations Créer Les Tables
Création des tables
php artisan migrate --path=/database/migrations/01_create_roles_table.php
php artisan migrate --path=/database/migrations/02_create_users_table.php
php artisan migrate --path=/database/migrations/03_create_uploads_table.php
php artisan migrate --path=/database/migrations/04_create_pages_table.php
php artisan migrate --path=/database/migrations/05_create_exercises_table.php
php artisan migrate --path=/database/migrations/05_create_plans_table.php
php artisan migrate --path=/database/migrations/07_create_workouts_table.php
php artisan migrate --path=/database/migrations/08_create_swim_sets_table.php
php artisan migrate --path=/database/migrations/09_create_my_lists_table.php
php artisan migrate --path=/database/migrations/10_create_workout_exercises_table.php
php artisan migrate --path=/database/migrations/11_create_workout_swim_sets_table.php
php artisan migrate --path=/database/migrations/12_create_plan_workouts_table.php
php artisan migrate --path=/database/migrations/13_create_my_list_items_table.php
Poisson Rouge : Une par une pour maitriser les erreurs ?????