Passing array values to laravel factory

Krishna Raj K picture Krishna Raj K · Aug 4, 2017 · Viewed 7.7k times · Source

I'm trying to create a fake data seeder using fzaninotto/faker and factory in Laravel 5.4. I want to send an array of data to the factory, in which i can pick a random element using faker. The array is a result of a DB query, which I don't want to do recursively in the Modelfactory. Here is what I done.

In seeder, it calls the factory.

factory(App\Models\Types::class, 10)->create();

In Modelfactory, the function is as below

$factory->define(App\Models\Types::class, function (Faker\Generator $faker) {
    $materials = App\Models\Material::pluck('id')->all();
    return [
        'name' => $faker->unique()->word,
        'material_id' => $faker->randomElement($materials),
        'status' => 1,
        'display_status' => 1,
    ];
});

The array $materials is created with the model call to Material is done in each loop, which I want to avoid. It takes too much time to seed more data (say 100000). Is there any option pass the data from seeder file to factory? Moving the Model call before the factory definition will now solve my issue because the Material is seeded in some other seeder file, which results empty array because the Modelfactory is loaded at the beginning by default.

Answer

louisfischer picture louisfischer · Aug 4, 2017

I personally consider factories as just a way to fill fillable attributes of a model. I take care of the relationships in the seeders.

Let's say you have two models Type and Material. You create two factories named TypeFactory and MaterialFactory. For instance TypeFactory would be as follows:

$factory->define(App\Models\Types::class, function (Faker\Generator $faker) {
    return [
        'display_status' => 1,
        'name' => $faker->unique()->word,
        'status' => 1
    ];
});

Then in the seeder of the types table, you could do:

$materials = factory(App\Models\Material::class, 10)->create();

$types = factory(App\Models\Type::class, 100)->make();

$types->each(function($type) use ($materials) {
    $material = $materials->random();

    $type->material()->associate($material);
    $type->save();
});

Note the difference between create() and make(). create() persists the model and make() only returns an instance of it.

This is probably not related to your problem but App\Models\Material::pluck('id')->all() is not correct. You should first retrieve all instances of the model and then call the pluck method:

$materialsIds = App\Models\Material::all()->pluck('id');