LaravelでCSVを読み込んでSeederを走らせる方法とCSVの1行目の先頭が0になるときの対処法

LaravelでCSVを扱うことがありましたので備忘録として残しておきます。

SplFileObjectクラスでCSVファイルを読み込む

PHP,LaravelでCSVファイルを読み込む方法を調べているとfile_get_contents()メソッドは使わないほうがいいと書いてあることが多いので、今回はSplFileObjectクラスを使用します。

use Carbon\Carbon;

public function run()
    {
        $file = new SplFileObject('database/csv/facility.csv'); // ファイルの読み込み
        $file->setFlags(
            \SplFileObject::READ_CSV | // CSV 列として行を読み込む
                \SplFileObject::READ_AHEAD |  // 先読み/巻き戻しで読み出す。
                \SplFileObject::SKIP_EMPTY |  // 空行は読み飛ばす
                \SplFileObject::DROP_NEW_LINE // 行末の改行を読み飛ばす
        );
        $list = [];
        $now = Carbon::now();
        // 一行ずつ処理
        foreach ($file as $index => $line) {
                $list[] = [
                    "user_id"          => $line[0], // 行の1列目
                    "facility_name"     => $line[1], // 行の2列目
                    'pref'              => $line[2],
                    'city'              => $line[3],
                    'address'           => $line[4],
                    'building'          => $line[5],
                    "created_at"        => $now,
                    "updated_at"        => $now,
                ];
            }
        }
        DB::table("facilities")->insert($list);
    }

エラー

CSVファイルを作成してSeederを走らせると下記のようなエラーが出ました。

General error: 1366 Incorrect integer value: '1'

あらら…数字が文字列だったのかな?と思いintval()を使いキャストしてから再度シーディングすると今度は下記のようなエラーが表示されました。

Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fail

外部キーとの整合性が取れていない??どうして??と思い調べてみるとどうやらCSVファイルの1行目の先頭が0になっていることがわかりました。

CSVファイルの1行目の先頭が0になる

ググってみるとCSVファイルを意識せずにダウンロードすると先頭に意識していない3バイト、BOMが入っていることがわかりました。
https://qiita.com/PET_HAL/items/fd1364513f81562671b6

ということで対策します。

解決策

エディタなどでCSVファイルをBOMなしに変更するのが簡単かと思いますが、コードで対応したかったので下記のようになりました。

use Carbon\Carbon;

public function run()
    {
        $file = new SplFileObject('database/csv/facility.csv');
        $file->setFlags(
            \SplFileObject::READ_CSV | // CSV 列として行を読み込む
                \SplFileObject::READ_AHEAD |  // 先読み/巻き戻しで読み出す。
                \SplFileObject::SKIP_EMPTY |  // 空行は読み飛ばす
                \SplFileObject::DROP_NEW_LINE // 行末の改行を読み飛ばす
        );
        $list = [];
        $now = Carbon::now();
        foreach ($file as $index => $line) {
            // 先頭に意識していない3バイトのBOMが含まれている時に対応
            if ($index === 0) {
                $line[0] = preg_replace('/^\xEF\xBB\xBF/', '', $line[0]);
            }
            $intId = intval($line[0]); //念のためキャストする
            if (!is_null($intId) && $intId !== 0){
                $list[] = [
                    "user_id"          => $intId,
                    "facility_name"     => $line[1],
                    'pref'              => $line[2],
                    'city'              => $line[3],
                    'address'           => $line[4],
                    'building'          => $line[5],
                    "created_at"        => $now,
                    "updated_at"        => $now,
                ];
            }
        }
        DB::table("facilities")->insert($list);
    }

コメントを残す

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。