Laravel9で登録、編集時に確認画面と完了画面を表示する

Laravel9で登録、編集時に確認画面と完了画面を表示する Laravel

Laravel9でCRUDを実装する記事を書きました。

登録時は以下のような画面遷移にしています。

一覧画面→入力画面→一覧画面(登録完了したデータを表示)

編集時も同様で、以下のような流れです。

一覧画面→編集画面→一覧画面(更新完了したデータを表示)

CRUDを実装するという意味では、上記が必要最低限かなというところですが、実際の業務では、入力内容を確認する画面があったり、処理が完了した旨を表示する画面があったりすることが多いです。
具体的には以下のような流れです。

一覧画面→入力画面→確認画面→完了画面→一覧画面

今回は、上記の流れになるように確認画面と完了画面を追加してみます。

環境

以下の環境で実装しています。
2023年1月に実装した時点の情報になります。

  • PHP:8.1.14
  • Laravel:9.46.0

新規登録時に確認画面を表示する

まず、新規登録時に確認画面を表示する処理を追加します。
新規登録時に、以下のように入力項目と「入力内容を確認する」ボタンを用意しました。

入力画面

ルーティングは以下のようにしました。

Route::controller(ShopsController::class)->name('shops.')->group(function() {
    Route::post('shops/confirm', 'confirm')->name('confirm');
});

「入力内容を確認する」ボタンをクリックした時に、上記のルーティングへ post します。

<form method="post" action="{{ route('shops.confirm') }}" class="mt-6 space-y-6">
    @csrf
    <div>
        <x-input-label for="name" value="名前" />
        <x-text-input id="name" name="name" type="text" class="mt-1 block w-full" :value="old('name')" required autofocus />
        <x-input-error class="mt-2" :messages="$errors->get('name')" />
    </div>
    <div>
        <x-input-label for="address" value="住所" />
        <x-text-input id="address" name="address" type="text" class="mt-1 block w-full" :value="old('address')" required />
        <x-input-error class="mt-2" :messages="$errors->get('address')" />
    </div>
    <div class="flex items-center gap-4">
        <x-primary-button>入力内容を確認する</x-primary-button>
    </div>
</form>

コントローラーは以下のようにしました。
リクエスト内容をそのまま確認画面のビューへ渡しています。

public function confirm(ShopRequest $request)
{
    return view('shops.confirm', [
        'inputs' => $request->all(),
    ]);
}

確認画面は以下のように、入力内容を表示します。

確認画面

確認画面のビューは以下のようにしました。

<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Shops') }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <form method="post" action="{{ route('shops.store') }}" class="mt-6 space-y-6">
                @csrf
                <input type="hidden" name="name" value="{{ $inputs['name'] }}">
                <input type="hidden" name="address" value="{{ $inputs['address'] }}">

                <div class="overflow-hidden bg-white shadow sm:rounded-lg">
                    <div class="border-t">
                        <dl>
                            <div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                                <dt class="text-sm font-medium">名前</dt>
                                <dd class="mt-1 text-sm sm:col-span-2 sm:mt-0">{{ $inputs['name'] }}</dd>
                            </div>
                            <div class="bg-gray-50 px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
                                <dt class="text-sm font-medium">住所</dt>
                                <dd class="mt-1 text-sm sm:col-span-2 sm:mt-0">{{ $inputs['address'] }}</dd>
                            </div>
                        </dl>
                    </div>
                </div>
                <div class="mt-4">
                    <x-primary-button name="back">修正する</x-primary-button>
                    <x-primary-button>この内容で登録する</x-primary-button>
                </div>
            </form>
        </div>
    </div>
</x-app-layout>

確認画面から入力画面に戻る

入力内容を修正したい場合に、前の画面(入力画面)に戻るボタンを用意します。
「修正する」ボタンをクリックした場合は、以下のように対象のルーティングへ submit します。
この時、「登録する」ボタンと「修正する」ボタンを判別するために、「name=”back”」を付与しています。

<form method="post" action="{{ route('shops.store') }}" class="mt-6 space-y-6">
    (中略)
    <x-primary-button name="back">修正する</x-primary-button>
    (中略)
</form>
Route::controller(ShopsController::class)->name('shops.')->group(function() {
    Route::post('shops/complete', 'store')->name('store');
});

