サイトアイコン IT NEWS

Laravel ExcelパッケージでCSVデータをDBへ一括登録する方法

laravel-excel-csv

LaravelExcelを操作するための「Laravel Excel」というパッケージがありあます。
今回はそれを利用してCSVファイルをデータベースへ簡単にインポートする方法をご紹介します。
CSVを使ったデータ一括登録にとても便利です!

Laravel ExcelでCSVをインポート

Laravel Excelの基本的な使い方は公式サイトに書いてありますので参考にしてください。

パッケージのインストール

いつもの如、Composerを使ってパッケージインストールします。

composer require maatwebsite/excel

著者の場合は、Laravelバージョン5.5ですので、config/app.php内のプロバイダーエイリアスの登録は不要になります。
最後にLaravelvendor:publishコマンドで完了です。

php artisan vendor:publish

これでconfigディレクトリの中にexcel.phpという設定ファイルが入ります。
後程使います。

CSVデータを1行ずつ登録

今回のシチュエーションは、コントローラー側でストレージディレクトリに保存しているCSVデータを1行ずつ読み込んでデータベース登録するもの。
その際、同じものがあれば更新、なければ新規登録を行います。
登録先のテーブル名はposts(モデル名はPost)とします。
CSVの内容はブログによくある記事のタイトルや内容を想像してください。

設定ファイルの変更

今回の例ではCSVファイルのサイズが巨大なため、以下を変更しています。
お好みで変更してください。

・・・
'settings' => [
    'memoryCacheSize' => '32MB',
    'cacheTime'       => 600
],
・・・

また、この記事を読まれているということは、日本語を使っていると思いますので、文字化けしないように入出力の文字コードを変更する必要があるかもしれません。
デフォルトはUTF-8なので、日本語ならShift-JISかな?
著者はUTF-8に変換済みのCSVファイルを使いますのでこのままです。

・・・
'encoding' => [
    'input'  => 'UTF-8',
    'output' => 'UTF-8'
],
・・・

最後に、ここが1番重要です!
CSVを1行ずつ読み込む際に、CSVのヘッダ(1行目)をキーとして使わないようにしましょう。
CSVファイルの1行目と登録するテーブルのフィールド名が一致していれば変更の必要はなく、もっと簡単になりますが、日本に住んでいる限りそんなに都合の良いデータがあるはずもなく…。
ってことで、headingfalseにして1行目を無視します。

'heading' => 'false',

Modelにfillableをセットする

上記の通り、CSVの1行目を使いませんので、Postモデルの$fillableにCSVと一致するフィールド名を登録しておきます。

// 例)
protected $fillable = ['post_id', 'title', 'body', 'category', 'tags', 'status' … ];

Controllerで差分登録

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;

use Excel;class CsvController extends Controller
{
    public function __construct(Post $post)
    {
        $this->post = $post;
    }    public function import()
    {
        $fields = $this->post->getFillable();
        $reader = Excel::load(storage_path('csv/data.csv'));
        $rows = $reader->toArray();
        foreach ($rows as $row){
            $id = $row[0];
            $record = $this->post->firstOrNew(['post_id' => $id]);
            foreach ($row as $key => $value) {
                $colmun = $fields[$key];
                $record->$colmun = $value;
            }
            $record->save();
        }
    }
}

解説

まずは、useLaravel Excelを宣言します。

Excel::load(storage_path('csv/data.csv'));

で/storage/csv/data.csvのCSVを読み込み、

$reader->toArray();

配列に変換し、行数分ループを回します。
firstOrNew()でデータの存在を確認し、なければオブジェクトを生成します。
Postモデルの$fillableの値をキーにセットして、save()で登録します。
今回は差分登録するためにsave()を使ってデータを登録します。
save()関数は、データが存在して変更があるならupdate、存在しなければinsertを自動的に行なってくれます。

【番外編】

もしCSV1行目とテーブルのフィールド名が一致していたら、2つ目のループが不要になり、以下のように書くことができます。

    ・・・
    foreach ($rows as $row){
        $id = $row['post_id'];
        $record = $this->post->firstOrNew(['post_id' => $id]);
        $record->fill($row);
        $record->save();
    }
    ・・・・

CSVファイルをアップロードするやり方はこちらを参考に。

次はCSV出力も試してみたいです。
以上、すごく便利ですね。

モバイルバージョンを終了