factoryを使ったダミーデータ作成方法の3回目です。今回は、複数のデータ作成に便利なsequence
メソッドと、そのユースケースをご紹介します。
前回、同じく複数データを作成するcreateMany
メソッドを使った記述をご紹介しました。
少し振り返りになりますが、name属性がそれぞれ「高橋・佐藤・田中」のデータをcreateMany
で作成する場合、以下のように記述します。
User::factory()->createMany([ ['name' => '高橋'], ['name' => '佐藤'], ['name' => '田中'], ]);
作成したいデータを配列でcreateMany
に渡すことで、簡潔に記述することができます。
では、sequence
で同じデータを作る場合はどのようにするのでしょうか。
sequenceで複数データを作成
先ほどと同じ、name属性が「高橋・佐藤・田中」のデータを作成してみましょう。以下のように記述します。
User::factory() ->count(3) ->sequence( ['name' => '高橋'], ['name' => '佐藤'], ['name' => '田中'] ) ->create();
count
メソッドに作成件数を指定し、sequence
には作成したいデータを渡します。またcreate
メソッドも繋ぐ必要があります。
このケースではcreateMany
と比較して、sequence
の方がやや冗長に見えますよね。ですが、以下のようなケースならどうでしょう。
sequenceが適しているケース(1)
sex属性が「女性」と「解答なし」のデータをそれぞれ3件、全6件分作成したい。このようなケースでは、sequence
を使って以下のように記述できます。
User::factory() ->count(6) ->sequence( ['sex' => '女性'], ['sex' => '解答なし'], ) ->create();
tinkerで実行すると、「女性・解答なし・女性・解答なし….」と繰り返すデータがちゃんと6件作成されていることがわかります。
= Illuminate\Database\Eloquent\Collection {#29800 all: [ App\Models\User {#29813 sex: "女性", name: "三宅 涼平", id: 142, }, App\Models\User {#29793 sex: "解答なし", name: "渡辺 充", id: 143, }, App\Models\User {#29777 sex: "女性", name: "近藤 裕樹", id: 144, }, App\Models\User {#29845 sex: "解答なし", name: "伊藤 加奈", id: 145, }, App\Models\User {#29771 sex: "女性", name: "三宅 加奈", id: 146, }, App\Models\User {#29781 sex: "解答なし", name: "青田 くみ子", id: 147, },
sequence
を使わなくても、以下のように「女性」のレコード・「解答なし」のレコードをそれぞれで作成しても良いかもしれません。
User::factory(3)->create(['sex' => '女性']); User::factory(3)->create(['sex' => '解答なし']);
ただ、その場合作成されたレコード群は「女性・女性・女性・解答なし・解答なし・解答なし」と不自然にデータが固まってしまうので、テストケースによってどちらにするかは使い分けるとよさそうです。
ちなみに、今のようなデータをcreateMany
を使って作成しようとすると、
User::factory()->createMany([ ['sex' => '女性'], ['sex' => '解答なし'], ['sex' => '女性'], ['sex' => '解答なし'], ['sex' => '女性'], ['sex' => '解答なし'], ]);
このように6件分のデータを1つ1つ配列に渡さないといけないので、より冗長になってしまいます。
sequenceが適しているケース(2)
もう1つのsequence
が適しているケースは、「データに一意性を持たせたい場合」です。
以下は、私が関わらせていただいているプロジェクトで使われているコードを本記事用に少し変更したものですが、sequence
の使用例としてまさにぴったりです。
テスト用に47都道府県のレコードを作成したい。県名は、連続した一意性のあるデータとしたい。そういう場合、以下のようなシンプルな記述で作成できます。
Prefecture::factory()->count(47) ->sequence(function ($sequence) { return ['name' => "都道府県{$sequence->index}"]; })->create();
上記のコードではクロージャーで引数として$sequence
を受け取っています。$sequence
オブジェクトが持つindexプロパティを使用し、県名に連番を割り当てています。
以下はtinkerの実行結果です。「都道府県0、都道府県1、都道府県2、都道府県3、都道府県4、、、」と連続した番号が割り当てられることで、それぞれのデータに一意性を持たせることができます。
= Illuminate\Database\Eloquent\Collection {#29831 all: [ App\Models\Prefecture {#29822 id: 20, name: "都道府県0", }, App\Models\Prefecture {#29825 id: 21, name: "都道府県1", }, App\Models\Prefecture {#29821 id: 22, name: "都道府県2", }, App\Models\Prefecture {#29820 id: 23, name: "都道府県3", }, App\Models\Prefecture {#29819 id: 24, name: "都道府県4", }, App\Models\Prefecture {#29818 id: 25, name: "都道府県5", }, App\Models\Prefecture {#29817 id: 26, name: "都道府県6", }, App\Models\Prefecture {#29816 id: 27, name: "都道府県7", }, . . .
$sequence
のindexプロパティは「0」始まりなので、連番の始まりを「1」にしたい場合は、コールバック関数の中で +1 としてください。
->sequence(function ($sequence) { return ['name' => "都道府県" . ($sequence->index + 1)]; })
sequence
はそれほど出番が多いメソッドではないかもしれませんが、適した箇所に使うととっても便利です。ぜひご活用ください。