Laravel工厂关系...尊重create()或make()

时间:2017-05-23 00:03:01

标签: php laravel eloquent phpunit

根据Laravel的documentation on defining relationships within model factories

  

您还可以使用工厂定义中的Closure属性将关系附加到模型。例如,如果您想在创建帖子时创建新的用户实例,则可以执行以下操作:

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

我遇到的问题是关系定义中对create()的引用。在我看来,这并不属于这里。

如果我想要将我的关系持久保存到数据库中,它会很有效:

factory(App\Post::class)->create();

通过直接在此上方运行代码,将创建一个新的App\Post和一个新的App\User,并且这两个代码都会持久保存到数据库中。

但是,如果我只是想new模型,而不是通过运行来保持任何(根本没有)数据库:

factory(App\Post::class)->make();

它完成了我想要的某一点。新的App\Post实例已创建但未保留,但创建了App\Comment并将其保留到数据库中。

在我看来,我真正想要的是这样的事情:

$factory->define(App\Post::class, function ($faker) {
    return [
        'title' => $faker->title,
        'content' => $faker->paragraph,
        'user_id' => function () {
            // here I only want to declare the relationship,
            // not decide whether I want to create() or make()
            // the relationship, something like:
            return factory(App\User::class)->createOrMake()->id;

            // or perhaps something like:
            return factory(App\User::class)->id;
        }
    ];
});

最终结果是我希望相关数据能够尊重我在呼叫顶部尝试做的事情。做一切。或创造一切。

我在这里做错了吗?或者这是目前还没有的东西?

谢谢!

3 个答案:

答案 0 :(得分:1)

你想要你的相关模型的lazy()方法!

至少在Laravel 5.5中。

我在这里找到了你的问题,因为我遇到了同样的问题。我找到了答案,感谢Laravel精心编写的代码 - lazy()被定义在make()XDebug带我去的上方 - 我已经尝试过了,它似乎有效。

这就是我正在做的事情:

$factory->define(App\ArtItem::class, function (Faker $faker) {
    return [
        // 'id' => $faker->randomDigit,
        'slug' => $faker->unique->word,
        'artist_id' => factory(App\Artist::class)->lazy(),
        'image_id' => factory(App\Image::class)->lazy(),
        'created_at' => $faker->dateTime,
        'updated_at' => $faker->dateTime,
        'deleted_at' => $faker->dateTime,
    ];
});

Lazy()是一个有趣的生物,它返回一个闭包,所以你不能factory(App\Image::class)->lazy()->id,但我仍然看到它成功设置了正确的image_id和artist_id。

我当然希望你在此之前很久就找到了解决方案,但也许这会帮助其他人!

答案 1 :(得分:0)

尝试这种方法

我和你的问题一样,这个解决方案对我有用,但找不到原因。

Customerid:(5 input)
123
123
234
123
234
Output(Expected)
123
234
Actual:
123
123
123
234

答案 2 :(得分:0)

现在终于可以使用Laravel 5.6.12中添加的Factory Callbacks解决了这个问题。

$factory->afterMaking(Post::class, static function (Post $post) {
    if (!$post->user_id) {
        $post->user()->associate(factory(User::class)->make(['id' => 0]));
    }
});
$factory->afterCreating(Post::class, static function (Post $post) {
    if (!$post->user_id) {
        $post->user()->associate(factory(User::class)->create())->save();
    }
});

现在,无论何时make个帖子,如果不传递它的user_id,它将为您make个用户,并设置关系而不保存它。但是,如果您create个帖子,它将把一个新用户持久保存到数据库中,并将其ID保存到帖子模型中。

请注意,afterMakingafterCreating闭包在create工厂模型中同时被调用。我暂时将用户ID设置为0,以防外键posts.user_id被定义为not null。它将被更新为afterCreating中的正确值。这是一个可怕的骇客,但直到我们获得一个合适的beforeCreating钩子,该钩子才允许我们首先创建相关模型。