LoginSignup
4
6

More than 5 years have passed since last update.

LaravelでLeague/Csvを使ってアップロードされたcsvを読み込みDBに保存する

Last updated at Posted at 2019-05-06

環境

Laravel 5.6
League/Csv 9.2

前提

  • Qiita初投稿です、お手柔らかにお願いします。
  • 今回はバリデーションについては実装、言及しません。

導入

League/Csvをインストールする。
composer dump-autoloadは多分必要。

composer require league/csv
composer dump-autoload

今回ぶち込みたいCSV

company_name name email
hoge株式会社 佐藤 exapmle1@example.com
foo株式会社 山田 exapmle2@example.com

実装

UserController.php
<?php

namespace App\Http\Controllers;

use App\Eloquent\User;
use Illuminate\Http\Request;
use League\Csv\Reader;
use League\Csv\Statement;

class UserController extends Controller
{

    // 省略

    public function importCSV(Request $request, Statement $stmt, User $user)
    {
        $file_path = $request->file('file')->getPathname();
        // ReaderはDIできないらしい。
        $csv = Reader::createFromPath($file_path, 'r')->setHeaderOffset(0);
        $records = $stmt->process($csv);
        $data = [];

        // 後ほど解説。
        foreach ($records as $record) {
            $record['created_at'] = now();
            $record['updated_at'] = now();
            $data[] = $record;
        }
        $user->insert($data);

        return redirect()->route('user.index');
    }
}

解説

ここでリクエストされたfileの一時保管パス?的なのを取得する。

$file_path = $request->file('file')->getPathname();

そしてここ、

foreach ($records as $record) {
            $record['created_at'] = now();
            $record['updated_at'] = now();
            $data[] = $record;
        }
        $user->insert($data);

$recordsには

ResultSet {#375 ▼
  #records: LimitIterator {#372 ▶}
  #header: array:4 [▶]
}

というオブジェクトが入っているのでforeachで取得していくとなんと、各recordには

[ "company_name" => "hoge株式会社"
  "name" => "佐藤",
  "email" => "example1@example.com"
]

などの配列が入っているというわけ。

Laravelだとinsertの引数に各レコードを値にもつ多次元配列を渡すことで複数レコードまとめて挿入できる。
しかし、insertは「created_at」「updated_at」が更新されないので、foreachで回しながら入れている。

おまけ

今回のroute

web.php
Route::post('/users/csv', "UserController@importCSV")->name('user.importCSV');

今回のview

users.blade.php
  {{ Form::open(['url' => route('user.importCSV'), 'method' => 'POST', 'class' => '', 'files' => true]) }}

  <div class='form-group'>
    <input type="file" name="file" value="">
  </div>

  <button type="submit">csv読み込み</button>

  {{ Form::close() }}

応用編

大切なことはすべて公式ドキュメントが教えてくれた。
9.0のドキュメント↓
https://github.com/thephpleague/csv/blob/master/docs/9.0/index.md

<?php
use League\Csv\Reader;
use League\Csv\Statement;

$csv = Reader::createFromPath('/path/to/your/csv/file.csv', 'r');

// headerは何行目か。
$csv->setHeaderOffset(0);

$header = $csv->getHeader();
//return [0 => "企業"
//  1 => "名前"
//  2 => "メールアドレス"]

// 10行飛ばして25行とる
$stmt = (new Statement())
    ->offset(10)
    ->limit(25);
$stmt->process($csv);

まとめ

2019年でPHPでcsvをいじりたいってなると、goodbyか、このLeague/Csvの二強な感じがしていて、今回書きやすそうだしGitHubのスターもダントツでLeague/Csvの方が高かったのでこちらを採用しました。
今回は使わなかったのですが、goodbyは省メモリを売りにしているそうなのでメモリを気にする量のcsvを裁くときは視野に入れたいですね。
結局、Laravelが好きです。

引用

4
6
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
4
6