CSVインポート機能の作成

2022/04/25

前回、LaravelでCSVエキスポートの記事をエントリーしました。

この流れで今回はCSVインポートの機能を作成してみます。

CSVインポート/エキスポート の処理はPHPの関数で作成するやり方とライブラリを利用するやり方の2つあります。

この記事ではライブラリ(goody/csv)を使ってCSVファイルをインポートします。

※ 最近Twitterはじめました。記事には書いていない補足説明やはまった箇所などツィートします。是非、この機会に!
>>フォローする

 

完成形

 

仕様

CSV(test.csv)

 

DBテーブル構成

 

手順

テーブル作成

artisanコマンドでスケルトンを作成。


php artisan make:migration create_csv_users_table --create=csv_users

 

自動生成されたスケルトンに中身を入れていきます。


public function up()
{
    Schema::create('csv_users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name')->comment('名前');
        $table->string('email')->comment('メールアドレス');
        $table->string('tel',20)->nullable()->comment('電話番号');
        $table->timestamps();
    });
}

 

作成したマイグレーションファイルを実行。


php artisan migrate

 

モデル作成

モデルのスケルトンを作成。


php artisan make:model Models/CsvUser

 

中身を入れてきます。


class CsvUser extends Model
{
    //ブラックリスト方式
    protected $guarded = ['id'];
}

 

Bladeファイル作成

フォーム

Bootstrap4のファイルを選択するコンポーネントを使いました。ファイル名はpractice2.blade.php。


<h1>Laravel で CSV インポート 演習</h1>
    <p>CSVファイルを csv_users テーブルに登録します。</p>
    <form action="" method="post" enctype="multipart/form-data">
        {{ csrf_field() }}
        <div class="row">
            <label class="col-1 text-right" for="form-file-1">File:</label>
            <div class="col-11">
                <div class="custom-file">
                    <input type="file" name="csv" class="custom-file-input" id="customFile">
                    <label class="custom-file-label" for="customFile" data-browse="参照">ファイル選択...</label>
                </div>
            </div>
        </div>
        <button type="submit" class="btn btn-success btn-block">送信</button>
    </form>

 

ファイルを選択すると、入力フォーム部分にファイル名を表示するためには以下のjQueryも必要です。末尾に記述します。


:
<script>
    // ファイルを選択すると、入力フォーム部分にファイル名を表示
    $('.custom-file-input').on('change',function(){
        $(this).next('.custom-file-label').html($(this)[0].files[0].name);
    })
</script>
</body>
</html>

 

フラッシュメッセージ

CSVインポートが完了したらフラッシュメッセージを表示させます。


@if(Session::has('flashmessage'))
    <script>
        $(window).on('load',function(){
            $('#myModal').modal('show');
        });
    </script>

    <!-- モーダルウィンドウの中身 -->
    <div class="modal fade" id="myModal" tabindex="-1"
         role="dialog" aria-labelledby="label1" aria-hidden="true">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body text-center">
                     {{ session('flashmessage') }}
                </div>
                <div class="modal-footer text-center">
                </div>
            </div>
        </div>
    </div>
@endif

 

PHPライブラリ「Goodby CSV」ライブラリをインストール


composer require goodby/csv

 

ルーティング&コントローラ作成

ルーティング

コントローラは前回作成したCSVダウンロードのコントローラに追記しました。

厳密にはCSVアップロードになるので、気になるかたは新しいコントローラを作成してください。


Route::get('csv/practice2', 'CsvDownloadController@practice2'); //表示
Route::post('csv/practice2', 'CsvDownloadController@upload_regist'); //登録

 

コントローラ(表示)

public function practice2()
{
    return view('csv.practice2');
}

 

コントローラ(CSVインポート処理)

この記事のメインになるところですね。


// use 宣言を追加
use Goodby\CSV\Import\Standard\LexerConfig;
use Goodby\CSV\Import\Standard\Lexer;
use Goodby\CSV\Import\Standard\Interpreter;
:
public function upload_regist(Request $rq)
{
    if($rq->hasFile('csv') && $rq->file('csv')->isValid()) {
        // CSV ファイル保存
        $tmpname = uniqid("CSVUP_").".".$rq->file('csv')->guessExtension(); //TMPファイル名
        $rq->file('csv')->move(public_path()."/csv/tmp",$tmpname);
        $tmppath = public_path()."/csv/tmp/".$tmpname;

        // Goodby CSVの設定
        $config_in = new LexerConfig();
        $config_in
            ->setFromCharset("SJIS-win")
            ->setToCharset("UTF-8") // CharasetをUTF-8に変換
            ->setIgnoreHeaderLine(true) //CSVのヘッダーを無視
        ;
        $lexer_in = new Lexer($config_in);

        $datalist = array();

        $interpreter = new Interpreter();
        $interpreter->addObserver(function (array $row) use (&$datalist){
           // 各列のデータを取得
           $datalist[] = $row;
        });

        // CSVデータをパース
        $lexer_in->parse($tmppath,$interpreter);

        // TMPファイル削除
        unlink($tmppath);

        // 処理
        foreach($datalist as $row){
            // 各データ取り出し
            $csv_user = $this->get_csv_user($row);

            // DBへの登録
            $this->regist_user_csv($csv_user);
        }
        return redirect('/csv/practice2')->with('flashmessage','CSVのデータを読み込みました。');
    }
    return redirect('/csv/practice2')->with('flashmessage','CSVの送信エラーが発生しましたので、送信を中止しました。');
}

 

解説

インポートの流れは以下のようになります。

1.フォームデータからCSVファイルを受け取る
2.Goodby/CSV の config設定
3.Goodby/CSV ライブラリでCSVデータをパース
4.get_csv_userメソッドでkeyとCSVデータを配列にセット
5.regist_user_csvメソッドでDBに保存
コントローラ(get_csv_user)

private function get_csv_user($row)
{
    $user = array(
        'name' => $row[0],
        'email' => $row[1],
        'tel' => $row[2],
    );
    return $user;
}

 

コントローラ(regist_user_csv)

private function regist_user_csv($user)
{
    $newuser = new \App\CsvUser;
    foreach($user as $key => $value){
        $newuser->$key = $value;
    }
    $newuser->save();
}

 
 
以上です。

次回はこのソースにCSVデータのバリデーション機能をつけてみようと思います。

本庄マサノリ

仕事で Laravel を使っています。気づいたことや新しい発見など情報を発信していきます。問い合わせはこちら

>> Twitter をフォローする

 

-チュートリアル, 中級