• 請求くん
  • Laravel

[Laravel]CSVファイルのインポート機能作成 (maatwebsite/excel)

LaravelでCSVファイルのインポート機能を追加するにあたってライブラリを探していたところ、maatwebsite/excelが使いやすそうだったので試してみました。
実際に使用した方法を記録として残しておきます。

インストール

公式は下記です。
https://docs.laravel-excel.com/3.1/getting-started/installation.html

composer require maatwebsite/excel
php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config

config/excel.php というファイルが作成されます。

前提

  • 今回アップロードしたいCSVのサンプル
企業名,郵便番号,住所,電話番号,代表者名,担当者名,備考
テスト02株式会社,2203456,埼玉県上尾市井戸木,090-4736-0924,佐藤,中島,テストです

上記の1行目をタイトルとして認識させ、2行目以降をデータとして挿入したいという要件です。

フロント(Blade)

<form action="{{ route('company.import') }}" method="post" enctype="multipart/form-data" class="flex flex-col md:flex-row items-center gap-2 justify-end w-full md:w-3/4 lg:w-2/5">
    @csrf
    <div class="w-full flex-1">
        <input type="file" name="file" id="file" accept=".csv,.xlsx,.xls" class="w-full text-gray-500 font-medium text-sm bg-gray-100 file:cursor-pointer cursor-pointer file:border-0 file:py-2 file:px-4 file:mr-4 file:bg-gray-800 file:hover:bg-gray-700 file:text-white rounded">
    </div>
    <div class="w-full md:w-44 flex gap-2 justify-end">
        <button type="submit" class="focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 border border-gray-300 hover:opacity-80">アップロード</button>
        <button type="button" id="clearButton" class="focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-3 py-1.5 border border-gray-300 hover:opacity-80">クリア</button>
    </div>
</form>

ファイル送信のためのフォームを作成します。
ファイル送信の際には、formタグにenctype="multipart/form-data"を入れる必要があるので忘れずに。

6〜9行目のボタン(クリアボタン)は、ファイル選択したけど「やっぱやめた」というとき用のボタンです。
これはJavaScriptで実装しているのですが、今回の内容とはずれるので詳細は割愛します。

ルーティング

web.php

Route::post('/company/import', [CompanyController::class, 'import'])->name('company.import');

CompanyControllerのimportメソッドを読み込んでいます。

コントローラーの作成

CompanyController.phpのimportメソッド

// メソッドだけ抜き取り

public function import(Request $request)
{
    $file = $request->file('file');
    Excel::import(new CompaniesImport, $file);
    return redirect()
        ->route('company.index')
        ->with('message', 'データが正常にインポートされました');
}

CompaniesImport.phpというImportクラスを読み込んでいるので、作成します。

Importクラスの作成

app/Imports/CompaniesImport.phpを作成(ディレクトリは任意)

namespace App\Imports;

use App\Models\Company;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class CompaniesImport implements ToModel, WithHeadingRow
{
    public function model(array $row)
    {
        return new Company([
            'name' => $row['企業名'],
            'post_code' => $row['郵便番号'],
            'address' => $row['住所'],
            'tel' => $row['電話番号'],
            'ceo_name' => $row['代表者名'],
            'responsible_person_name' => $row['担当者名'],
            'note' => $row['備考'],
        ]);
    }
}

WithHeadingRowを使用すると、最初の行をタイトルとして認識してくれるようです。
他にも色々使い方があるようなので、公式をご確認ください。
https://docs.laravel-excel.com/3.1/imports/heading-row.html

WithHeadingRowで最初の行のタイトルが日本語だとうまくいかないという事象が発生しました。
config/excel.phpHeading Row Formatterの部分をnoneにするとうまくいきました。

'heading_row'  => [
    'formatter' => 'none',
],

以上です。
誰かの参考になれれば幸いです。