【问题标题】:Laravel factory relationships... respect create() or make()Laravel 工厂关系...尊重 create() 或 make()
【发布时间】:2017-10-22 18:10:03
【问题描述】:

根据 Laravel 的documentation on defining relationships within model factories

您还可以使用工厂定义中的闭包属性将关系附加到模型。例如,如果您想在创建 Post 时创建一个新的 User 实例,您可以执行以下操作:

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

我遇到的问题是关系定义中对@9​​87654323@ 的引用。在我看来,这不属于这里。

如果我想将我的关系与数据库持久化,它会非常有用:

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;
        }
    ];
});

最终结果是我希望相关数据能够尊重我从调用顶部开始尝试执行的操作。做一切。或者创造一切。


我在这里做错了吗?或者这是目前不存在的东西?

谢谢!

【问题讨论】:

  • 嗨,我面临同样的问题。你是怎么解决这个问题的?
  • @Zalo 我没有。 :(

标签: php laravel eloquent phpunit


【解决方案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。

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

【讨论】:

  • 看起来很酷!我需要它,但它对我不起作用...如果我使用 factory(...)->lazy() 定义我的工厂,那么,当我使用 make(User::class) 时,它仍在调用 create( ) 在引擎盖下...
【解决方案2】:

现在终于可以使用 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 一个 Post,它会将一个新用户持久化到数据库中,并将它的 ID 保存到 Post 模型中。

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

【讨论】:

    猜你喜欢
    • 2020-12-28
    • 2021-06-29
    • 2018-06-13
    • 2015-12-09
    • 2021-07-08
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 2017-03-21
    相关资源
    最近更新 更多