1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LaravelのFactoryの理解があまかった件について

Posted at

はじめに

久しぶりの投稿でQiitaCLIのコマンドを忘れてしまったちびまろです。

早速ですがみなさん、Laravelは好きですか?

僕は好きです!大好きです!

プライベートで少しずつ勉強しているのでまだまだひよっこですが、新しく機能について理解が深まるともっともっとと気持ちが昂ります!

理由?分かりません。好きなもんは好きなんです!

題名にあるとおり、今回はLaravelのFactoryについて書かせていただければと思います。

私自身何となく「テストデータを大量に作るやつ」くらいのイメージで使ってましたが、ちゃんと理解して使おうと思い立ったので調べてみることにしました。

Factoryとは

データベースにテスト用のダミーデータを簡単に作成するための設計書です。

勉強している最中にイメージ的にmigrationと似ているなと感じました。

Factoryはテストや開発中に大量のデータを扱いたいときに便利な機能です。
本物のデータを用意しなくてもFactoryとFaker(PHPライブラリ)を組み合わせることで簡単にランダムなデータを生成することができます。

この機能を使うことで手動で何十、何百ものデータを作成する手間を省くことができます。

めちゃくちゃ便利...!

Laravelの中にdatabaseディレクトリがあり、その中にFactoryクラスが存在します。

database
├── database.sqlite
├── factories
│   └── UserFactory.php
├── migrations
│   ├── 0001_01_01_000000_create_users_table.php
│   ├── 0001_01_01_000001_create_cache_table.php
│   └── 0001_01_01_000002_create_jobs_table.php
└── seeders
    └── DatabaseSeeder.php

Factoryの作成方法

Factoryを新たに作成することも可能です。
Laravelにはartisanコマンドと呼ばれるLaravel独自のコマンドがあります。
こちらのコマンドで新しいFactoryを作成できます。

php artisan make:factory factoryName

このコマンドを実行すると、database/factoriesディレクトリ内に新しいFactoryクラスが生成されます。
factoryNameで作成するFactoryクラスの名前を指定できます。

php artisan make:factory PostFactory

このコマンドを実行すると、database/factories/PostFactory.phpが生成されます。

database
├── factories
│   ├── PostFactory.php
│   └── UserFactory.php
... 省略

このファイル内でモデルのデフォルトの属性値を定義します。

Factoryの中身について

今回はLaravelインストール時にデフォルトで作成されるUserFactory.phpの中身を見ていきましょう。

UserFactory.php
<?php

namespace Database\Factories;

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

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
 */
class UserFactory extends Factory
{
    /**
     * The current password being used by the factory.
     */
    protected static ?string $password;

