Summer Sale! All accounts are 50% off this week.

DavidSprauel's avatar

Model factory loop

Hey,

I'm facing a problem I struggle to resolve while trying to setting up some test for my application. When i'm generating a factory i fall in a loop which leads to an allocated memory error.

The database schema were already there and i have (unfortunetly) to deal with it.

Here is my 3 main factories:

$factory->define(Contact::class, function (Faker $faker) {
    return [
        'company_id'       => factory(Company::class),
        'user_category_id' => rand(1, 3),
        'entry_date'       => now(),
        'key'              => Str::random(16),
        'email'            => $faker->safeEmail
    ];
});
$factory->define(Company::class, function (Faker $faker) {
    return [
        'name'            => $faker->company,
        'contact_id'      => factory(Contact::class),
        'location_id'     => factory(Location::class),
        'company_type_id' => rand(1, 3),
    ];
});
$factory->define(User::class, function (Faker $faker) {
    return [
        'contact_id'     => factory(Contact::class),
        'firstname'      => $faker->firstName,
        'lastname'       => $faker->lastName,
        'email'          => $faker->unique()->safeEmail,
        'password'       => 'yIXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password,
        'key'            => Str::random(16),
        'remember_token' => Str::random(10),
    ];
});

The problem is, when i wanna create a user, it creates a contact, which create a company, which create another contact, and that should stop there but for an unknown reason it seems to loop and create another, then another contact which needs another company etc...

So i'm trying to create the company first and already here it seems to loop when creating a contact although it shouldn't. When I create a company, that 'contact_id' => factory(Contact::class), line should create a contact with a direct relationship with the company, so in theory, the contact factory shouldn't create another company right ?

Is there something i'm missing ?

0 likes
5 replies
mvd's avatar

Hi @davidsprauel

Yes there is a problem a contact factory creates a company but the company factory creates again a contact ...you are in a loop. I am not sure if this is the best way but this will not loop.

Change the company factory to this

$factory->define(Company::class, function (Faker $faker) {
    return [
        'name'            => $faker->company,
        'contact_id'      => function() {
            return factory(Contact::class)->create()->id;
        },
        'location_id'     => factory(Location::class),
        'company_type_id' => rand(1, 3),
    ];
});

Create a company but you don't have a contact yet, so set this to 0

$company = factory(Company::class)->create(['contact_id' => 0]);

Update contact factory

$factory->define(Contact::class, function (Faker $faker) {
    return [
        'company_id'       => function() {
            return factory(Company::class)->create()->id;
}       ,
        'user_category_id' => rand(1, 3),
        'entry_date'       => now(),
        'key'              => Str::random(16),
        'email'            => $faker->safeEmail
    ];
});

Create the contact

$contact = factory(Contact::class)->create(['company_id' => $company->id]);

Now we have also a contact so we can update company with this contact id.

$company->contact_id = $contact->id;
$company->save();

Change the user factory

$factory->define(User::class, function (Faker $faker) {
    return [
        'contact_id'     => function() {
            return factory(Contact::class)->create()->id;
        },
        'firstname'      => $faker->firstName,
        'lastname'       => $faker->lastName,
        'email'          => $faker->unique()->safeEmail,
        'password'       => 'yIXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password,
        'key'            => Str::random(16),
        'remember_token' => Str::random(10),
    ];
});

Last step, create the user

$user= factory(User::class)->create(['contact_id' => $contact->id]);
DavidSprauel's avatar

Thanks fo your answer.

Just for me to know, there is a difference between doing

 'contact_id'      => function() {
            return factory(Contact::class)->create()->id;
        },

and

'contact_id' => factory(Contact::class)

?

The problem is, I can't set the contact_id to 0 as it has a foreign key and SQL will return an error

mvd's avatar

@davidsprauel

With the 'function'

'contact_id'      => function() {
            return factory(Contact::class)->create()->id;
        },

you can pass a variable and use it for the 'contact_id'. If you don't pass this variable it will use the return factory(Cont.... code.

With

'contact_id' => factory(Contact::class)

You are generating a new contact and you can not override the 'contact_id'

DavidSprauel's avatar

@mvd

Alright, I wasn't aware of that, thanks. I kinda found a solution:

factory(Company::class)->create([
            'contact_id' => factory(Contact::class)->create([
                'user_category_id' => 6
            ])->id
        ])

that work with no issues.

gssj85's avatar

I'm having exactly the same problem.

It would be nice if there was a way so a factory knew when it was called from another factory and used the same id generated from the factory that called it.

1 like

Please or to participate in this conversation.