例外処理の対応(Laravel)

## はじめに
バックエンド側（API側)の処理で必要な処理だけを急いで書いて、エラー処理は疎かになりがちで、書いてもいつも書き方がまちまちなので、ここでいったん整理した。


## 記載方法
まとめたといっても単純でtry catchを使用することである。
特定の不具合に関してはエラー処理を具体的に決めて処理をするということである。

### 記載例
コントローラファイル
App\Http\Controllers
```php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\QueryException;
use PDOException;
use Exception;
use App\Exceptions\FileExtensionException;
use App\Exceptions\CsvColumnMismatchException;

class MyController extends Controller
{
    public function handleRequest(Request $request)
    {
        try {
            // ファイル拡張子の確認
            $this->validateFileExtension($request);

            // CSVファイルのカラム確認
            $this->validateCsvColumns($request);

            // トランザクションとDB操作
            $this->handleTransaction($request);  // $request を渡す

            return redirect()->route('success.page');

        } catch (FileExtensionException $e) {
            return back()->with('error', 'アップロードされたファイルはCSVではありません。');

        } catch (CsvColumnMismatchException $e) {
            return back()->with('error', 'CSVのカラムが一致しません。');

        } catch (PDOException $e) {
            return back()->with('error', 'データベースに接続できませんでした。');

        } catch (QueryException $e) {
            return back()->with('error', 'データベースクエリに問題がありました。');

        } catch (Exception $e) {
            \Log::error($e);  // 例外をログに記録
            return back()->with('error', 'データの操作中にエラーが発生しました。');
        }
    }

    private function validateFileExtension(Request $request)
    {
        if ($request->file('csv_file')->getClientOriginalExtension() !== 'csv') {
            throw new FileExtensionException();
        }
    }

    private function validateCsvColumns(Request $request)
    {
        // ここではサンプルとしてCSVの最初の行を取得し、カラムを確認します。
        $file = new \SplFileObject($request->file('csv_file')->path());
        $header = $file->fgetcsv();

        $expectedColumns = ['column1', 'column2', 'column3'];  // 期待されるカラム名のサンプル

        if ($header !== $expectedColumns) {
            throw new CsvColumnMismatchException();
        }
    }

    private function handleTransaction(Request $request)  // $request を引数として受け取る
    {
        // トランザクション開始
        DB::beginTransaction();

        try {
            // クエリ実行
            $result = DB::table('some_table')->get();

            // Eloquentモデルの保存
            $model = new MyModel;
            $model->some_field = $request->input('value');  // $request を使う
            $model->save();

            // トランザクションコミット
            DB::commit();

        } catch (Exception $e) {
            // トランザクションロールバック
            DB::rollback();
            throw $e;  // 例外を再スロー
        }
    }
}


```


例外ファイル
App\Exceptions
```php
// FileExtensionException.php
namespace App\Exceptions;

use Exception;

class FileExtensionException extends Exception
{
    // 任意で追加のコード
}

// CsvColumnMismatchException.php
namespace App\Exceptions;

use Exception;

class CsvColumnMismatchException extends Exception
{
    // 任意で追加のコード
}
```

### 記載内容
Laravelを使用している。
csvファイルをアップしたのをテーブルに保存し、前画面に戻る例を挙げている。
エラーとして起こりうることとして色々あると思うが、何が起こるかを記載する。
今回は、エラーとして、ファイル拡張子、CSVファイルカラムのヘッダー確認を行なっている。
他に、ファイルの存在とアップロード確認、ファイルサイズ、csvのデータ行に対する検証等があるが、今回は割愛している。

要は何をエラーにするかを決めることである。

### 記載方法
1.本処理を書く。
ここではcsvアップとDB書き込みである。
必要に応じてメソッド化する(今回はメソッド化している)。

2.エラー処理をcatchで対応する。
既に存在する例外クラス、独自例外クラスは作成する。
ここが厄介なところかもしれない。

今回は以下既に存在する例外クラスを使用している。
useに記載する。
```php
use Illuminate\Database\QueryException;
use PDOException;
use Exception;
```
これらの例外クラスは既に存在するので、useで記載する。
PDOExceptionは、PHPのPDO（PHP Data Objects）拡張で発生する可能性のあるエラーを表し、PHPの標準ライブラリに含まれています。
QueryExceptionは、LaravelのデータベースクエリビルダやEloquent ORMでデータベースクエリに関するエラーが発生した際に投げられる例外で、Laravelフレームワークに含まれる。

3.エラー処理作成
既存例外クラスは2で行う。
独自の例外クラスは、throw new クラス名()として対応。
そのクラスをApp¥Exceptionでフォルダを作成し、クラスを作成する。
今回はエラー状態を捕捉したいだけなので、例外クラスは空で構わない。
特定のエラー状態をプログラムが認識できるようになる。

### その他
catch (Exception $e) で一般的なエラーをキャッチしているが、ここではエラーのロギングも行うといい。これによって、後でエラーを解析る。

## おわりに
しばらくこれで様子を見る。
とりあえず例外を気にしない記載は控えていきたい。