ユーザ用ツール

サイト用ツール


プログラム言語:php:laravel:csvアップロード

文書の過去の版を表示しています。


【Laravel】CSVアップロード(インポート)

CSVファイルをアップロードし、バリデーションチェック&DBに登録する方法の一例。

config\site\csv.php

コンフィグファイルに、csv の列に対応した DB カラム名の関連付けを定義する。

  1. <?php
  2. return [
  3. 'csv_columns' => [
  4. 0 => 'number',
  5. 1 => 'title',
  6. 2 => 'name',
  7. 3 => 'age',
  8. 4 => 'comment',
  9. ],
  10. ];

app\Libs\SampleCsv.php

csv 周りの処理をクラスにまとめておく。

  1. <?php
  2.  
  3. namespace App\Libs;
  4.  
  5. class SampleCsv
  6. {
  7. private $file;
  8. private $data = [];
  9.  
  10. public function __construct($path)
  11. {
  12. $this->file = new \SplFileObject($path);
  13. }
  14.  
  15. public function convertColumns()
  16. {
  17. $count = 0;
  18.  
  19. while (!$this->file->eof()) {
  20. $line = $this->file->fgetcsv(',', '\'');
  21.  
  22. $count ++;
  23.  
  24. if (!$line || is_null($line[0])) {
  25. continue;
  26. }
  27.  
  28. mb_convert_variables('UTF-8', 'sjis-win', $line);
  29.  
  30. $tmp = [];
  31. foreach ($line as $key => $val) {
  32. $column_name = config('site.csv.csv_columns')[$key];
  33. $tmp[$column_name] = $val;
  34. }
  35.  
  36. $this->data[$count] = $this->revise($tmp);
  37. }
  38.  
  39. return $this->data;
  40. }
  41.  
  42. // 入力内容の補正
  43. private function revise($inputs)
  44. {
  45. foreach ($inputs as $key => $input) {
  46. switch ($key) {
  47. case 'number':
  48. case 'age':
  49. // 全角英数を半角に
  50. $input = mb_convert_kana($input, 'as');
  51. break;
  52. }
  53.  
  54. $inputs[$key] = $input;
  55. }
  56.  
  57. return $inputs;
  58. }
  59.  
  60. public function validationRules()
  61. {
  62. return [
  63. 'number' => 'bail|required|integer|between:0,999999999',
  64. 'title' => 'bail|required|max:100',
  65. 'name' => 'bail|required|max:50',
  66. 'age' => 'bail|required|integer|between:0,150',
  67. 'comment' => 'bail|max:1000',
  68. ];
  69. }
  70.  
  71. public function validationMessages()
  72. {
  73. return [
  74. ];
  75. }
  76.  
  77. public function validationAttributes()
  78. {
  79. return [
  80. 'number' => 'No',
  81. 'title' => 'タイトル',
  82. 'name' => '名前',
  83. 'age' => '年齢',
  84. 'comment' => 'コメント',
  85. ];
  86. }
  87. }

app\Http\Controllers\SampleController.php

ajax の場合の例。
普通の POST 送信の場合は「return response()→json()」としているところを書き換えれば OK。

  1. <?php
  2.  
  3. namespace App\Http\Controllers;
  4.  
  5. use App\Http\Controllers\Controller;
  6. use Illuminate\Support\Facades\Validator;
  7.  
  8. use DB;
  9.  
  10. # models
  11. use App\Models\Sample;
  12.  
  13. # requests
  14. use App\Http\Requests\Admin\SampleRequest;
  15.  
  16. # libs
  17. use App\Libs\SampleCsv;
  18.  
  19. class SampleController extends Controller
  20. {
  21. public function store(SampleRequest $request)
  22. {
  23. $sample_csv = new SampleCsv($request->file('csv')->path());
  24. $csv_data = $sample_csv->convertColumns();
  25.  
  26. $csv_errors = []; // エラーメッセージを格納
  27. $number_count = []; // number の重複チェック用
  28.  
  29. foreach ($csv_data as $key => $val) {
  30. $validator = Validator::make(
  31. $val,
  32. $sample_csv->validationRules(),
  33. $sample_csv->validationMessages(),
  34. $sample_csv->validationAttributes()
  35. );
  36.  
  37. if ($validator->fails() === true) {
  38. $csv_errors[$key] = $validator->errors()->all();
  39. }
  40.  
  41. $number = $val['number'];
  42.  
  43. $number_count[$number] = isset($number_count[$number])
  44. ? $number_count[$number] + 1
  45. : 1;
  46.  
  47. $sample = Sample::where('number', $number)
  48. ->first();
  49.  
  50. if (!is_null($sample)) {
  51. $csv_errors[$key][] = $number . ' は登録済みのNoです。';
  52.  
  53. } elseif ($number_count[$number] > 1) {
  54. $csv_errors[$key][] = 'No ' . $number . ' はcsvファイル内で重複しています。';
  55. }
  56. }
  57.  
  58. if (count($csv_errors) > 0) {
  59. $response = [];
  60. $response['message'] = 'The given data was invalid.';
  61. $response['errors'] = ['csv_errors' => $csv_errors];
  62. return response()->json($response, 422);
  63. }
  64.  
  65. try {
  66. DB::beginTransaction();
  67.  
  68. Art::delete();
  69.  
  70. foreach ($csv_data as $val) {
  71. $sample = new Sample();
  72. $sample->fill($val);
  73. $sample->save();
  74. }
  75.  
  76. } catch (\Exception $e) {
  77. $log_message = var_export([
  78. 'message' => $e->getMessage(),
  79. 'file' => $e->getFile(),
  80. 'line' => $e->getLine(),
  81. ], true);
  82. \Log::channel('system_error')->info($log_message);
  83.  
  84. return response()->json(['status' => 'error']);
  85. }
  86.  
  87. DB::commit();
  88.  
  89. return response()->json(['status' => 'success']);
  90. }
  91. }

app\Http\Requests\SampleRequest.php

  1. <?php
  2.  
  3. namespace App\Http\Requests;
  4.  
  5. use Illuminate\Foundation\Http\FormRequest;
  6.  
  7. class SampleRequest extends FormRequest
  8. {
  9. public function authorize()
  10. {
  11. return true;
  12. }
  13.  
  14. public function rules()
  15. {
  16. return [
  17. 'csv' => [
  18. 'bail',
  19. 'required',
  20. 'file',
  21. ],
  22. ];
  23. }
  24.  
  25. public function attributes()
  26. {
  27. return [
  28. 'csv' => 'csv',
  29. ];
  30. }
  31. }

コメント

コメントを入力. Wiki文法が有効です:
 
プログラム言語/php/laravel/csvアップロード.1611563444.txt.gz · 最終更新: 2021/01/25 17:30 by humolife