環境
Laravel 5.6
League/Csv 9.2
前提
- Qiita初投稿です、お手柔らかにお願いします。
- 今回はバリデーションについては実装、言及しません。
導入
League/Csvをインストールする。
composer dump-autoloadは多分必要。
composer require league/csv
composer dump-autoload
今回ぶち込みたいCSV
company_name | name | |
---|---|---|
hoge株式会社 | 佐藤 | exapmle1@example.com |
foo株式会社 | 山田 | exapmle2@example.com |
実装
<?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
Route::post('/users/csv', "UserController@importCSV")->name('user.importCSV');
今回のview
{{ 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が好きです。
引用