WEBOPIXEL

Laravel ExcelでCSVをアップロードしてそのままDBに保存&ダウンロード

Posted: 2018.01.26 / Category: PHP / Tag: 

CSVファイルをそのままデータベースに保存したり、逆にデータベースをCSVにしてダウンロードしたいということはよくあると思います。
Laravel Excel というライブラリを使うと簡単にできるのでご紹介いたします。

Sponsored Link

Laravel 5.4
laravelcollective 5.4
Laravel Excel v2.1
を使用します。

Laravel Excelのインストール

Composerでインストールします。

composer require "maatwebsite/excel:~2.1.0"
Laravel Excel Documentation – Maatwebsite

初期設定

Laravel 5.5は必要ないですが、5.4まではコンフィグファイルにサービスプロバイダーとエイリアス登録します。

config/app.php

'providers' => [
	// ...
	Maatwebsite\Excel\ExcelServiceProvider::class,
],
'aliases' => [
	// ...
	'Excel' => Maatwebsite\Excel\Facades\Excel::class,
],

CSVファイルについて

今回は価格表を想定したテーブル構造にしてみます。
アップロードCSVファイルの最初の行はカラム名を入れます。

price.csv

id,code,name,price
1,G001,商品1,100
2,G002,商品2,200
3,G003,商品3,300
4,G004,商品4,400
5,G005,商品5,500
6,G006,商品6,600
7,G007,商品7,700
8,G008,商品8,800
9,G009,商品9,900
10,G010,商品10,1000

データベース作成

データベースは「商品コード」「商品名」「金額」の項目を作成してみます。

config/app.php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePricesTable extends Migration
{
	public function up()
	{
		Schema::create('prices', function (Blueprint $table) {
			$table->increments('id');
			$table->integer('code');
			$table->string('name');
			$table->integer('price');
		});
	}
	public function down()
	{
		Schema::dropIfExists('prices');
	}
}

migrateコマンドでデータベースにテーブルを作成します。

$ php artisan migrate

モデルの作成

モデルです。特別なことはありませんが、タイムスタンプを無効にしてます。

config/app.php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Price extends Model
{
	public $timestamps = false;

	protected $fillable = [
		'code',
		'name',
		'price'
	];
}

ルーティングの作成

管理画面から編集するという感じにしたいので「admin」でプレフィクスやらネームスペースを付与しています。

croutes/web.php

Route::group(['prefix' => 'admin', 'namespace' => 'Admin', 'as' => 'admin::'], function()
{
	Route::get('prices', 'PricesController@index')->name('prices');
	Route::patch('prices/upload', 'PricesController@upload')->name('prices.upload');
	Route::get('prices/download', 'PricesController@download')->name('prices.download');

});

ビューの作成

ビューにはファイルをアップロードするフォームとダウンロードするボタンを設置します。

resources/views/admin/prices/index.blade.php

{!! Form::model($prices, [
	'url' => route('admin::prices.upload'),
	'method' => 'PATCH',
	'files' => true
]) !!}
<div class="row">
	<div class="col-md-4">
		{!! Form::file('csv_file', null, ['class' => 'form-control']) !!}
	</div>
	<div class="col-md-8">
		{!! Form::submit('アップロード', ['class' => 'btn btn-primary']) !!}
	</div>
</div>
{!! Form::close() !!}

{{ link_to_route('admin::prices.download', 'ダウンロード', null, ['class' => 'btn btn-primary']) }}

コントローラーの作成

メインとなる部分です。
アップロードは差し替えにしたかったので、データを挿入する前にtruncateで全削除しています。
CSVのパース自体は\Excel::loadだけでしてくれます。
ある程度不特定のユーザーが使用擦る場合はもう少しデータのバリデーションも追記した方がよさそうですね。

app/Http/Controllers/Admin/PricesController.php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Price;

class PricesController extends Controller
{
    public function index()
    {
        $prices = Price::all();
        return view('admin.prices.index', compact('prices'));
    }

    public function upload(Request $request)
    {
        $this->validate($request, [
            'csv_file' => 'required|mimes:txt|max:1000'
        ]);
        $file = $request->file('csv_file');

		// ファイルの読み込み
        $reader = \Excel::load($file->getRealPath())->get();
        $rows = $reader->toArray();

        // 一度削除してから保存
        Price::truncate();
        if(count($rows)){
            foreach ($rows as $row) {
                Price::firstOrCreate($row);
            }
        }

        \Session::flash('flash_message', '価格表を更新しました。');
        return redirect()->route('admin::prices');
    }

    public function download(){
        $price = Price::get()->toArray();
        return \Excel::create('price', function($excel) use ($price) {
            $excel->sheet('sheet', function($sheet) use ($price)
            {
                $sheet->fromArray($price);
            });
        })->download('csv');
    }
}

今回はCSVでしたが、Laravel Excel は名前の通りエクセルファイルも扱えます。

ここまでのものはGithubに置いてます。

参考サイト
【Laravel-Excel】表ファイルを読み込んでそのままDBに保存する方法【CSVインポート】