コントローラーは以下のようにしました。
「修正する」ボタンをクリックした場合は、リクエストに「back」という文字列が含まれるので、入力内容を引き継いで、入力画面にリダイレクトしています。

public function store(ShopRequest $request)
{
    if ($request->has('back')) {
        return Redirect::route('shops.create')->withInput($request->all());
    }
    (中略)
}

新規登録時に完了画面を表示する

確認画面で「この内容で登録する」ボタンをクリックすることで、登録を行い、完了画面を表示するようにします。

確認画面
<form method="post" action="{{ route('shops.store') }}" class="mt-6 space-y-6">
    (中略)
    <x-primary-button>この内容で登録する</x-primary-button>
    (中略)
</form>

コントローラーは上記の「修正する」ボタンと同様のものです。
上記の戻る処理の判定後、登録を行い、完了画面を表示します。

public function store(ShopRequest $request)
{
    if ($request->has('back')) {
        return Redirect::route('shops.create')->withInput($request->all());
    }

    Shop::create($request->all());
    return view('shops.complete')->with('status', 'shops-stored');
}

ビューは以下のようにしました。

完了画面
<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
            {{ __('Shops') }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="overflow-hidden bg-white shadow sm:rounded-lg">
                <div class="px-4 py-5 sm:px-6">
                    @if ($status == 'shops-stored')
                    <p class="max-w-2xl text-sm text-gray-500">新規登録が完了しました。</p>
                    @endif
                </div>
            </div>
            <div class="mt-4">
                <a href="{{ route('shops.index') }}" class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white tracking-widest hover:bg-gray-700">戻る</a>
            </div>
        </div>
    </div>
</x-app-layout>

編集時に確認画面を表示する

続いて、編集時に確認画面を表示する処理を追加します。
画面のレイアウトは新規登録時と同様です。

編集時の入力画面

編集時のルーティングは、モデルの暗黙の結合を含むため、新規登録時とは分けて、以下のようにしました。

Route::controller(ShopsController::class)->name('shops.')->group(function() {
    Route::post('shops/{shop}/edit-confirm', 'updateConfirm')->name('update_confirm');
});

コントローラーは以下のようにしました。
編集時は引数にモデルを含むので、リクエスト内容に加え、モデルも確認画面のビューへ渡しています。

public function updateConfirm(ShopRequest $request, Shop $shop)
{
    return view('shops.confirm', [
        'shop' => $shop,
        'inputs' => $request->all(),
    ]);
}

確認画面は以下のように、入力内容を表示します。
新規登録時とはボタンの文言が異なっています。

編集時の確認画面

確認画面のビューは以下のようにしました。
新規登録時とファイルは同一で、変更点が3点あります。

1つ目は、確認画面→完了画面遷移時の submit 先を、新規登録 or 編集で分けています。

<form method="post" action="{{ !isset($shop) ? route('shops.store') : route('shops.update', $shop->id) }}" class="mt-6 space-y-6">
Route::controller(ShopsController::class)->name('shops.')->group(function() {
    Route::post('shops/complete', 'store')->name('store');
    Route::put('shops/{shop}/edit-complete', 'update')->name('update'); // 追加
});

2つ目は、編集時は put で submit するようにしています。

@csrf
@isset($shop)      // 追加
    @method('PUT') // 追加
@endisset          // 追加
<input type="hidden" name="name" value="{{ $inputs['name'] }}">
<input type="hidden" name="address" value="{{ $inputs['address'] }}">

3つ目は、新規登録 or 編集でボタンの文言を変えています。

<x-primary-button>{{ !isset($shop) ? 'この内容で登録する' : 'この内容で更新する' }}</x-primary-button>

編集時に完了画面を表示する

コントローラーは以下のようにしました。
構成は新規登録時と同様です。

public function update(ShopRequest $request, Shop $shop)
{
    if ($request->has('back')) {
        return Redirect::route('shops.edit', $shop)->withInput($request->all());
    }

    $shop->update($request->all());
    return view('shops.complete')->with('status', 'shops-updated');
}

完了画面は、表示するメッセージが異なります。

編集時の完了画面
@if ($status == 'shops-stored')
<p class="max-w-2xl text-sm text-gray-500">新規登録が完了しました。</p>
@elseif ($status == 'shops-updated')                             // 追加
<p class="max-w-2xl text-sm text-gray-500">更新が完了しました。</p> // 追加
@endif
タイトルとURLをコピーしました