gpt4 book ai didi

database - Laravel 工厂 - 创建或动态化

转载 作者:行者123 更新时间:2023-12-05 07:12:04 27 4
gpt4 key购买 nike

我有一个简单的问题。

我如何编写一个工厂来定义使用 make()create() 的关系,具体取决于原始调用 make() 还是 create()

这是我的用例:

我有一个简单的工厂

/** @var $factory Illuminate\Database\Eloquent\Factory */
$factory->define(App\User::class, function (Faker $faker) {
return [
'role_id' => factory(Role::class),
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => 'secret',
];
});

我的问题是 role_id。当使用factory(Role::class)时,它总是会创建一个角色!写入数据库...

在我的测试中,当我编写 factory(User::class)->create(); 时,它会创建一个用户和角色,没关系!

但是如果我写 factory(User::class)->make(); 它仍然会创建一个角色...我不会在使用 make( ),在那种情况下,我只想要一个简单的 role_id => 0

我怎样才能做到这一点?

谢谢!

编辑(解决方法)

好吧,这比预期的要难,当您定义嵌套关系时,无法知道何时使用 make()create()...我发现的唯一方法是使用 debug_stacktrace() 方法,并寻找从 Factory 调用的 make 方法。

为了简化和可重用性,我为工厂创建了一个名为 associateTo($class) 的辅助方法,该方法将定义工厂中的关系。使用 create() 时,它将返回相关模型的现有 ID,使用 make() 时,它将返回 1。

通过这种方式,工厂可以:

/** @var $factory Illuminate\Database\Eloquent\Factory */
$factory->define(App\User::class, function (Faker $faker) {
return [
'role_id' => associateTo(Role::class), // Defining relationship
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => 'secret',
'remember_token' => Str::random(10),
];
});

辅助函数是:

/**
* Helper that returns an ID of a specified Model (by class name).
* If there are any Model, it will grab one randomly, if not, it will create a new one using it's Factory
* When using make() it wont write in Database, instead, it will return a 1
*
* @param string $modelClass
* @param array $attributes
* @param bool $forceNew
* @return int
*/
function associateTo(string $modelClass, array $attributes = [])
{
$isMaking = collect(debug_backtrace())
// A function called 'make()'
->filter(fn ($item) => isset($item['function']) && $item['function'] === 'make')
// file where I have global functions
->filter(fn ($item) => isset($item['file']) && Str::endsWith($item['file'], 'functions.php'))
->count();

if ($isMaking) return 1;

/** @var Model $model */
$model = resolve($modelClass);

return optional($model::inRandomOrder()->first())->id
?? create($modelClass, $attributes)->id; // call to Factory
}

有了这个,我可以轻松地编写单元测试(使用工厂)而不需要使用数据库连接,所以单元测试变得超快!

我希望这对其他人有帮助!

最佳答案

您可以覆盖属性 role_id:

factory(User::class)->make(['role_id' => 0]);

另一种解决方案 - 以 _id 结尾的任何属性的辅助方法:

function make($class)
{
$attributes = \Schema::getColumnListing((new $class)->getTable());
$exclude_attribures = [];

foreach ($attributes as $attribute)
{
if(ends_with($attribute, '_id'))
{
$exclude_attribures[] = [$attribute => 0];
}
}

return factory($class)->make($exclude_attribures);
}

调用示例:

make(User:class);

关于database - Laravel 工厂 - 创建或动态化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60540837/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com