deansatch's avatar

seeding nested relationship with Factory

This is what I'm trying to do...

Company::factory()
            ->times(300)
            ->has(Branch::factory()->carParks(), 'branches')
            ->create();

in my BranchFactory I have...

public function carParks()
    {
        return $this->afterCreating(function (Branch $branch) {
            CarParkFactory::new()->template()->create([
                'branch_id' => $branch->id,
            ]);
        });
    }

And in CarParkFactory ...

 public function template()
    {
        return $this->state(function () {
            return [
                    'name' => 'car park 1',
            ];
        });
    }

This all works well. i.e. it creates the companies, each with a branch, and each branch has a car park named 'car park 1'. But I actually want each branch to have 4 car parks with 4 different set names (car park 1, car park 2, car park 3 and car park 4)

How could I do this? Please bear in mind I've simplified this to keep the code short. The reality is each car park will have more fields than just a name.

0 likes
1 reply
Swaz's avatar
Swaz
Best Answer
Level 20

Option 1

In your simplified example there is no need for the afterCreating() or template() methods:

// DatabaseSeeder.php
Company::factory(300)
    ->has(Branch::factory()
        ->hasCarParks(['name' => 'Car Park 1'])
        ->hasCarParks(['name' => 'Car Park 2'])
        ->hasCarParks(['name' => 'Car Park 3'])
        ->hasCarParks(['name' => 'Car Park 4'])
    )
    ->create();

Option 2

If you need the template() method:

// DatabaseSeeder.php
Company::factory(300)
    ->has(Branch::factory()
        ->has(CarPark::factory()->template()->state(['name' => 'Car Park 1']))
        ->has(CarPark::factory()->template()->state(['name' => 'Car Park 2']))
        ->has(CarPark::factory()->template()->state(['name' => 'Car Park 3']))
        ->has(CarPark::factory()->template()->state(['name' => 'Car Park 4']))
    )
    ->create();

Option 3 - The Fancy Pants Way

You could also do something like this. But you would end up with Car Park 1, ..., Car Park 1200 in your database. Which may or may not be desirable.

// DatabaseSeeder.php
Company::factory(300)
    ->has(Branch::factory()->hasCarParks(4))
    ->create();
// CarParkFactory.php
public function definition()
{
    static $id = 1;

    return [
        'branch_id' => Branch::factory(),
        'name' => sprintf('Car Park %s', $id++),
    ];
}
1 like

Please or to participate in this conversation.