    /**
     * 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' => static::$password ??= Hash::make('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,
        ]);
    }
}

各コードの意味

ズラーっとコードがたくさんあると少々混乱するかもしれませんが、1つずつに絞ってみていくとそれほど難しくもありません。
すぐ理解できなくてもそんなもんです!

ということで1つずつ説明していきます。

protected static ?string $password;

プログラミングしてる人ならよく見るコードの形ですね!

「最もprotectedで、最もstaticで、そして最もstringな宣言でいかせていただきます。」(何言ってんだ)

すみません、ふざけすぎました。

protected

プロパティやメソッド、定数などのアクセス権の制御を示すキーワードです。
public、protected、privateのいずれかを指定することで定義が可能です。

protectedを宣言されたものは、そのクラス自身やそのクラスを継承したクラス、親クラスからのみアクセスが可能です。
それ以外の場所からは直接アクセスすることはできません。
つまり、今回でいうとUserFactory.phpの中でのみ、この$passwordに値を代入したり、値を参照したりすることが可能です。

static

クラスプロパティ、またはメソッドに対してstaticを宣言すると、クラスのインスタンス化を行う必要がなくなります。

インスタンスを使用しなくても、クラスを直接指定することで変数やインスタンスを呼び出せるようにできます。

どうやら擬似変数である$thisについては、staticを宣言されたメソッドの内部から利用することが出来ないらしいです。

?string

型宣言でstringは見たことありますが、先頭にある?って何ですかね。

公式ドキュメントに記載がありました。

パラメータや戻り値の型宣言をする際に、型の前に?をつけるとnullableであることを指定できる。

クエスチョンマークの後ろで指定した型だけでなく、nullも渡せるようになります。

何でもそうですが、便利〜!と安易に考えて使用する場面をミスるとバグに繋がりかねない機能だなと思いました。
使用する際は注意したいですね!!

definitionメソッド

メソッドのすぐ上にコメントが書いてありますね。

Define the model's default state.

日本語訳は「モデルのデフォルト状態を定義する。」です。

これはFactoryで生成されるユーザーの「初期データ」を設定するためのメソッドです。

このメソッドは下記のようなコードを実行すると呼び出され、生成するユーザーのデフォルトの属性を指定します。

User::factory()->make()
User::factory()->create()

Userモデルと紐づいており、下記コードのreturnで指定されているnameemailpasswordなどはusersテーブルのカラムと紐づいています。

UserFactory.php
public function definition(): array
{
    return [
        'name' => fake()->name(),
        'email' => fake()->unique()->safeEmail(),
        'email_verified_at' => now(),
        'password' => static::$password ??= Hash::make('password'),
        'remember_token' => Str::random(10),
    ];
}

fake()->???()とすることで、PHPのライブラリであるFakerを使ってダミーデータを生成して!と指示することができます。

name

ユーザーの名前が登録されるカラム。
fake()->name()を使うことでランダムな名前が生成されます。

email

ユーザーのメールアドレスが登録されるカラム。

ランダムで一意なメールアドレスを生成

fake()->unique()->safeEmail()

ではここでUserFactory.phpの中にあるpasswordで何をしているのかを見ていきましょう。

'password' => static::$password ??= Hash::make('password'),

初めてUserFactoryが実行される時、左側のstatic::$passwordの状態はnullです。

static::$passwordがnullの場合にHash::make('password')が実行されます。

1回目の実行
Hash::make('password')が実行されます。

2回目以降
static::$passwordに格納されたデータが再利用されます。

ではいつ格納されるのか!!!!
ここで注目すべきものが??=です。

これは null合体代入演算子 と呼ばれる機能で左辺の変数がnullの場合に限り、右辺の値を代入することができる演算子です。

処理の流れ

  1. 1回目の実行では、static::$passwordがnullなので、Hash...が実行されます
  2. Hash::make('password')が実行されると同時に??=によって、static::$passwordに結果が代入されます
    static::$passwordはstaticプロパティであるため、このクラス全体から使えます
  3. 2回目以降の実行では、static::$passwordに値が入っているため、??=による代入は実行されません。1回目の実行でstatic::$passwordに代入されたハッシュ化パスワードがをのまま使われます

unverifiedメソッド

ECサイトとかのユーザーを新規登録するとき、入力したメールアドレス宛に確認メールが届きますよね?

このメソッドはそれ関連で、ユーザーがメールを未確認の状態で作成されるように設定します。
確認メールを承認していないユーザーが必要な場合もあるため、その際にこのunverifiedメソッドを使います。

下記ロジックのようにこのunverifiedメソッドを使うことができます。

$user = User::factory()->unverified()->create()

上記が実行されると、usersテーブルのemail_verified_atにnullが設定されたテストデータが登録されます。

まとめ

  • Fakerはダミーデータ作成のためのPHPライブラリ
  • Factoryはダミーデータ作成のための設計書(定義書)
  • 基本的にはdefinition()でテーブルに対するテストデータを定義する
  • Null合体演算子 と呼ばれる演算子がある

なんとなくテストデータを作成するためのデータと認識していたレベルでしたが、今回改めて調べた結果理解度がかなりアップしましたね!
他にもなんとなくで使用している機能があるのでどんどん調べていこうと思いました!
ごっつ楽しくなりそうですねww

ではみなさん!今日もプログラミングを楽しんでいきましょう!!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?