user7554217
user7554217

Reputation:

Laravel 5.6 - Factory Relations infinite seeding

I defined a factory in order to seed tables with faker. Following the official docs, I implemented it as showed, like this:

<?php

use Faker\Generator as Faker;

$factory->define(App\Item::class, function (Faker $faker) {
    return [
        'codice' => $faker->word,
        'data_acquisto' => $faker->date('Y-m-d'),
        [...] // Other stuff
        // Relations
        'componente_id' => function() {
            return factory(App\Componente::class)->create()->id;
        },
    'tipologia_id' => function() {
        return factory(App\Tipologia::class)->create()->id;
    },
    'condizione_id' => function() {
        return factory(App\Condizione::class)->create()->id;
    },
    'locazione_id' => function() {
        return factory(App\Locazione::class)->create()->id;
    },
    'fornitore_id' => function() {
        return factory(App\Fornitore::class)->create()->id;
    },
    'parent_id' => function() {
        return factory(App\Item::class)->create()->id;
    }
     ];
 });

When I launch it with php artisan migrate:refresh --seed, framework starts to seed the destination tables, but it being stuck in the relation seeding phase (factory(App\Componente::class)->create()->id). Apparently resulting in a some sort of infinite/recursive process (generating thousands of records), until the task crashes due to an overflow.

By googling around, I noticed different approaches from many devs, but seems that others experienced this problem like me. Someone tried to indicate the max number in the factory argument:

// Ex. 5 max
return factory(App\Componente::class, 5)->create()->id;

And the Laravel doc doesn't mention it. But in this way, it throws another exception:

Property [id] does not exist on this collection instance.

Either if the migration results like this:

Schema::create('componente', function (Blueprint $table) {
    $table->increments('id'); // <- ID exists!
    $table->string('tipo');
    [...] // Other stuff
}

About this, I read about the collection specification, i.e. the use of first(). But I don't get how to avoid this scenario. I mean, if I use first() in the statement, how can it generates the number of required rows if first() returns only the first collection occurrence?

At last, I just need to create 3 rows of this one, so how can I approach it?

Thanks in advance everyone for help.

UPDATE

Here's ComponenteFactory.php

<?php

use Faker\Generator as Faker;

// Definizione dati test
$factory->define(App\Componente::class, function (Faker $faker) {
    return [
        'tipo' => $faker->word,
        'descrizione' => $faker->optional()->sentence,
        'garanzia' => $faker->optional()->text,
        'note' => $faker->optional()->sentence
    ];
});

Upvotes: 2

Views: 904

Answers (1)

Chin Leung
Chin Leung

Reputation: 14921

The problem comes from your parent_id relationship.

return factory(App\Item::class)->create()->id;

Since the parent is another item, it will create a parent and keep going on creating parents after parents for the new items, which will cause an infinite loop.

To fix this, you may use a random factor to see if you generate a parent or not.

For example:

'parent_id' => function () {
    return mt_rand(0, 100) % 2 == 0 ? factory(App\Item::class)->create()->id : null;
}

Therefore, when generating the parent relationship, there's a 50% that it will stop the chain.

Upvotes: 1

Related Questions