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

pulkit's avatar

Model Factories relationship dependencies

Just migrating from Laravel 4.2 to 5.1, and setting up the model factories. In the 4.2 version I uses to use the laracasts/testdummy package which offered similar functionality.

With testdummy to create dependent relationships you could use 'factory:class'.

Eg:

$factory('Class\Two', [
    'relation_id' => 'factory:Class\One',
    'name' => $faker->name
]);

Can something similar be done with Model Factories or does the relationship need to be created manually?

Eg:

$factory->define('App\Class\Two', function (Faker\Generator $faker) use ($factory) {
    $relation = $factory->create('App\Class\One');
    return [
        'relation_id' => $relation->id,
        'name' => $faker->name
    ];
});
0 likes
9 replies
JeffreyWay's avatar
Level 59

Yeah - just create it manually.

$factory->define(App\Thing::class, function ($faker) {
    return [
        'user_id'     => factory('App\User')->create()->id,
        'description' => $faker->paragraph
    ];
});
7 likes
willvincent's avatar

You're on the right track, but syntax is wrong.. This would work:

$factory->define(App\Class\Two::class, function (Faker\Generator $faker) use ($factory) {
    $relation = factory(App\Class\One::class)->create();
    return [
        'relation_id' => $relation->id,
        'name' => $faker->name
    ];
});

Or, without defining it as a variable, like so:

$factory->define(App\Class\Two::class, function (Faker\Generator $faker) use ($factory) {
    return [
        'relation_id' => factory(App\Class\One::class)->create()->id,
        'name' => $faker->name
    ];
});

Previously asked and answered here: https://laracasts.com/discuss/channels/laravel/how-to-create-this-model-factory-laravel-51

1 like
jayknight's avatar

Sorry for commenting on a really old thread. Is there a way to do this without persisting the new "One" object?

boptom's avatar

@jayknight if you need to add the factory output to a database then you will need to persist the One object to maintain the foreign key constraints (if that is how you set up your migrations).

Otherwise, you can just set the relation_id to an integer.

You can use "states" if you sometimes need persistence, and sometimes not. See here:

https://laravel.com/docs/5.5/database-testing#factory-states

sagalbot's avatar

Just an FYI, @JeffreyWay's method does work, but if you were to pass your own user_id to the factory call, you'd end up with 2 users in the database, because factory('App\User')->create()->id is called no matter what.

The alternative is to wrap it in a closure:

$factory->define(App\Thing::class, function ($faker) {
    return [
        'user_id'     => function() {
              return factory('App\User')->create()->id;
        },
        'description' => $faker->paragraph
    ];
});

That way, you're only generating App\User if one wasn't passed in.

9 likes
HectorOrdonez's avatar

@sagalbot That is fantastic.

However, how do you work with "making" instead of creating the factories?

If I do factory(App\Thing)->make() it will try to create the dependency too.

sagalbot's avatar

@hectorordonez you'll have to provide a value to overwrite the closure. Using the example above:

factory(App\Thing::class)->make(['user_id' => null]);

That'd prevent the closure from being called.

S3C_MM's avatar

Doesn't this work in Laravel as well?

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use Faker\Generator as Faker;

$factory->define(App\Thing::class, function (Faker $faker) {
    return [
        'user_id'     => factory('App\User'), // this resolves auto-magically
        'description' => $faker->paragraph
    ];
});

Please or to participate in this conversation.