Files
2026-04-01 10:30:52 +09:00

266 lines
8.5 KiB
PHP

<?php
namespace Database\Seeders\Sample;
use App\Models\Role;
use App\Models\User;
use App\Traits\HasSeederCounts;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\Hash;
class DummyUserSeeder extends Seeder
{
use HasSeederCounts;
/**
* 영문 이름 목록 (이메일 생성용)
*
* @var array<string>
*/
private array $englishFirstNames = [
'james', 'john', 'michael', 'david', 'william',
'emma', 'olivia', 'sophia', 'isabella', 'mia',
'robert', 'joseph', 'thomas', 'charles', 'daniel',
'emily', 'elizabeth', 'madison', 'abigail', 'charlotte',
];
/**
* 영문 성 목록 (이메일 생성용)
*
* @var array<string>
*/
private array $englishLastNames = [
'smith', 'johnson', 'williams', 'brown', 'jones',
'garcia', 'miller', 'davis', 'rodriguez', 'martinez',
'wilson', 'anderson', 'taylor', 'thomas', 'moore',
];
/**
* 더미 사용자를 생성합니다.
*
* --count=users=N 옵션으로 생성 수를 지정할 수 있습니다.
* 500건 초과 시 배치 삽입으로 성능을 최적화합니다.
*/
public function run(): void
{
$count = $this->getSeederCount('users', 100);
$this->command->info("더미 사용자 {$count}개 생성을 시작합니다.");
// 역할 조회
$roles = Role::whereIn('identifier', ['admin', 'manager', 'user'])->get()->keyBy('identifier');
if ($roles->isEmpty()) {
$this->command->error('역할이 존재하지 않습니다. RolePermissionSeeder를 먼저 실행해주세요.');
return;
}
$timezones = [
'Asia/Seoul',
'Asia/Tokyo',
'America/New_York',
'America/Los_Angeles',
'Europe/London',
'Europe/Paris',
];
$languages = ['ko', 'en'];
$statuses = ['active', 'inactive', 'blocked'];
$countries = ['KR', 'JP', 'US', 'GB', 'FR', 'DE'];
$useBatchInsert = $count > 500;
$batchSize = 500;
$batch = [];
$roleBatch = [];
$createdCount = 0;
$hashedPassword = Hash::make('password123');
$progressBar = $this->command->getOutput()->createProgressBar($count);
$progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%');
for ($i = 1; $i <= $count; $i++) {
$firstName = $this->getRandomFirstName();
$lastName = $this->getRandomLastName();
$name = "{$firstName} {$lastName}";
// 이메일은 영문 소문자와 숫자만 사용
$emailFirstName = $this->englishFirstNames[array_rand($this->englishFirstNames)];
$emailLastName = $this->englishLastNames[array_rand($this->englishLastNames)];
$email = $emailFirstName.'.'.$emailLastName.$i.'@example.com';
$userData = [
'name' => $name,
'nickname' => $firstName.$i,
'email' => $email,
'password' => $hashedPassword,
'email_verified_at' => rand(0, 1) ? now()->subDays(rand(1, 365)) : null,
'language' => $languages[array_rand($languages)],
'timezone' => $timezones[array_rand($timezones)],
'country' => $countries[array_rand($countries)],
'status' => $statuses[array_rand($statuses)],
'mobile' => '010-'.rand(1000, 9999).'-'.rand(1000, 9999),
'bio' => rand(0, 1) ? $this->getRandomBio() : null,
'ip_address' => rand(1, 255).'.'.rand(0, 255).'.'.rand(0, 255).'.'.rand(1, 254),
'last_login_at' => rand(0, 1) ? now()->subDays(rand(0, 30)) : null,
];
// 역할 부여 (90% user, 8% manager, 2% admin)
$roleIdentifier = $this->getRandomRole();
if ($useBatchInsert) {
$userData['created_at'] = now();
$userData['updated_at'] = now();
$batch[] = $userData;
$roleBatch[] = $roleIdentifier;
// 배치 크기에 도달하면 일괄 삽입
if (count($batch) >= $batchSize) {
$this->insertBatch($batch, $roleBatch, $roles);
$batch = [];
$roleBatch = [];
}
} else {
$user = User::create($userData);
$role = $roles->get($roleIdentifier);
if ($role) {
$user->roles()->attach($role->id, [
'assigned_at' => now(),
'assigned_by' => null,
]);
}
}
$createdCount++;
$progressBar->advance();
// 100건마다 메모리 정리
if ($i % 100 === 0) {
gc_collect_cycles();
}
}
// 남은 배치 삽입
if ($useBatchInsert && ! empty($batch)) {
$this->insertBatch($batch, $roleBatch, $roles);
}
$progressBar->finish();
$this->command->newLine();
$this->command->info("더미 사용자 {$createdCount}개가 성공적으로 생성되었습니다.");
}
/**
* 사용자 배치 삽입 및 역할 부여
*
* @param array $batch 사용자 데이터 배열
* @param array $roleBatch 역할 식별자 배열
* @param \Illuminate\Support\Collection $roles 역할 컬렉션
* @return void
*/
private function insertBatch(array $batch, array $roleBatch, $roles): void
{
// 배치 삽입 전 이메일 목록 저장
$emails = array_column($batch, 'email');
// 배치 삽입
User::insert($batch);
// 삽입된 사용자 조회하여 역할 부여
$insertedUsers = User::whereIn('email', $emails)->get()->keyBy('email');
$roleAttachments = [];
foreach ($batch as $index => $userData) {
$user = $insertedUsers->get($userData['email']);
if ($user) {
$role = $roles->get($roleBatch[$index]);
if ($role) {
$roleAttachments[] = [
'user_id' => $user->id,
'role_id' => $role->id,
'assigned_at' => now(),
'assigned_by' => null,
];
}
}
}
if (! empty($roleAttachments)) {
\Illuminate\Support\Facades\DB::table('user_roles')->insert($roleAttachments);
}
}
/**
* 랜덤 역할 식별자를 반환합니다.
* 90% user, 8% manager, 2% admin 비율
*
* @return string
*/
private function getRandomRole(): string
{
$rand = rand(1, 100);
if ($rand <= 2) {
return 'admin';
}
if ($rand <= 10) {
return 'manager';
}
return 'user';
}
/**
* 랜덤 이름(First Name)을 반환합니다.
*/
private function getRandomFirstName(): string
{
$names = [
'민준', '서준', '도윤', '예준', '시우',
'하준', '지호', '주원', '지후', '준우',
'서연', '서윤', '지우', '서현', '민서',
'하은', '하윤', '윤서', '지민', '지유',
'James', 'John', 'Michael', 'David', 'William',
'Emma', 'Olivia', 'Sophia', 'Isabella', 'Mia',
];
return $names[array_rand($names)];
}
/**
* 랜덤 성(Last Name)을 반환합니다.
*/
private function getRandomLastName(): string
{
$names = [
'김', '이', '박', '최', '정',
'강', '조', '윤', '장', '임',
'Smith', 'Johnson', 'Williams', 'Brown', 'Jones',
'Garcia', 'Miller', 'Davis', 'Rodriguez', 'Martinez',
];
return $names[array_rand($names)];
}
/**
* 랜덤 자기소개를 반환합니다.
*/
private function getRandomBio(): string
{
$bios = [
'안녕하세요! 반갑습니다.',
'개발을 좋아하는 사람입니다.',
'Hello! Nice to meet you.',
'새로운 것을 배우는 것을 좋아합니다.',
'Software developer passionate about technology.',
'항상 배우고 성장하려고 노력합니다.',
'Love coding and problem solving.',
'커피와 코딩을 좋아합니다.',
];
return $bios[array_rand($bios)];
}
}