Laravelで簡単にCSVファイルをインポートする方法

Posted in Laravel on 10月 26, 2016

ほかのシステムから取得したCSVファイルをインポート/アップロードしてデータベースに保存したいという機会は頻繁にあるかと思います。

CSVファイルをインポートする方法にはいろいろありますが、この記事では、maatwebsite/excelパッケージを利用して簡単にファイルをインポートする方法を説明します。

maatwebsite/excelパッケージを利用してダウンロードしたい場合は、Laravelで簡単にテーブル情報をダウンロードを参考にしてください。

Laravel 5.3におけるmaatwebsiteパッケージのインストール

maatwebsiteパッケージの利用するためにはパッケージのインストールとサービスプロバイダーの登録を行う必要があります。

Composerを利用したパッケージのインストール

パッケージをインストールするためには、composr.jsonにmaawebsite/excelを追加して、composer updateを実行します。

composer.json

{
    "name": "laravel/laravel",
    "description": "The Laravel Framework.",
    "keywords": ["framework", "laravel"],
    "license": "MIT",
    "type": "project",
    "require": {
        "php": ">=5.6.4",
        "laravel/framework": "5.3.*",
        "maatwebsite/excel": "~2.1.0"

composer.jsonに"maatwebsite/excel": "~2.1.0"行を追加した後、composer updateを行います。

composer updateを実行するとすべてのパッケージが更新されるので、少し時間がかかりますが、画面を見ているとmaatwebsite/excelのインストールを確認することができます。

$composer update
Warning: This development build of composer is over 60 days old. It is recommended to update it by running "/usr/local/bin/composer self-update" to get the latest version.
Loading composer repositories with package information
Updating dependencies (including require-dev)
      ・
      ・
      ・

 - Installing maatwebsite/excel (2.1.6)
    Downloading: 100%

Excelのサービスプロバイダーを登録

config/app.phpにExcelのサービスプロバイダーとエイリアスを登録します。 追加するのは、Maatwebsite\Excel\ExcelServiceProvider::class、'Excel' => Maatwebsite\Excel\Facades\Excel::classの2行です。

'providers' => [

    /*
     * Laravel Framework Service Providers...
     */

Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
Maatwebsite\Excel\ExcelServiceProvider::class,
'aliases' => [

'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
'Excel' => Maatwebsite\Excel\Facades\Excel::class,

これでmaatwebsite/excelパッケージを利用する環境は整いました。

インポートに必要な各種ファイルの作成

パッケージのインストールは完了したので、テーブル、コントローラー、ルーティング等インポートを構成するファイルの作成を行います。

テーブルの準備

インポートするデータを格納するテーブルを作成します。

列は、品番(product_id)、商品名(product_name)、価格(price)で構成されています。

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->increments('id');
            $table->string('product_id');
            $table->string('product_name');
            $table->Integer('price');
            $table->timestamps();
        });
    }

ルーティングの追加

laravel5.3では、web.phpに必要な情報を登録します。

Route::get('import','ImportController@index');
Route::post('import','ImportController@import');

Route::get('products','ProductController@index');

コントローラーの作成

フォームから受け取ったCSVファイルのデータは、インストールしたパッケージを利用して読み取り、読み取ったデータをデータベースに保存します。

ImportContrller.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Product;

use Excel;
use Redirect;

class ImportController extends Controller
{

    public function index()
    {
        return view('import');
    }

    public function import(Request $request){

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

        $rows = Excel::load($file->getRealPath(),function($reader){

        })->get();

        $rows = $rows->toArray();

        foreach ($rows as $row){

            Product::create($row);

        }

        return redirect('products');

    }

}

CSVインポートフォーム画面

ファイルを選択し、アップロードする開始するフォーム画面は下記の通りです。

インポート画面

import.blade.php

@extends('base')

@section('content')
<div class="row">
        <div class="col-md-6">

            <h2>商品情報のCSVインポート画面</h2>

            <form method="POST" action="/import" enctype="multipart/form-data">

            {{ csrf_field() }}

            <table class="table table-bordered">
            <thead>
                <tr>
                <th>項目</th>
                <th>値</th>
                </tr>
            </thead>
            <tbody>
            <div class="form-group">
                <tr>
                <th>
                <label for="pca_product_id" class="control-label">ファイル名</label>
                </th>
                <td>
                <input type="file" name="file" class="form-control">
                </td>
                </tr>
            </div>
            </tbody>
            </table>

            <div class="form-group">
                <button type="submit" class="btn btn-primary">インポートする</button>
            </div>

            </form>

        </div>
    </div>   
@stop

インポートするデータ

インポートをするために下記のようなデータを作成し、CSV形式で保存します。

1行目の列名には、データベースで利用している列名と同じ名前を必ず使用します.

product.csv CSVデータ

ファイルのアップロード

フォーム画面かproduct.csv選択してインポートボタンを押すとデータがテーブルに登録され、product一覧表で追加した品番の情報を確認することができます。

商品一覧

複数のEloquentモデルでImportControllerを共有

先ほどまでは、Poductのみに注目してきましたが、システムにはProduct以外にもさまざまなテーブルがあるかと思います。 それぞれのテーブルに対して、ImportのためのControllerを作成するのは効率が悪いので先ほどから一歩進めて共有化するために少しだけコードを変更します。

共有化のためのコントローラーファイルの更新

新たに変数$model_nameを追加し、フォーム画面からPOSTで$model_name変数を受け取ります。$model_nameを追加することにより、先ほどまでは直接書き込んでいたProductを変数に変更することでProductだけではなく、ほかのモデルでも使用できるようにします。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Excel;
use Redirect;

class ImportController extends Controller
{

    public function index()
    {
        return view('import');
    }

    public function import(Request $request){

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

        $model_name = 'App\\'.$request->name;

        $rows = Excel::load($file->getRealPath(),function($reader){

        })->get();

        $rows = $rows->toArray();

        foreach ($rows as $row){

            $model_name::create($row);

        }

        return Redirect::back();

    }

}

フォームに変数nameを入れる

新規にhiddenのinput行を追加して、valueには、インポートしたモデル名を指定します。

<input type="hidden" name="name" value="Product">

ほかのモデルにインポートしたい場合は、valueの値をほかのモデル名に変更します。

また、先ほどCSVファイルの作成時にも記載しましたが、CSVの1行目の列名は各モデルに対応するテーブルの列名にあわせてください。

以上の2点の変更で、コントローラーを共有化して簡単にCSVファイルをインポートすることができます。