😊
Laravelで実データと制御ファイル(ファイルサイズ量)をペアで出力する方法のメモ
はじめに
以下のように、実データと制御データをペアで管理するCSV連携(※)を行うユースケースを考えてみます。
目的は、CSV読み取り側が実データを読み取る前に、制御データの内容を元に事前バリデーションを行うことです。
今回は、ファイルサイズでバリデーションを行うケースを想定します。
$ cd storage/app/public/
$ head *
==> output_20210703072428.csv <==
1,apple,100
2,banana,150
3,cherry,200
==> output_20210703072428.ctl <==
38
※こういうのって名前がついていたりするんだろうか
前提
- Macでtreeコマンドを使用しています(動作確認用に。なければlsとかで代用可)
brewでインストールできます
$ brew install tree
やってみたこと
Laravelプロジェクトを作成
$ composer create-project laravel/laravel --prefer-dist csv-with-ctl-file
処理部を実装
web.phpを編集します。
web.php
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Route::get('/create', function () {
// CSVを想定したテストデータを作成
$items = array();
$items[] = array(
'id' => 1,
'name' => 'apple',
'price' => 100
);
$items[] = array(
'id' => 2,
'name' => 'banana',
'price' => 150
);
$items[] = array(
'id' => 3,
'name' => 'cherry',
'price' => 200
);
// ファイル出力設定
$filename = 'output_' . date( 'YmdHis' ); // e.g. output_20210703072148
$path = storage_path( 'app/public/' . $filename );
// データファイルの出力
$dataFile = new \SplFileObject( $path . '.csv', 'w' );
$dataFile->setCsvControl( ',' );
foreach( $items as $item ){
$dataFile->fputcsv( $item );
}
// コントロールファイルの出力
$ctrlFile = new \SplFileObject( $path . '.ctl', 'w' );
$ctrlFile->fwrite( $dataFile->getSize() );
});
実装の補足
-
/create
というパスを用意 -
$items = array();
で初期化した後に$items[] = <データ>
と記述してテストデータをどんどん追記していきます
// CSVを想定したテストデータを作成 $items = array(); $items[] = array( 'id' => 1, 'name' => 'apple', 'price' => 100 ); >> ```
-
SplFileObjectを使ってCSVとしてデータを出力します。
第3引数でw
を指定しているので書き出しモードでオープンし、ファイルが無ければ新規作成されます。他のモードのバリエーションはfopenのドキュメントを参照
$dataFile = new \SplFileObject( $path . '.csv', 'w' ); $dataFile->setCsvControl( ',' );
- SplFileObjectのgetSize()でバイト数を取得できる
$ctrlFile->fwrite( $dataFile->getSize() );
動作確認
- treeコマンドで前後の状態を取得し、curlで
/create
を叩き、ファイルが出力されたことを確認
$ tree storage/app/public/
storage/app/public/
0 directories, 0 files
$ curl http://localhost:8000/create
$ tree storage/app/public/
storage/app/public/
├── output_20210703072428.csv
└── output_20210703072428.ctl
$ cd storage/app/public/
$ head *
==> output_20210703072428.csv <==
1,apple,100
2,banana,150
3,cherry,200
==> output_20210703072428.ctl <==
38
最後に
簡単にできそうだとは思ったけど本当にできた。
SplFileInfoのユーティリティ、めっちゃ揃ってるので便利。
Discussion