見出し画像

一覧機能 #WebアプリケーショのUIパターン #Laravelの教科書

この記事はWebアプリケーションのUIパターンについて解説しています。その他のUIパターンについてはこちらのマガジンからどうぞ。


# はじめに

UIがパターンの一つ、一覧・検索のパターンについて解説します。

前提として作成パターンが必要となります。作成パターンについて書かれた記事はこちらです。


モデルについては新規に作成せずに、作成パターンで作成した「レシピ情報モデル(Recipe)」を利用します。

app/Models/Recipe.php

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Recipe extends Model
{
	use HasFactory;
	
	protected $table = "user_recipe";
	
	protected $fillable = ['name', 'url', 'description', 'user_id'];
}


本稿では作成機能で登録されたレシピの一覧機能を実装しながら一覧のパターンについて解説を行います。

別記事でも説明していますが、Laravelの機能は次の流れで開発を行います。

1. 作成機能のControllerの作成
2. 作成機能のViewの作成
3. ルーティングの設定


# 一覧・検索パターン

一覧画面は「登録したデータが新着順に並ぶ」という機能でほとんどのWebアプリケーションで登場するデータです。

WordPressの記事一覧

スクリーンショット 2020-09-24 0.04.48

記事一覧の画面は新規作成の誘導や検索のためのフォームなど、他の機能の入り口として使われることが多いです。

検索についてはナビゲーションメニューに検索フォームがあるだけでなく、一覧画面に「タグ」や「カテゴリー」のリンクなどが用意されている場合があります。

一覧と検索、一見全く異なる2つの機能を同一のパターンとしている理由は、どちらの場合でもControllerの処理は共通しているからです。

・データーベースからデータを取り出す
・ページャーで何件か毎に表示する
・Viewで取り出したデータを表示する

一覧のパターン、検索のパターン、どちらもこの3個の処理を実装することになります。

検索パターンは上記に加え、View側で検索フォームを作成したり、検索フォームの値の受け取り、受け取った値からDBを検索するなどの処理が追加されます。そのため「一覧機能→検索機能」の順で開発することをおすすめします。


それは、レシピ一覧の機能を実際に作りながら作成手順とポイントを解説していきます。


# 設計

一覧機能は次のような設計で作成します。

■ 一覧機能
URL: /recipe
・レシピ検索フォームとレシピ一覧が表示される
・レシピ一覧は新着順に10件表示


# Controlelerの作成

レシピ一覧機能のためのControllerを作成していきます。

パターンに限らず、Controllerは次のことを開発前に決める必要があります。

・クラス名
・関数名


一覧、検索のパターンは一つのControllerで行うこともありますが、Controllerは出来る限り小さく作ることを推奨されています。

そのため「一覧」「検索」でそれぞれControllerを作成します。

今回は次のように定めました。

■ 一覧
・クラス名 = RecipeListController
・関数名
 ・画面表示 = show
■ 検索
・クラス名 = SearchRecipeController
・関数名
 ・検索 = search


今回はmake:controllerコマンドを使って「RecipeListController」を作成します。

php artisan make:controller RecipeListController


# 一覧機能: Controllerの作成

作成したRecipeListController.phpを編集していきます。

app/Http/Controllers/RecipeListController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
/* 必要なモデルをuseする */
use App\Models\Recipe;
class RecipeListController extends Controller
{
	
	function __construct(){
		$this->middleware('auth');
	}
	function show(Request $request){
		//自分が登録したレシピを取り出す
		$recipe_list = Recipe::where("user_id","=",\Auth::id())
			//並び順を新しい順にする
			->orderBy("id","desc")
			//10件毎にページングする
			->paginate(10);
		//View:recipe.recipe_listを表示する
		return view("recipe.recipe_list",[
			"recipe_list" => $recipe_list
		]);
	}
}

前述した通り、一覧パターンのControllerの役割はこの3つです。

・データーベースからデータを取り出す
・Viewで取り出したデータを表示する
・ページャーで何件か毎に表示する


このうち、データの取り出しページャーについてはModelの機能を使って実現します。

//自分が登録したレシピを取り出す
$recipe_list = Recipe::where("user_id","=",\Auth::id())
	
//並び順を新しい順にする
->orderBy("id","desc")
	
//10件毎にページングする
->paginate(10);

Controllerはデータを取得し、取得したデータをそのままViewに渡すのが役割となります。


また、認証が必要な画面なのでコンストラクタで指定してあります。

$this->middleware('auth');


# 一覧機能: Viewの作成

Viewのポイントは2点あります。

・Controllerから渡されたデータを@foreach〜@endforeachでループしながら表示すること
・ページングを表示するため「{{ $xxx->links() }}」を表示すること


Viewの全体は下記のような形となります。

resources/views/recipe/recipe_list.blade.php

