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

Baadier's avatar

Seeding & Model Factories between 3 relations

I'm struggling to get my seeding working with model factories. I get the following error

 [ErrorException]
  Undefined property: Illuminate\Database\Eloquent\Builder::$orders

$orders doesnt exist anywhere?

I have a Brand that has many BrandAccounts which has many BrandAccountLogs. The inverse of the relationship is hasOne.

I have the following model factories:

$factory->define(App\Brand::class, function (Faker\Generator $faker) {
    return [
        'name'           => $faker->unique()->company,
        'url'            => $faker->unique()->domainName
    ];
});

$factory->define(App\BrandAccount::class, function (Faker\Generator $faker) {
    return [
        'network'       => $faker->randomElement(array ('facebook','twitter','instagram')),
        'network_id'    => $faker->randomNumber(8)
    ];
});

$factory->define(App\BrandAccountLog::class, function (Faker\Generator $faker) {
    return [
        'log'           => $faker->biasedNumberBetween(100,10000)
    ];
});

and I'm trying to seed my tables with the following:

public function run()
    {
        Model::unguard();

        DB::statement('SET FOREIGN_KEY_CHECKS=0;');

        factory(App\Brand::class, 50)->create()->each(function($u) {
            $u->brandAccounts()->save(factory(App\BrandAccount::class, 1)->make()->each(function($l){
                $l->brandAccounts()->save(factory(App\BrandAccountLog::class)->make()
            }));
        });

        DB::statement('SET FOREIGN_KEY_CHECKS=1;');

        Model::reguard();
    }

I tried running the above with create() instead of make() on the 2 foreign tables and ended up with the same issue.

It works if I comment out:

factory(App\Brand::class, 50)->create()->each(function($u) {
            $u->brandAccounts()->save(factory(App\BrandAccount::class, 1)->make()->each(function($l){
                //$l->brandAccounts()->save(factory(App\BrandAccountLog::class)->make()
            }));
        });

but then I dont have all the data I need.

0 likes
3 replies
Baadier's avatar

I think I have it working with the following:

public function run()
    {
        DB::table('brands')->delete();
        DB::table('brandAccounts')->delete();
        DB::table('brandAccountLogs')->delete();

        $faker = Faker\Factory::create();

        // Create Brands to work with
        for ($records = 0; $records <= 50; $records++){
            $brand = new Brand([
                'name'               => $faker->unique()->company,
                'url'                => $faker->unique()->domainName
            ]);
            $brand->save();

            //Create Brand Accounts to work with
            for($accounts = 0; $accounts <= 10; $accounts++){
                $brandAccount = new BrandAccount([
                    'network'        => $faker->randomElement(array ('facebook','twitter','instagram')),
                    'network_id'     => $faker->randomNumber(8)
                ]);
                $brand->brandAccounts()->save($brandAccount);

                // Create Brand Account Log entries
                for($accounts = 0; $accounts <= 365; $accounts++){
                    if($accounts == 0){
                        $logTotal = $faker->randomNumber(5);
                        $date = Carbon::now();
                        $brandAccountLog = new BrandAccountLog([
                            'log'        =>  $logTotal,
                            'created_at' =>  $date
                        ]);
                    } else {
                        $logTotal += $faker->biasedNumberBetween(100,1000);
                        $date->addDay();
                        $brandAccountLog = new BrandAccountLog([
                            'log'        =>  $logTotal,
                            'created_at' =>  $date
                        ]);
                    }
                    $brandAccount->brandAccountLogs()->save($brandAccountLog);
                }
            }
        }
    }

Is there a more efficient way to do this?

sibongisenimsomis's avatar

Tested on Laravel 7.x (using migrate:fresh --seed, artisan command)

To whomever may be in need of an alternative method, this is what I have on my solution.

Table/Model structure between 3 tables, appointments, attachments & attachment_metas respectively.

Relationship sudo code: Appointment->hasMany(Attachment); Attachment->hasOne(AttachmentMeta))

Each model has a Factory that uses Faker for a total of 3 factories, in the factories the foreign key fields are not defined, because that will be taken care of by Laravel Eloquent

Code in DatabaseSeeder

/**
 * Create 100 Appointments and attach a random number of Attachments between 0-3, then assignment those
 * Appointments to a variable for later use.
 */
$appointments = factory(App\Appointment::class, 100)
    ->create()
    ->each(function ($appointment){
        $appointment->attachments()->saveMany(factory(\App\Attachment::class,rand(0,3) )->make());
    });


//Loop through the $appointments variable from above. For each $appointment, loop through the $attachments and attach 1 $attachment_meta
$appointments->each(function ($appointment){
    $appointment->attachments->each(function($attachment){
        $attachment->attachment_meta()->save(factory(App\AttachmentMeta::class)->make());
    });
});

This code assumes you have relationships properly defined in your models

fylzero's avatar

@baadier This was my approach recently...

<?php

use App\Models\Rma;
use App\Models\User;
use App\Models\Issue;
use App\Models\Comment;
use Illuminate\Database\Seeder;

class UserWithIssuesRmasAndComments extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // Create 10 Users
        $users = factory(App\Models\User::class, 10)->create();

        // For Every User...
        $users->each(function ($user) {

            // Create 10 Issues
            $issues = factory(App\Models\Issue::class, 10)->create([
                'created_by' => $user->id
            ]);

            // For Every Issue...
            $issues->each(function ($issue) {

                // Create 10 Comments
                $comments = factory(App\Models\Comment::class, 10)->create([
                    'commentable_id' => $issue->id,
                    'commentable_type' => 'App\Models\Issue',
                ]);
            });

            // Create 10 Rmas
            $rmas = factory(App\Models\Rma::class, 10)->create([
                'created_by' => $user->id
            ]);

            // For Every Rma...
            $rmas->each(function ($rma) {

                // Create 10 Comments
                $comments = factory(App\Models\Comment::class, 10)->create([
                    'commentable_id' => $rma->id,
                    'commentable_type' => 'App\Models\Rma',
                ]);
            });
        });
    }
}
24 likes

Please or to participate in this conversation.