0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Laravel】バリデーションとクエリ実行を別のルートに分ける

0
Posted at

CG

ルート
Route::post('/product/validate', [ProductController::class, 'validateStore']);
Route::post('/product/store', [ProductController::class, 'store']);
コントローラー
public function validateStore(Request $request)
{
    $validated = $request->validate([
        'item_cd' => 'required',
        'name' => 'required',
    ]);

    return back()
        ->withInput()
        ->with('confirm', true);
}
with('confirm', true)

セッションにフラグを保存
Laravelの with() 次の画面描画時だけ使える一時変数

blade
@if(session('confirm'))
<script>
document.addEventListener('DOMContentLoaded', function() {

    const modal =
        new bootstrap.Modal(
            document.getElementById('confirmModal')
        );

    modal.show();

});
</script>
@endif
<form method="POST"
      action="{{ route('product.store') }}">

    @csrf

    <input type="hidden"
           name="item_cd"
           value="{{ old('item_cd') }}">

    <input type="hidden"
           name="name"
           value="{{ old('name') }}">

    <button type="submit">
        OK
    </button>

</form>

with()の正体

return view('product')
    ->with('name', 'コーラ');
blade
{{ $name }}

これは、View変数を渡している。

しかし今回のこれは違う。

redirect時のwith()
return back()
    ->with('confirm', true);

back() は RedirectResponse を返します。

ここでの with() は、セッションに一時保存。

これが超重要。


CD

初学者がつまずくポイント① — HTTPはステートレス

// routes/web.php

// バリデーション専用ルート(DBには保存しない)
Route::post('/products/validate', [ProductController::class, 'validateOnly'])
    ->name('products.validateOnly');

// 実際の保存ルート(バリデーション済みが前提)
Route::post('/products/store', [ProductController::class, 'store'])
    ->name('products.store');
// app/Http/Controllers/ProductController.php

class ProductController extends Controller
{
    /**
     * ステップ1: バリデーションだけ行い、データをセッションに保存してViewへ戻す
     */
    public function validateOnly(Request $request)
    {
        // バリデーション(失敗すると自動で入力ダイアログに戻る)
        $validated = $request->validate([
            'name'  => 'required|string|max:100',
            'price' => 'required|integer|min:0',
            // 他のフィールドも追加してください
        ]);

        // ⚠️ つまずきポイント③ で後述
        // バリデーション済みデータをセッションに「一時保存」する
        session(['product_confirm' => $validated]);

        // 確認モーダルを表示するページ(またはダイアログ元のページ)へリダイレクト
        return redirect()->route('products.create')
            ->with('show_confirm_modal', true); // モーダル表示フラグも一緒に渡す
    }

    /**
     * ステップ2: セッションからデータを取り出してDBに保存
     */
    public function store(Request $request)
    {
        // セッションからバリデーション済みデータを取得
        $data = session('product_confirm');

        // セッションにデータがない場合(直接アクセスなど)は弾く
        if (!$data) {
            return redirect()->route('products.create')
                ->with('error', '不正なアクセスです。もう一度入力してください。');
        }

        // DBに保存
        Product::create($data);

        // セッションから確認データを削除(使い終わったので)
        session()->forget('product_confirm');

        return redirect()->route('products.index')
            ->with('success', '登録が完了しました');
    }
}

方法保持期間主な用途

方法 保持期間 主な用途
session(['key' => $value]) 明示的に削除するまで残る データの一時保存
->with('key', $value) 次の1リクエストだけ(フラッシュデータ) 成功メッセージ、フラグの受け渡し
blade
{{-- resources/views/products/create.blade.php --}}

{{-- 入力ダイアログ(フォーム) --}}
<form action="{{ route('products.validateOnly') }}" method="POST">
    @csrf
    <input type="text"   name="name"  value="{{ old('name') }}">
    <input type="number" name="price" value="{{ old('price') }}">
    
    {{-- バリデーションエラーの表示 --}}
    @error('name')
        <p class="error">{{ $message }}</p>
    @enderror

    <button type="submit">登録</button>
</form>


{{-- 確認モーダル --}}
{{-- ⚠️ つまずきポイント④ で後述 --}}
@if(session('show_confirm_modal'))
    <div id="confirmModal" style="display: block;">
        <p>以下の内容で登録しますか?</p>
        
        {{-- セッションに保存したデータを表示 --}}
        <p>商品名: {{ session('product_confirm.name') }}</p>
        <p>価格: {{ session('product_confirm.price') }}</p>

        {{-- OKボタン → storeルートへPOST --}}
        <form action="{{ route('products.store') }}" method="POST">
            @csrf
            <button type="submit">OK</button>
        </form>

        {{-- キャンセルボタン → モーダルを閉じるだけ(JS) --}}
        <button onclick="closeModal()">キャンセル</button>
    </div>
@endif

<script>
function closeModal() {
    document.getElementById('confirmModal').style.display = 'none';
}
</script>
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?