LaravelでCSVのインポート時のバリデーションをFromRequestで完結する方法
外部からデータを入れる際のゲートとしてFormRequestにまとめたかった
FormRequestのバリデーション前にCSVを取り込んでパラメータに加えて上げればうまくできた。
//実装例
class ProductRequest extends FormRequest
{
//バリデーション実行まえにCSVを読み込んでパラメータにセットする。
protected function prepareForValidation()
{
//既存のパラメータを取得しておく
$params = $this->all();
//アップロードファイルからエンコードを推定
$upload = $this->file('csv');
$detectEncoding = mb_detect_encoding($upload->getContent(), ['SJIS-win', 'SJIS', 'UTF-8'], true);
//SplFileObjectにしてから読み込んで行く(ExcelCSVのセル内改行など処理etc)
$csv = new \SplFileObject($upload->path());
$csv->setFlags(
\SplFileObject::READ_CSV |
\SplFileObject::READ_AHEAD |
\SplFileObject::SKIP_EMPTY |
\SplFileObject::DROP_NEW_LINE
);
$collection = collect();
foreach ($csv as $value) {
$collection->add(mb_convert_encoding($value, "UTF-8", $detectEncoding));
}
//読み込んだデータからパラメータをセット
$params['header'] = $collection->shift();
$params['data'] = [];
$headerNames = ['id','name','price'];
foreach($collection as $idx1 => $row){
foreach ($headerNames as $idx2 => $name) {
$params['data'][$idx1][$name] = $row[$idx2];
}
};
$this->merge($params);
}
public function rules(): array
{
if (request()->method == Request::METHOD_GET) {
$rules = [];
} else {
$rules = [
'csv' => ['required', 'mimes:csv', 'mimetypes:text/plain,text/csv'],
'header' => ['required', 'regex:/^id,name,price$/'],
'data.*.id' => ['required'],
'data.*.name'=>['required'],
'data.*.price'=>['required'],
];
}
return $rules;
}
public function attributes()
{
return [
'csv' => 'CSVファイル',
'header' => 'ヘッダー行',
'data.*.id' => '商品ID',
'data.*.name'=>'商品名',
'data.*.price'=>'価格',
];
}
}