Laravel データ作成  データ作成編

## はじめに
前回までにテーブル作成、モデル作成を行った。

https://qiita.com/kenji123/items/146b6895b05e25fe60be

それを元にテストデータ作成を行う。

## 作成方法
LaravelのSeeder、Factory、Fakerを使って、ユーザー、プロジェクト、タスクのテストデータを作成でする。

ちなみにSeederでテストデータを作るためのもの。
Factoryは複数のSeederで使う場合等、再利用できるようにすることで使用する。
Fakerは任意のデータを作成するライブラリー。

特に特定のビジネスロジックを使用してのデータ生成はFactoryは不要。
以下は、Seederにおいて、Factoryを使用せず、データを作成している。(データ作成箇所)

php artisan db:seedコマンドを実行すると、DatabaseSeederが実行される。
```bash
php artisan db:seed
```

特定のSeederを直接実行したい場合は、--classオプションを使用してそのSeederを指定する。

```bash
php artisan db:seed --class=ProjectSeeder
```

マイグレーションから作成し直すには下記を行う。
```bash
php artisan migrate:fresh --seed
```
このコマンドは全てのテーブルをドロップし、全てのマイグレーションを新たに実行し、そしてデータベースシーダーを実行できる。

次に、実際にFactory、Seederを記載する。

### Factory
今回Seederで使用するFactoryを記載する。

php artisan make:factory UserFactory --model=User
php artisan make:factory ProjectFactory --model=Project
php artisan make:factory TaskFactory --model=Task

UserFactory.php
```php
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
 */
class UserFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    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),
        ];
    }

    /**
     * Indicate that the model's email address should be unverified.
     */
    public function unverified(): static
    {
        return $this->state(fn (array $attributes) => [
            'email_verified_at' => null,
        ]);
    }
}

```


ProjectFactory.php
```ProjectFactory.php

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\User;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Project>
 */
class ProjectFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'user_id' => User::factory(),
            'title' => $this->faker->sentence(3),
            'description' => $this->faker->paragraph,
        ];
    }
}

```
User::factory()と書くと、Eloquent Factoryはこのプロジェクトが作成されるたびに新しいユーザーインスタンスも作成し、その新しいユーザーのIDをuser_idカラムに割り当てるように動く。

この記述により、プロジェクトを作成する際にそのプロジェクトに関連するユーザーも同時に作成することができる。そしてその関連するユーザーのIDがuser_idカラムに自動的に設定される。



TaskFactory.php
```TaskFactory.php

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\Task;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Task>
 */
class TaskFactory extends Factory
{

    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Task::class;

    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            //
            'title' => $this->faker->sentence(),
            'description' => $this->faker->paragraph(),
            'status' => $this->faker->randomElement(['todo', 'in_progress', 'done']),
            'due_date' => $this->faker->dateTimeBetween('+1 week', '+1 month'),
            'project_id' => function () {
                return \App\Models\Project::factory()->create()->id;
            },
        ];
    }
}


```

### Seeder
Factoryを利用し、データ作成するSeederを作る。

php artisan make:seeder UserSeeder
php artisan make:seeder ProjectSeeder
php artisan make:seeder TaskSeeder

UserSeeder.php
```php
<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\User;

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        //
        User::factory()
            ->count(10)
            ->create();
    }
}

```
UserFactoryを使って10個のユーザーデータを生成し、データベースに保存するという処理を表す。


ProjectSeeder.php
```ProjectSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Project;
use App\Models\User;

class ProjectSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        User::all()->each(function ($user) {
            $user->projects()->saveMany(
                Project::factory()
                    ->count(rand(1, 3))
                    ->hasTasks(rand(1, 3))
                    ->make()
            );
        });
    }
}

```
このコードでは、まず User::all() で全てのユーザーを取得し、その各ユーザーに対してプロジェクトを作成している。$user->projects()->saveMany() の呼び出しは、それぞれのユーザーが持つプロジェクトのリレーションシップを通じて、新しいプロジェクトを作成している。そして Project::factory()->count(rand(1, 3))->make() の呼び出しにより、1から3の間でランダムな数のプロジェクトを作成する。
以上の修正により、user_id が自動的にセットされるようになる。


TaskSeeder.php
```TaskSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\Task;
use App\Models\Project;
use Faker\Factory as FakerFactory;

class TaskSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $faker = FakerFactory::create('ja_JP');

        $projects = Project::all();

        foreach ($projects as $project) {
            for ($i = 0; $i < 3; $i++) {
                Task::create([
                    'title' => 'プロジェクト' . $project->id . 'のタスク' . ($i + 1),  // 日本語のタイトル
                    'description' => 'これはプロジェクト' . $project->id . 'のタスク' . ($i + 1) . 'の説明です',  // 日本語の説明
                    'due_date' => $faker->dateTimeBetween('-1 month', '+1 month'),
                    'completed' => $faker->boolean,
                    'project_id' => $project->id,
                    'status' => $faker->randomElement(['pending', 'in progress', 'completed']),
                ]);
            }
        }

    }
}

```
$faker = FakerFactory::create('ja_JP');にてFakerのrealTextメソッドが日本語を生成したが、日本語のテキストデータが必要で、それはデフォルトではFakerライブラリに含まれていないようである。
今回は、Fakerを使わずに直接日本語のタイトルや説明を指定するで対応した。

## 次にあたって
以上でデータ作成ができる。
今後Factory、Seederを使用し効率的なデータ作成を行えるようになること。
次は、以上のデータを使ってデータを表示する。