<x-app-layout>
   <x-slot name="header">
       <h2 class="font-semibold text-xl text-gray-800 leading-tight">
           レシピ一覧
       </h2>
   </x-slot>
	<div class="py-12">
		<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
			<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
				@if (session('status'))
				<div class="success mt-5 px-4 text-green-900">
					{{ session('status') }}
				</div>
				@endif
				<!-- ページ固有要素 -->
				<div class="mt-5 px-4 py-5">
                    
                    @include("recipe.recipe_search_form")

					<table class="w-full border shadow my-6">
						<thead>
							<tr class="py-3">
								<th class="px-3 py-3 text-center border">ID</th>
								<th class="px-3 py-3 text-center border">レシピ名</th>
								<th class="px-3 py-3 text-center border">作成日</th>
								<th class="px-3 py-3 text-center border">更新日</th>
								<th class="px-3 py-3 text-center border">詳細</th>
							</tr>
						</thead>
						<tbody>
						@foreach($recipe_list as $recipe)
						<tr>
							<td class="px-3 py-3 border">{{ $recipe->id }}</td>
							<td class="px-3 py-3 border">{{ $recipe->name }}</td>
							<td class="px-3 py-3 border">{{ $recipe->created_at->format("Y-m-d H:i:s") }}</td>
							<td class="px-3 py-3 border">{{ $recipe->updated_at->format("Y-m-d H:i:s") }}</td>
							<td class="px-3 py-3 border">
								<a href="#">詳細</a>
							</td>
						</tr>
						@endforeach
						</tbody>
					</table>
					{{ $recipe_list->links() }}
				</div>
				<!-- /ページ固有要素 ここまで -->
			</div>
		</div>
	</div>
</x-app-layout>


検索フォームは部品化しておくことで検索のパターンと共有化することができます。

@include("recipe.recipe_search_form")


resources/views/recipe/recipe_search_form.blade.php

<form class="w-full">
	<div class="flex flex-wrap">
		<div class="w-2/3">
			<input class="appearance-none border-2 border-gray-200 rounded w-full py-2 px-4" type="text" value="" placeholder="レシピ名で検索">
		</div>
		<div class="w-1/3 px-6">
			<button class="shadow bg-blue-500 text-white font-bold py-2 px-4 rounded" type="button">
				検索
			</button>
		</div>
	</div>
</form>


Controllerから渡されたデータを@foreach〜@endforeachでループしながら表示する部分はこちらです。

@foreach($recipe_list as $recipe)
<tr>
	<td class="px-3 py-3 border">{{ $recipe->id }}</td>
	<td class="px-3 py-3 border">{{ $recipe->name }}</td>
	<td class="px-3 py-3 border">{{ $recipe->created_at->format("Y-m-d H:i:s") }}</td>
	<td class="px-3 py-3 border">{{ $recipe->updated_at->format("Y-m-d H:i:s") }}</td>
	<td class="px-3 py-3 border">
		<a href="#" class="bg-blue-500 text-white font-bold py-2 px-4 rounded">詳細</a>
	</td>
</tr>
@endforeach

詳細のリンクは「詳細・編集」パターンを実装した後に次のように設定します。

<a href="{{ route('recipe_detail', ['id' => $recipe->id]) }}" 
class="...">詳細</a>

route()関数は名前をつけたルーティングを利用できるメリットがありますが、設定する前に「route()」を使うとエラーになるため、設定は実装後に行います。


ページングの表示部分は次のように書きます。

{{ $recipe_list->links() }}


各要素のclassに指定しているのはTailwindCSSの機能です。よく使うものだけ覚えておくCSSを書く必要なくこのようにクラス名の指定だけで画面を整えることができます。

・w-full…幅100%にする
・border…ボーダーを表示する
・shadow…影を表示する
・my-数値…上下のマージンを指定
・px-数値…左右のパディングを指定
・py-数値…上下のパディングを指定
・bg-blue-500...背景を青色にする
・text-white…テキストを白にする
・font-bold…太字にする
・rounde…角丸にする


# 一覧機能:ルーティング

一覧機能のルーティングを設定します。

routes/web.php

Route::get('/recipe', 
    [App\Http\Controllers\RecipeListController::class, "show"])
->name("recipe_list");



# 動作確認

ブラウザで「http://localhost:8000/recipe」を開いてレシピ一覧を確認します。

スクリーンショット 2020-09-24 0.00.35

ページングの表示の確認は10件以上のレシピを登録する必要があります。

少ない件数でも確認したい場合は「paginate(3)」のように件数を減らして表示を確認しましょう。


# まとめ

一覧・検索パターンの要点をまとめます。

・モデルは検索パターンで作ったものを利用出来る
・一覧→検索の順に作成する
・Controllerは「データの取出し」「ページング」「Viewにデータを渡す」処理だけで良い
・Viewは「@foreach〜@endforeachでデータ一覧を表示」「検索フォームを部品化して読み込む」
・ルーティングは「一覧画面」の指定を行う

検索についてはデータの取出しが少し難易度が上がります。こちらは別の記事で詳しく解説します。

一覧のパターンは取り出すモデルのクラスを変えるだけでほぼそのまま機能をコピーすることができます。

また、一覧画面は他の機能へのハブとなることが多いため作成機能の次に作ると良いでしょう。




完成まで突っ走る意気込みです。サポートしていただけると非常に嬉しいです。応援よろしくお願いします。