九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、以前このブログで「DBデータをCSV・Excelでエクスポートする」という記事を公開しました。
タイトルのとおりデータベースから必要なデータをエクスポートする機能なのですが、今回はこの機能に前からつけてみたかった「便利機能」を開発してみます。
それは・・・・
選択したカラムのデータだけをExcelでダウンロードする
という機能です。
例えばこんなことってないでしょうか。
DMを郵送したいから、会員ユーザーの「名前」と「住所」だけダウンロードしたい📮
もちろん、全データをダウンロードできれば後で編集できますが、必要な部分だけに絞り込むことができればとっても便利です。
そこで!
今回はLaravel
を使って選択したカラムだけExcel
でダウンロードする機能を作ってみます。
ぜひ楽しみながらやっていきましょう❗
「今調べたら、excelは英語で
『優れている』っていう意味なんですね😊」
開発環境: Laravel 7.x
目次
前提として
今回はusers
テーブルのダウンロード機能をつくりますので、以下のようなテストデータが入っていることが前提になります。
もしまだ用意されていない方は、「Laravel6.x以降でログイン機能をインストールする方法」が参考になると思います。
では、実際にやっていきましょう❗
パッケージをインストールする
まずPHP
でExcel
を操作するパッケージをcomposer
でインストールします。
composer require phpoffice/phpspreadsheet
モデルにカラムを取得できるメソッドを追加する
今回はカラム(フィールド)はDBテーブルから自動的にとってくるようにしたいので、User
モデルにgetTableColumns()
を追加します。
/app/User.php
<?php // 省略 class User extends Authenticatable { // 省略 public function getTableColumns() { // 👈 テーブルのカラムを取得 $table = $this->getTable(); $columns = $this->getConnection() ->getSchemaBuilder() ->getColumnListing($table); $hidden_columns = $this->getHidden(); return array_diff($columns, $hidden_columns); // hiddenとされているものを除外 } }
なお、この中で重要なのが、$hidden_columns
です。
この中にはpassword
などモデルとしては表示しないカラムが入っていて、「ダウンロード可能なカラム」からは除外するようにしています。
例えば、カラムが以下3つだとします。
id, name, password
このとき$hidden_columns
にpassword
が入っているとしたら、最終的に「ダウンロード可能なカラム」は
id, name
になります。
※さすがにモデルで隠されているデータをダウンロードできると問題かと思ってつけましたが、お好みで変更してください。
ルートをつくる
では、Laravel
にルートをつくりましょう。
Route::get('excel/form', 'ExcelController@form'); Route::post('excel/download', 'ExcelController@download');
1つ目がブラウザから直接アクセスする部分で、2つ目がダウンロードを実行するURLになります。
コントローラーをつくる
では、ルートにセットしたコントローラーをつくっていきます。
以下のコマンドを実行してください。
php artisan make:controller ExcelController
そして、作成されたファイルの中身を次のように変更します。
/app/Http/Controllers/ExcelController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; class ExcelController extends Controller { public function form() { $columns = (new \App\User)->getTableColumns(); return view('excel.form')->with('columns', $columns); // 👈 ビューへカラムを送る } public function download(Request $request) { $columns = (new \App\User)->getTableColumns(); $downloading_columns = []; foreach($columns as $column) { if(in_array($column, $request->columns)) { $downloading_columns[] = $column; } } $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $downloading_data = []; $users = \App\User::get(); foreach($users as $user) { $downloading_data[] = $user->only($downloading_columns); } $sheet->fromArray($downloading_data, null, 'A1'); $filename = 'users.xlsx'; $writer = new Xlsx($spreadsheet); header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); header('Content-Disposition: attachment; filename="'. $filename .'"'); $writer->save('php://output'); } }
まずform()
の部分ですが、ここはブラウザから直接アクセスする「ダウンロードページ」を作成する部分です。
そのため、ビューを呼び出すことになるのですが、このビューの中で先ほどの「ダウンロード可能なカラム名」が使えるようにしています。
そしてdownload()
は、実際にExcel
ファイルをダウンロードする部分です。
ここではひと手間加えてセキュリティ上のリスクを排除しています。
手順としては次のとおりです。
- まず(元々の)「ダウンロード可能なカラム」を取得
- 実際に送信されてきた選択カラムから1に含まれているカラムだけ抽出
- ダウンロードに適用
つまり、悪意のある送信があったとしても「ダウンロード可能なカラム」に入っていない場合はダウンロードできないなっています。(バリデーションのin
条件を使ってもいいかもしれません)
※つまり、直接送信されてきたカラムを直接使ってダウンロードさせるのはセキュリティ上あまりいいとはいえません。
あとは、DBからデータを取得してExcelファイル
として保存するようにしているだけです。
ビューをつくる
では、最後に「ダウンロードページ」のためのビューを作成しましょう。
(今回は通常の送信フォームを使うので、Vue
やAjax
は使わずネイティブなJavaScript
だけで作ってみました)
/resources/views/excel/form.blade.php
<html> <head> <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="p-3"> <h3 class="mb-4">選択したカラムのデータだけExcelでダウンロード</h3> <form id="form" method="post" action="/excel/download"> @csrf <div class="row"> <div class="col-md-6"> <div class="card"> <div class="card-body"> <!-- ダウンロード可能なカラムのチェックボックスをつくる ・・・ ① --> @foreach($columns as $column) <label> <input class="columns" name="columns[]" type="checkbox" value="{{ $column }}"> {{ $column }} </label> <br> @endforeach </div> <div class="card-footer"> <button type="submit" class="btn btn-primary float-right">ダウンロードする</button> <label> <input id="all_check" type="checkbox"> 全て選択/解除 </label> </div> </div> </div> </div> </form> </div> <script> document.querySelector('#form') // フォームが送信されたとき実行 ・・・ ② .addEventListener('submit', e => { const columns = document.querySelectorAll('.columns:checked'); if(columns.length === 0) { e.preventDefault(); alert('最低でもひとつはカラムを選択してください。'); } }); document.querySelector('#all_check') // 全て選択/解除を実行 ・・・ ③ .addEventListener('click', e => { const allChecked = e.target.checked; const columns = document.querySelectorAll('.columns'); for(let column of columns) { column.checked = allChecked; } }); </script> </body> </html>
ではこの中でやっていることを見ていきましょう。
①ダウンロード可能なカラムのチェックボックスをつくる
コントローラーでセットした「ダウンロード可能なカラム」をここでループさせてチェックボックを作っています。
②フォーム送信されたとき実行
「ダウンロードする」ボタンがクリックされたときに実行される部分です。
ここでは、チェックが入ったカラムの数を取得し、もしゼロの場合は「最低でもひとつはカラムを選択してください。」と表示するようにしています。
またその場合、e.preventDefault()
で送信をキャンセルしています。
③全て選択/解除を実行
まず現在の「全て選択/解除」のチェックがtrue or false
かを取得し、ダウンロードしたいカラムの全チェックボックスをその状態に合わせるようにしています。
テストしてみる
では実際にテストしてみましょう❗
このチェックボックスの中から「id」「name」「email」だけにチェックを入れてダウンロードボタンをクリックしてみます。
するとダウンロードが実行されるので、そのファイルを開くと・・・・・
はい、このとおり選択した3つのカラムだけがダウンロードできました❗
成功です😊✨
教材ソースコードをダウンロードする
以下からは今回実際に開発した教材ソースコード一式をダウンロードすることができます。
【Laravel】選択したカラムだけExcelでダウンロードするおわりに
ということで、今回は選択されたカラムだけをExcel
でダウンロードする機能をつくってみました。
こういった機能があると、よりユーザビリティが向上すると思うので、きっと使う側からは感謝されるんじゃないでしょうか(というか、そうあってほしいです😂)
ではでは〜❗
「コレ便利ですね〜、
と言われるとテンション上がりますよね👍✨」