3
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?

kurogoma939のひとりアドベントカレンダーAdvent Calendar 2024

Day 22

LaravelのSeederでcsvからデータ移行をする

Last updated at Posted at 2024-12-21

背景

Laravelのseeder機能はとても便利です。
Factoryも用いればそこそこなテストデータの作成ができ、ローカル開発をする分には十分です。

しかし、時にはステージング・テスト環境のものを引っ張ってローカルで確認したい場合があると思います。
今回は、そのデータをCSVとして出力し、Seederでテスト投入する手段について紹介します。

ディレクトリの用意

以下のディレクトリを用意してください。

  • database/seeders/csv
  • database/seeders/csv/data

csvディレクトリ直下にはCSV投入用のSeederをセットします。
dataディレクトリには実際のcsvファイルを配置します。

初期設定

Gitのために以下の2ファイルを作成してください。

  • database/seeders/csv/data/.gitkeep
  • database/seeders/csv/data/.gitignore
database/seeders/csv/data/.gitignore
*.csv

共通クラス(今回のメイン)

csv/dataに投入したcsvファイルをローカルに投入するクラスです。
CSV出力する都合nullやdate周りの変換処理を設定しています。

database/seeders/csv/SeederUtil.php
<?php

namespace Database\Seeders\csv;

use Illuminate\Support\Facades\Schema;

class SeederUtil
{
    /**
     * CSVファイルからデータを読み取り、指定されたモデルとテーブルに挿入します
     *
     * @param  string  $modelClass Fully Qualified Model Class Name (e.g. \App\Models\User::class)
     * @param  string  $tableName  テーブル名 (e.g. 'users')
     * @return void
     */
    public static function seedFromCsv(string $modelClass, string $tableName)
    {
        $csvFile = database_path('seeders/csv/data/' . $tableName . '.csv');
        $fileHandle = fopen($csvFile, 'r');
        $header = fgetcsv($fileHandle);

        // テーブルのカラムを取得
        $tableColumns = Schema::getColumnListing($tableName);

        while (($row = fgetcsv($fileHandle)) !== false) {
            $row = array_combine($header, $row);

            // 'NULL'文字列をnullに変換
            $row = array_map(function ($value) {
                return $value === 'NULL' ? null : $value;
            }, $row);

            // 存在しないカラムを除外
            $filteredRow = array_filter($row, function ($key) use ($tableColumns) {
                return in_array($key, $tableColumns);
            }, ARRAY_FILTER_USE_KEY);

            // created_at, updated_atカラムがあれば現在日時を追加
            $now = now();
            if (in_array('created_at', $tableColumns)) {
                $filteredRow['created_at'] = $now;
            }
            if (in_array('updated_at', $tableColumns)) {
                $filteredRow['updated_at'] = $now;
            }

            $modelClass::create($filteredRow);
        }

        fclose($fileHandle);
    }
}

DatabaseSeeder.php

csv投入用に作成します。namespaceにご注意ください。

<?php

namespace Database\Seeders\csv;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(UserSeeder::class);
}

UserSeederの実装

csv/UserSeeder.php
<?php

namespace Database\Seeders\csv;

use Illuminate\Database\Seeder;
use App\Models\User;

class UserSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        SeederUtil::seedFromCsv(User::class, 'users');
    }
}

これであとはCSVを配置することでデータ投入ができます。
また、DatabaseSeeder.phpの配置が違うので以下のようなコマンドで実行してください。

php artisan migrate:fresh
php artisan db:seed --class="Database\Seeders\csv\DatabaseSeeder"

一応今はSeederクラスを個別で実装するようにしましたが、DatabaseSeederにまとめてしまってもいいかと思います。
また、もし上記の共通実装では足りないテーブル別の変換処理が必要になった場合はseedFromCsv関数をコピペして加工してください。

3
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
3
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?