
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、前回・前々回とDBのユーザーデータに関連する話題をお届けしました。
そして、この流れで何か記事にできないかと考えていたのですが、ひとつまだこのブログでは紹介していない内容を思いつきました。
それは、
CSVファイルのインポート
です。
例えば、CSV
ファイルにたくさんのユーザー情報が入っていて、このファイルをアップロードすることでDBのusers
テーブルにデータを追加することができるという、ある種ユーザービリティにも通じる機能です。
もちろんこの機能を応用すれば、ユーザー情報だけでなく商品データなどその他のデータをインポートすることもできるようになります。
ぜひ皆さんのお役に立てると嬉しいです
開発環境: Laravel 6.x
前提として
今回はusers
テーブルにデータをインポートをするので、Laravel
のログイン機能が有効になっている必要があります。詳しくは以下のページをご覧ください。
- Laravel 6.x 以上 ・・・ Laravel6.0でログイン機能を使う方法
- それ未満 ・・・ 【Laravel5.6】インストール直後にやること3点
パッケージをインストールする
CSV
のデータをチェックするパッケージcsv-validatorをインストールします。(私が公開しているパッケージです。今回のためにフルで書き直しました)
composer require sukohi/csv-validator:3.*
ルートをつくる
では、先にルートをつくっておきましょう。
/routes/web.php
Route::get('csv_import', 'CsvImportController@create');
Route::post('ajax/csv_import', 'CsvImportController@ajax_store');
1行目がブラウザからアクセスするルートで、2行目はCSVファイル
をAjax
で送信する部分です。
コントローラーをつくる
続いてコントローラーをつくります。
以下のコマンドを実行してください。
php artisan make:controller CsvImportController
そして、中身を次のようにしてください。
app/Http/Controllers/CsvImportController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Sukohi\CsvValidator\Rules\Csv;
class CsvImportController extends Controller
{
public function create() {
return view('csv_import.create');
}
public function ajax_store(Request $request) {
$csv_rules = [
0 => 'required|email|unique:users,email',
1 => 'required|string',
2 => 'required|string|min:6'
];
$request->validate([
'csv_file' => [
'required',
'file',
new Csv($csv_rules, 'sjis-win')
]
]);
$csv_data = $request->csv_file_data; // パッケージが作成したCSVデータ
foreach($csv_data as $row_data) {
$user = new \App\User();
$user->email = $row_data[0];
$user->name = $row_data[1];
$user->password = bcrypt($row_data[2]);
$user->save();
}
return ['result' => true];
}
}
この中では、create()
がブラウザでアクセスするメソッド、ajax_store()
がAjax
を通してアクセスするメソッドになります。
なお、ajax_store()
の中では、まず先ほどインストールしたパッケージをつかってバリデーションを実行し、問題がなければアップロードされたCSV
のデータを使ってユーザーを新規登録しています。
ビューをつくる
/resources/views/csv_import/create.blade.php
というファイルをつくって中身を次のようにします。
<html>
<body>
<div id="app">
<h1>CSVファイルでDBにインポート</h1>
<label>CSVファイル</label><br>
<input id="file" type="file" @change="onFileChange">
<div v-if="csvErrors">
<ul>
<li v-for="error in csvErrors" v-text="error"></li>
</ul>
</div>
<br>
<button type="button" @click="onSubmit">インポートする</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.0/axios.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
csvFile: null,
csvErrors: []
},
methods: {
onFileChange(e) {
this.csvFile = e.target.files[0];
},
onSubmit() {
this.csvErrors = [];
const url = '/ajax/csv_import';
let formData = new FormData();
formData.append('csv_file', this.csvFile);
axios.post(url, formData)
.then(response => {
if(response.data.result) {
document.getElementById('file').value = '';
alert('インポートが完了しました。');
}
})
.catch(error => {
this.csvErrors = error.response.data.errors.csv_file;
});
}
}
});
</script>
</body>
</html>
この中で重要なのは2ヶ所です。
まずひとつめは、<input type="file">
につけられたchange
イベントです。このイベントが実行されると、onFileChange
が呼ばれ、選択されたファイルの情報がVue
のdata
に保持されることになります。
そして、もうひとつは「インポートする」ボタンをクリックしたときに実行されるonSubmit()
の部分です。
ここでは、選択されたcsv
ファイルをFormData
で送信しています。アクセスするのは先ほどつくったコントローラーのajax_store()
です。
なお、もしエラーが発生した場合は<input type="file">
の下にv-for
を使って表示するようになっています。
実際にブラウザでアクセスするとこうなります。
テストしてみる
では、実際に以下のCSV
を送信してテストしてみます。
文字コードはShift_JIS
です。
ファイルを選択して送信します。
実行後のusers
テーブルです。
うまく追加されました
では次に、バリデーションがうまく働いているかをチェックするために、今の状態のままで次のCSV
ファイルを送信してみましょう。
送信すると次のようになりました。
成功です
ダウンロードする
今回開発したソースコード一式を以下からダウンロードすることができます。
※ ただし、パッケージのインストールはご自身で行ってください。また、storage/app/csv
にはアップロード用のuser.csv
が入っています。
おわりに
ということで、今回はCSV
ファイルを使ったインポート機能をつくってみました。
比較的にデータをCSV
でダウンロードさせる機能は簡単なのですが、アップロードの場合はバリデーションが必要になってくるのでちょっと手間だったりしますが、今回のパッケージを使っていただくと時短で開発ができると思います。
また、今回のパッケージは内部的には同じく私が公開しているfluent-csvというパッケージを使っています。これは元々php-spreadsheet
でShift_JIS
のCSV
が作れなかったので作成したパッケージですが、現在はCSVの「読み・書き」両方に対応しているのでこちらも興味があるかたはぜひ使ってみてくださいね。
ではでは〜!