Well, I know I'm not the only one with the question as I found this
https://laracasts.com/discuss/channels/laravel/laravel-modelfactory-seeding-pivot-table
from 4 years ago, still unanswered , or this more recent one https://laravelquestions.com/2020/11/29/using-factory-with-nested-relationships-in-laravel-8/.
Below are the gory details of my toy model, but the basic thing is I have
User <- 1:N -> Project <- 1:N -> Task
Eventually, "Project" will have extra data attached to it. I've created it as a model, not a pivot, but maybe it should be a pivot. I need some advice on this.
The goal, from the setup process, is to be able to do get a User factory, create multiple projects each of which has multiple tasks associated with it. I'm even okay with generating a User with one project and several tasks. With the code further below, I can do this
328 roland> sail php artisan tinker
Psy Shell v0.10.6 (PHP 8.0.2 — cli) by Justin Hileman
>>> use App\Models\{User,Project,Task}
>>> User::factory()->hasProjects(3)->create()
=> App\Models\User {#4295
name: "Seamus Boyer",
email: "[email protected]",
email_verified_at: "2021-02-25 06:44:41",
updated_at: "2021-02-25 06:44:41",
created_at: "2021-02-25 06:44:41",
id: 1,
}
>>>
and I get a single user with three projects in the database. How do I get tasks created?
So here's the toy setup for this.
327 roland> sail php artisan make:model -f -m Project
Model created successfully.
Factory created successfully.
Created Migration: 2021_02_25_064104_create_projects_table
328 roland> sail php artisan make:model -f -m Task
Model created successfully.
Factory created successfully.
Created Migration: 2021_02_25_064109_create_tasks_table
The factories are fine as-is. I edit the migrations to add foreign keys to projects and tasks:
public function up()
{
Schema::create('projects', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
and
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->foreignId('project_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
}
and now we can run the migrations.
328 roland> sail php artisan tinker
Psy Shell v0.10.6 (PHP 8.0.2 — cli) by Justin Hileman
328 roland> sail php artisan migrate:fresh
Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (49.16ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (44.57ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (44.11ms)
Migrating: 2021_02_25_064104_create_projects_table
Migrated: 2021_02_25_064104_create_projects_table (85.13ms)
Migrating: 2021_02_25_064109_create_tasks_table
Migrated: 2021_02_25_064109_create_tasks_table (95.18ms)
So now the models need a little tweaking. Note that I'm not adding any data to confuse things, I just want to get the relationships and, eventually, the factories, to work.
The User.php model has this added
public function projects() {
return $this->hasMany(Project::class);
}
Project.php has this added
public function user() {
return $this->belongsTo(User::class);
}
public function tasks() {
return $this->hasMany(Task::class);
}
and Task.php has this added
public function project() {
return $this->belongsTo(Project::class);
}
And we're now ready to try to make things.