Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

rbroberts's avatar

How can I use Factories to create chained objects, A -> B -> C

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.

0 likes
2 replies
rbroberts's avatar
rbroberts
OP
Best Answer
Level 3

And...in spite of having spent a couple of hours trying to search for the answer, I naturally found it minutes after I posted the above.

https://stefanzweifel.io/posts/2020/09/17/nested-states-in-laravel-8-database-factories/

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()->has(ProjectFactory::times(6)->hasTasks(3))->create();
[!] Aliasing 'ProjectFactory' to 'Database\Factories\ProjectFactory' for this Tinker session.
=> App\Models\User {#4306
     name: "Jettie Renner",
     email: "[email protected]",
     email_verified_at: "2021-02-25 07:11:57",
     updated_at: "2021-02-25 07:11:57",
     created_at: "2021-02-25 07:11:57",
     id: 4,
   }
>>>
sr57's avatar

Hi @rbroberts

:-) That arrives sometimes, and sometimes just because it makes us to better describe the problem. Please mark your answer as best to close the thread. Have a nice day.

Please or to participate in this conversation.