在Laravel中,数据库种子通常通过模型工厂完成.因此,您使用Faker数据为模型定义蓝图,并说明您需要多少个实例:
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
$user = factory(App\User::class, 50)->create();
Run Code Online (Sandbox Code Playgroud)
但是,假设您的用户模型hasMany与许多其他模型有关系,例如Post模型:
Post:
id
name
body
user_id
Run Code Online (Sandbox Code Playgroud)
因此,在这种情况下,您希望使用在Users表中播种的实际用户为Posts表添加种子.这似乎没有明确讨论,但我确实在Laravel文档中找到了以下内容:
$users = factory(App\User::class, 3)
->create()
->each(function($u) {
$u->posts()->save(factory(App\Post::class)->make());
});
Run Code Online (Sandbox Code Playgroud)
因此,在您的用户工厂中,您为每个创建的用户创建X个帖子.但是,在一个大型应用程序中,可能有50-75个模型与用户模型共享关系,您的用户播种器实际上最终会将整个数据库与其所有关系一起播种.
我的问题是:这是处理这个问题的最佳方法吗?我能想到的唯一另一件事是首先播种用户(没有播种任何关系),然后在播种其他模型时根据需要从数据库中随机抽取用户.但是,如果它们需要是唯一的,您必须跟踪哪些用户已被使用.此外,这似乎会为播种过程添加大量额外的查询批量.
use*_*101 30
您也可以使用saveMany.例如:
factory(User::class, 10)->create()->each(function ($user) {
$user->posts()->saveMany(factory(Posts::class, 5)->make());
});
Run Code Online (Sandbox Code Playgroud)
Tim*_*myG 13
您可以为讨论的ModelFactory内做到这一点使用闭包在这里.
该解决方案也适用于播种机,干净利落地工作.
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
$factory->define(App\Post::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'body' => $faker->paragraph(1),
'user_id' => function() {
return factory(App\User::class)->create()->id;
},
];
});
Run Code Online (Sandbox Code Playgroud)
对于播种机,请使用以下简单的方法:
//create 10 users
factory(User::class, 10)->create()->each(function ($user) {
//create 5 posts for each user
factory(Post::class, 5)->create(['user_id'=>$user->id]);
});
Run Code Online (Sandbox Code Playgroud)
注意:此方法不会在数据库中创建不需要的条目,而是在创建关联记录之前分配传递的属性.
就个人而言,我认为一个Seeder类来管理这些关系比分离的播种器类更好,因为你在一个地方拥有所有的逻辑,所以一看就能看出发生了什么.(任何知道更好方法的人:请分享):)
一个解决方案可能是:一个DatabaseSeeder和类中的私有方法,以保持'run'方法更清洁.我在下面有这个例子,它有一个User,Link,LinkUser(多对多)和一个Note(多对一).
对于多对多关系,我首先创建所有链接,然后获取插入的ID.(因为ids是auto-inc,我认为可以更容易地获取id(获得最大值),但在此示例中无关紧要).然后创建用户,并为每个用户附加一些随机链接(多对多).它还为每个用户创建随机笔记(多对一示例).它使用'工厂'方法.
如果您替换"发布"的"链接",这应该有效.(您可以删除'注意'部分然后......)
(还有一种方法可以确保您拥有1个拥有自己登录凭据的有效用户.)
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// Create random links
factory(App\Link::class, 100)->create();
// Fetch the link ids
$link_ids = App\Link::all('id')->pluck('id')->toArray();
// Create random users
factory(App\User::class, 50)->create()->each(function ($user) use ($link_ids) {
// Example: Many-to-many relations
$this->attachRandomLinksToUser($user->id, $link_ids);
// Example: Many-to-one relations
$this->createNotesForUserId( $user->id );
});
// Make sure you have a user to login with (your own email, name and password)
$this->updateCredentialsForTestLogin('john@doe.com', 'John Doe', 'my-password');
}
/**
* @param $user_id
* @param $link_ids
* @return void
*/
private function attachRandomLinksToUser($user_id, $link_ids)
{
$amount = random_int( 0, count($link_ids) ); // The amount of links for this user
echo "Attach " . $amount . " link(s) to user " . $user_id . "\n";
if($amount > 0) {
$keys = (array)array_rand($link_ids, $amount); // Random links
foreach($keys as $key) {
DB::table('link_user')->insert([
'link_id' => $link_ids[$key],
'user_id' => $user_id,
]);
}
}
}
/**
* @param $user_id
* @return void
*/
private function createNotesForUserId($user_id)
{
$amount = random_int(10, 50);
factory(App\Note::class, $amount)->create([
'user_id' => $user_id
]);
}
/**
* @param $email
* @param $name
* @param $password
* @return void
*/
private function updateCredentialsForTestLogin($email, $name, $password)
{
$user = App\User::where('email', $email)->first();
if(!$user) {
$user = App\User::find(1);
}
$user->name = $name;
$user->email = $email;
$user->password = bcrypt($password); // Or whatever you use for password encryption
$user->save();
}
}
Run Code Online (Sandbox Code Playgroud)
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
'password' => bcrypt(str_random(10)),
'remember_token' => str_random(10),
];
});
$factory->define(App\Post::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'body' => $faker->paragraph(1),
'user_id' => factory(App\User::class)->create()->id,
];
});
Run Code Online (Sandbox Code Playgroud)
所以现在如果你这样做factory(App\Post::class, 4)->create(),它将创建4个不同的帖子,并在此过程中还创建4个不同的用户.
如果您希望所有帖子都使用相同的用户,我通常会这样做:
$user = factory(App\User::class)->create();
$posts = factory(App\Posts::class, 40)->create(['user_id' => $user->id]);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
16102 次 |
| 最近记录: |