📁

Laravel の seeder がカオスになってきたのでフォルダ分けした

2020/12/28に公開

システムの継続開発が進むにつれ、システムに必要なデータもどんどん増えていく。
そして気づけば migration のフォルダも seeder のフォルダもファイルだらけで何が何やら・・・。ということに。
migration は時系列で並ぶのでまだマシだが、seeder は デフォルトで UserSeeder みたいな命名のファイルがあるので、それに釣られてしまった結果、どの seeder がどのときに追加したやつだっけ?みたいになりがち。

なので seeders フォルダの下にサブフォルダを切って、機能別に整理しようと思い立った。
単にフォルダを切っただけど「特定の seeder だけ実行したい」と言う場合や「Controller や Service クラスなどから実行できない」事態になる。

やることは以下の4つ。

  1. seeder を任意にディレクトリ分けする
  2. composer.json に記述を追加する (Laravel5 などの場合)
  3. ディレクトリ分けした seeder に namespace の記述を追加する
  4. seed コマンド実行時に namespace を付与する

seeder を任意にディレクトリ分けする

好きなようにやる。
database以下のディレクトリ構成

上記の例では DatabaseSeeder.php は 引数を指定せずに php artisan db:seed を実行した時に使われるデフォルトの seeder ここでは、初期設定に必要な seeder 群を呼び出している。
seederの中身
それぞれの seeder クラスの中ではさらに以下のように namespace 付きでディレクトリ分けした seeder クラスを呼び出す(記述については後述)。
seeders
この例では call のクラスに namespace つけているが、ファイルの先頭で use を使っても問題ない。
繰り返し呼び出すわけでもないし、増減した時に2箇所編集するのも面倒なので、自分はここに直接全部書いている。

composer.json に記述を追加する (Laravel5 などの場合)

autoload のところに "Database\\Seeders\\": "database/seeders/" の行を追加。
Laravel8 のを見たところ、すでにこの記述があるので不要。

"autoload": {
    "psr-4": {
        "App\\": "app/",
        "Database\\Seeders\\": "database/seeders/"
    },
    "classmap": [
        "database/seeds",
        "database/factories"
    ]
},

キーの方にある\ はバックスラッシュ (Macでのバックスラッシュの出し方は こちら )。
2個つけるのを忘れずに。

classmap を消した方がいいのかなと思いつつも、とりあえずはこのまま。

ディレクトリ分けした seeder に namespace の記述を追加する

Database\Seeders は composer.json に書いた通りで、それ以下の名前は任意で。
任意だけど、ディレクトリ名のキャメルケースとかがわかりやすいかと。
namespace記述

seed コマンド実行時に namespace を付与する

例えば setup ディレクトリにある管理者のデータを単体で流したいときは以下のようにする。

実行する前に! composer dump-autoload を実行して、クラスの読み込みを最新化おくこと (seeder を編集した時の基本)。

php artisan db:seed --class=Database\\Seeders\\Setup\\AdministratorsSeeder

またしてもバックスラッシュは2こ。
引用符などは不要。

おまけ : Controller など app 側から呼び出す場合

時々、動的にデータを流し込みたいと言う要望があるケースがある。
新規利用者がいた時に、システム利用サンプルを生成する場合など。

普通にプログラム中にモデルを呼び出してゴリゴリ書いても良いんだけど、外部化しておきたい。
データ流し込みといえば seeder の仕事だろう。
じゃぁ seeder を呼び出せばいいじゃない!

クラスの呼び出し
先ほど namespace を追加したので、普通に use するだけ!
なんと簡単。

普通のクラスなので、 run メソッドを実行するだけ。
app側からseederを実行
上記例では引数を受け取っている。
参考までにseeder側も。
引数を設定

それでは良き seeder ライフを!

Discussion