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はそれほど出番が多いメソッドではないかもしれませんが、適した箇所に使うととっても便利です。ぜひご活用ください。
