データや処理が複雑かつやり直しを避けたい場合、処理結果のプレビュー機能の実装が望まれます。この機能は画像やデザインを文字列で定義できる記事投稿システムなどの入力画面と閲覧画面の差異が大きいシステムでよく実装が望まれます。例えば変な内容のブログ記事を公開してしまうことを避けるために公開前にプレビュー機能であらかじめブログ記事を見ることができるようにしたい、といった具合です。この記事では Laravel のトランザクション機能を利用してプレビュー機能を簡易に作る方法を紹介します。
データベースのトランザクションは複数の操作を一つの操作として扱う機能です。トランザクションが開始されると、その中で行われる全てのデータ操作は一時的にデータベースに記録されますが、トランザクションがコミットされるまでは他の操作からは見えません。そして、何らかの問題が発生した場合には、トランザクションをロールバックすることで、トランザクション開始前の状態に戻すことができます。ここで重要なのはコミット前まで処理を進めた後にトランザクション前まで戻すことができるという点です。この点を利用すると次のフローでプレビュー用のデータを用意し、プログラム内で扱えます。
1. トランザクション開始
2. 実際の保存機能実行
3. 保存結果を閲覧用のデータとして取得
4. ロールバックでデータベースへの保存を確定しない
5. 取得済みの閲覧用形式の保存結果を用いてプレビュー画面を表示
おおまかなプレビュー機能の実装例が次です。
<?php class PreviewController { /** * @param SaveRequest $request フォームリクエスト。Laravelの機能でバリデーションをコントローラーに来る前に行うリクエスト * @param SaveAction $saveAction 保存処理。別で作ったクラスのインスタンス。__invokeメソッドに処理本体があるクラス * @param ShowAction $showAction 閲覧処理。別で作ったクラスのインスタンス。__invokeメソッドに処理本体があるクラス * @return \Illuminate\Contracts\View\View * @throws Throwable */ public function __invoke(SaveRequest $request, SaveAction $saveAction, ShowAction $showAction): \Illuminate\Contracts\View\View { // トランザクション開始 DB::beginTransaction(); // 別で作った保存処理を呼び出す $savedModel = $saveAction($request); // 保存した対象を閲覧処理から呼び出す $result = $showAction($savedModel->getKey()); // ロールバックで保存をなかったことにする DB::rollBack(); // プレビュー結果を表示 return view('preview', ['result' => $result]);; } }
こんな感じにするとプレビュー機能とは別に作る必要のある保存機能と閲覧機能を再利用してプレビュー機能を比較的容易に作れます。