Excelデータをweb上でも管理するアプリ作成[laravel]

題名の通り
Excelにあるデータをweb上でも管理するアプリを作成しました。

こちらにあるExcelファイルのデータをWeb上で管理します
[Excelファイル](https://qiita.com/freelanceradiation/items/7ebaea73b3334fddfd7d)	
※Macだと登録シートでデータの登録、一覧表示、変更、削除機能が使えないです。

#要件
・Web上でも顧客管理がしたい。（バックアップも兼ねて）
・検索したい
・検索した結果をExcelに出力したい

#画面
![スクリーンショット 2021-08-24 21.58.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700700/347a38c3-c027-d55c-5e4a-dfd25356d2a5.png)


#機能
・ログイン
・Excelデータ取り込み & 出力
・検索

#実装
今回はExcelデータ取り込み & 出力のみ書いていこうと思います。
参考：[検索機能](https://qiita.com/freelanceradiation/items/9008771e0425c8aca481)	

```php:Web.php
Route::middleware('auth')->group(function () {
    Route::get('/', 'ClientsController@index')->name('client.index');
    Route::get('/export', 'ClientsController@export')->name('export');
    Route::post('/import', 'ClientsController@import')->name('import');
});
```
```php:ClientsController.php
<?php

namespace App\Http\Controllers;

use App\Client;
use Illuminate\Http\Request;
use App\Exports\ClientExport;
use App\Imports\ClientImport;
use Maatwebsite\Excel\Facades\Excel;

class ClientsController extends Controller
{
    /**
     *　顧客一覧
     */
    public function index(Request $request)
    {

        $query = Client::query();

        $client_name = $request->client_name;

        //顧客名の値が存在&商品名の値が空ではなかった場合
        if ($request->has('client_name') && $client_name !== '') {
            $query->where('client_name', 'like', '%' . $client_name . '%')->get();
        }

        $datas = $query->paginate(15);


        return view('client.index', ['datas' => $datas, 'client_name' => $client_name]);
    }

    /**
     *　Excelファイル出力
     */
    public function export(Request $request)
    {
        $client_name = $request->client_name;
        $export_name = $request->export_name;

        if (!isset($export_name)) {
            return back()->withErrors('ファイル名を入力して下さい');
        }

        if (!isset($client_name)) {
            $client_name = "";
        }

        return Excel::download(new ClientExport($client_name), $export_name . '.xlsx');
    }

    /**
     *　Excelファイル取り込み
     */
    public function import(Request $request)
    {
        $file = $request->file('file');

        if (!isset($file)) {
            return back()->withErrors('ファイルを選択して下さい');
        }

        if ($file->getClientOriginalName() <> "顧客データ.xlsm") {
            return back()->withErrors('顧客データ.xlsmを選択して下さい');
        }
        $import = new ClientImport();
        $import->onlySheets('データ');  //シート指定

        Excel::import($import, $file);

        return back()->withStatus('保存しました'); //withStatus()は戻った時にメッセージを表示
    }
}


```

```php:views\client\index.blade.php
@extends('layouts.app')

@section('content')

<!-- エラーメッセージ表示 -->
@if ($errors->any())
<div class="alert alert-danger">
    <ul>
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif

<!-- 成功メッセージ表示 -->
@if (session('status'))
<div class="alert alert-success" role="alert">
    {{ session('status') }}
</div>
@endif
　
<div class="client">
    <div class="container mt-4 offset-2 flex">
        <div class="a a1" style="width:400px;">
            <form class="search" enctype="multipart/form-data" action="{{route('client.index')}}" accept-charset="UTF-8" method="get">
                @csrf
                <div class="searchBox">
                    <div class="a2">
                        <h2 class="mr-2">顧客名</h2>
                        <input type="text" name="client_name" class="form-control" value="{{isset($client_name) ? $client_name : "" }}">
                    </div>
                    <div class="a2">
                        <h2 class="mr-2">　</h2>
                        <span class="input-group-btn">
                            <input type="submit" class="btn btn-success ml-4" value="検索">
                        </span>
                    </div>
                </div>

            </form>
        </div>
        <div class="a a2">
            <form action="{{ route('import') }}" method="POST" enctype="multipart/form-data">
                @csrf
                <div class="form-group">
                    <input type="file" name="file">
                    <button class="btn btn-success">&emsp;取込&emsp;</button>
                </div>
            </form>
            <form action="{{ route('export') }}" method="GET" enctype="multipart/form-data">
                @csrf
                    <div class="form-group" >
                        <input type="hidden" name="client_name" class="form-control" value="{{$client_name ? $client_name : "" }}">
                    　 　<input type="text" name="export_name" placeholder="ファイル名を入力">
                        <button class="btn btn-secondary" style="width: 90px; margin-left: 121px;">出力</button>
                    </div>
            </form>
            <!-- <input type="submit" class="b btn btn-danger" value="登録"> -->
        </div>
    </div>
</div>


<div class="container mt-4">
    <div class="panel panel-default">
        <div class="panel-heading">全件{{$datas->total()}}件</div>
        <div class="panel-body">
        </div>
        <table border="1" class="table" style="border-collapse: collapse">
            @foreach($datas as $data)
            <thead class="bg-success">
                <tr>
                    <th>名前</th>
                    <th>連絡先</th>
                    <th>メールアドレス</th>
                </tr>
            </thead>
            <tbody>

                <tr>
                    <td>{{$data->client_name}}</td>
                    <td>{{$data->client_PhoneNumber}}</td>
                    <td>{{$data->client_email}}</td>
                </tr>

            </tbody>
            @endforeach　
        </table>
        <!-- 検索結果を保持したままページネーションできる-->
        {{ $datas->appends(request()->input())->links() }}
    </div>
</div>
</div>
@endsection
```

```php:app\Imports\ClientImport.php

<?php

namespace App\Imports;

use App\Client;
use Maatwebsite\Excel\Row;
use Maatwebsite\Excel\Concerns\OnEachRow;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithConditionalSheets;

class ClientImport implements OnEachRow, WithHeadingRow, WithMultipleSheets
{
    /**
     *　トレイト
     */
    use WithConditionalSheets;

    /**
     *　どのシートをインポートするか指定
     */
    public function conditionalSheets(): array
    {
        return [
            'データ' => new ClientImport()
        ];
    }

    /**
     *　データ保存
     */
    public function OnRow(Row $row)
    {
        $row = $row->toArray();
        
        $client = Client::FirstOrNew(
            // 重複除外カラムを指定
            ['client_email' => $row['メールアドレス']],
            // データベースのカラムとエクセルのカラムを紐づけ
            [
                'client_PhoneNumber' => $row['連絡先'],
                'client_name' => $row['顧客名'],
                'type_id' => 1,
            ]
        );

        $client->save();
    }
}
```

```php:app\Exports\ClientExport.php
<?php

namespace App\Exports;

use App\Client;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\FromCollection;

class ClientExport implements WithHeadings, FromCollection
{
    /**
     * コンストラクト
     */
    public function __construct(string $client_name)
    {
        $this->client_name = $client_name; // Where句のデータ
    }

    /**
     * 条件データ取得
     */
    public function collection()
    {
        return Client::where('client_name', 'like', '%' . $this->client_name . '%')->get(['client_name','client_PhoneNumber','client_email']);
    }

    /**
     * Excel1フィールド指定
     */
    public function headings(): array
    {
        return [
            '顧客名',
            '電話番号',
            'メールアドレス'
        ];
    }
}
```
#感想
・もっと工夫すればいいものが作れそうな気がする。
・出力したシートの名前もちゃんと設定できるようにしたらよかった。

今回はExcelファイルのデータをWeb上で管理するというのが目的だったので、いい感じにできたのではないのでしょうか。※実務で使うとなればまだまだですが・・・