やりたい状態
「若いIDほど古い記事」にする。
例:12件生成する場合
IDが小さいほど古いデータ
| id | created_at |
|---|---|
| 1 | 12日前 |
| 2 | 11日前 |
| 3 | 10日前 |
| ... | ... |
| 12 | 1日前 |
実際のコード
/database/factories/ArticleFactory.php
$article_total = 12;
Article::factory()
->count($article_total)
->sequence(function ($sequence) use ($article_total) {
$offset_days = $article_total - $seq->index;
return [
'created_at' => now()->subDays($offset_days),
'updated_at' => now()->subDays($offset_days),
];
})
->create();
なぜこれで実現できるのか?
① Factoryは内部でループしている
概念的にはこう:
for ($i = 0; $i < 12; $i++) {
// レコード生成
}
このとき ↓
| ループ番号 ($i) | 実際のID |
|---|---|
| 0 | 1 |
| 1 | 2 |
| 2 | 3 |
② $sequence->index の正体
sequence()を使うと、Laravel内部ではこうなっています。
$sequence = new Sequence($i);
Sequenceクラス(簡略化):
class Sequence
{
public $index;
public function __construct($index)
{
$this->index = $index;
}
}
つまり:
$sequence->index = ループ番号
③ なぜ引き算しているのか?
$offset_days = $article_total - $sequence->index;
12件の場合:
| index | 計算 | subDays |
|---|---|---|
| 0 | 12 - 0 | 12日前 |
| 1 | 12 - 1 | 11日前 |
| 2 | 12 - 2 | 10日前 |
| ... | ... | ... |
| 11 | 12 - 11 | 1日前 |
だから:
| id | created_at |
|---|---|
| 1 | 12日前 |
| 12 | 1日前 |
になる。
ページネーションでどうなる?
Article::orderBy('created_at', 'desc')->paginate(5);
1ページ目:
id 12, 11, 10, 9, 8
2ページ目:
id 7, 6, 5, 4, 3
3ページ目:
id 2, 1
並びが直感的でテストが安定します。
もし引き算しなかったら?
now()->subDays($sequence->index)
この場合:
| id | created_at |
|---|---|
| 1 | 今日 |
| 2 | 1日前 |
| 3 | 2日前 |
若いIDが一番新しくなってしまう。
本質まとめ
今回のコードは実質これと同じ:
for ($i = 0; $i < 12; $i++) {
$days = 12 - $i;
$created_at = now()->subDays($days);
}
Laravelが内部でループして、
そのループ番号を $sequence->index として渡しているだけ。