Laravelのfactoryとseederで1対多関係のテーブルのテストデータを自動作成

個人メモ。
詳しい解説は、最下部の参考記事から。

# 環境
- Laravel 10.4.1
- データベース MariaDB 5.5.68
- PHP 8.2.4 

# 前提
- `User`テーブルと`Todo`テーブルがあり、リレーションで1対多の関係（user1に対し、todoが複数）。
- この1対多の関係で整合性のあるテストデータを自動作成する。

# 作業
- todoSeeder作成
```bash
php artisan make:seeder todoSeeder
```
で　\Laravelapp\database\seeders\todoSeeder.php　作成。
（userSeederは確か最初から存在）

- userモデルにリレーション追加
```PHP:app/Models/User.php
// リレーション設定
public function todo(): HasMany
{
    return $this->hasMany(Todo::class);
}
```
- todoモデルにリレーション追加
```PHP:app/Models/Todo.php
// リレーション設定
public function user(): BelongsTo
{
    return $this->belongsTo(User::class);
}
// Faker（モデルファクトリ）でのインサートを許可するカラムを定義
protected $fillable = [
    'user_id',
    'title',
    'todo',
    'add_date',
    'update_date',
];
```

- UserFactory.php のdefinition の初期状態（変更なし）
```PHP:\database\factories\UserFactory.php
public function definition(): array
{
    return [
        'name' => fake()->name(),
        'email' => fake()->unique()->safeEmail(),
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        'remember_token' => Str::random(10),
    ];
}
```
- TodoFactory.php　は下記のように記載
```PHP:\database\factories\TodoFactory.php
use App\Models\User;
public function definition(): array
{
    $date = $this->faker->dateTimeBetween('-1year');
    
    return [
        'user_id' => User::factory(),
        'title' => $this->faker->realText(random_int(10, 20)),
        'todo' => $this->faker->realText(random_int(30, 50)),
        'add_date' => $date,
        'update_date' => $date,
    ];
}
```


- 自動生成するデータを日本語にする
`/config/app.php`の`faker_locale`を'ja_JP'にすると、自動生成されるデータが日本語になります。
```PHP:app.php
    /*
    |--------------------------------------------------------------------------
    | Faker Locale
    |--------------------------------------------------------------------------
    |
    | This locale will be used by the Faker PHP library when generating fake
    | data for your database seeds. For example, this will be used to get
    | localized telephone numbers, street address information and more.
    |
    */
    // 'faker_locale' => 'en_US',
    'faker_locale' => 'ja_JP',
```

- DatabaseSeeder.php に下記1行追加
```PHP:\database\seeders\DatabaseSeeder.php
public function run(): void
{
    $this->call(todoSeeder::class);
}
```

- todoSeeder.php　を下記のようにする
```PHP:\database\seeders\todoSeeder.php
use Illuminate\Database\Seeder;
use App\Models\User;
use App\Models\Todo;
public function run(): void
{
    $users = User::factory(3)->create();
    Todo::factory(30)->recycle($users)->create();
}
```
ここでのポイントはrecycleを使っているところで、これにより、todoテーブルのuser_idカラムに、あらかじめ作成したuserのランダムなidが入って、一対多のデータになる。

これで、user：todoの一対多のリレーションでのデータがランダムに追加できた。
上記のtodoSeederだと、userが３レコードに対し、todoが合計30作られ、userのいずれかに割り振られる。（3ユーザー合計で30todoレコードとなる）
→この場合、userSeeder.phpには何も追加で書かなくてよかった。

- ログインテスト時のパスワードについて
ちなみに自動生成されたUserテーブルのデータで、ログインテストをするときのパスワードは何になるのか？ハッシュ化された文字列が生成されるので元のパスワードがわからないはず、と疑問に思っていたが、UserFactoryに下記の記載があり、「password」がハッシュ化した文字列が生成されるので、テストでは「password」とすればログインできると気づいた（コメントが親切にハッシュ前文字列を示していたのだ）。
```php:UserFactory.php
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
```


# 参考
[LaravelのModel Factoryでリレーション関係のダミーデータを作る](
https://www.webopixel.net/php/1805.html)
[LaravelのFakerとSeedingでダミーデータを自動生成しデータベースへ投入する](https://www.ritolab.com/posts/28)
[Laravelでテストデータ作成　ファクトリ・シーダ](https://syuntech.net/php/laravel/factory_seeder/)

[データベース：シーディング 10.x Laravel](https://readouble.com/laravel/10.x/ja/seeding.html)
[マイグレーション 10.x Laravel](https://readouble.com/laravel/10.x/ja/migrations.html)