ビューの共通部分とは
ビューの共通部分とは、例えば、HTMLの共通の部分や、ヘッダー、フッターなどがあります。今まで作ってきたビューの一部をもう一度見てみましょう。show-booksとshow-detail-bookを見比べてみます。
show-books
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Books一覧</title>
</head>
<body>
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>詳細</th>
<th>更新</th>
<th>削除</th>
</tr>
@foreach ($books as $book)
<tr>
<td>{{ $book->id }}</td>
<td>{{ $book->title }}</td>
<td><a href="{{ route('books.detail', $book) }}">詳細</a></td>
<td><a href="{{ route('books.edit', $book) }}">更新</a></td>
<td>
<form action="{{ route('books.destroy', $book) }}" method="POST">
@csrf
@method("DELETE")
<button type="submit">削除</button>
</form>
</td>
</tr>
@endforeach
</table>
<a href="{{ route('books.create') }}">新規作成</a>
</body>
</html>
show-detail-book
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Books一覧</title>
</head>
<body>
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>Author</th>
<th>Price</th>
</tr>
<tr>
<td>{{ $book->id }}</td>
<td>{{ $book->title }}</td>
<td>{{ $book->author }}</td>
<td>{{ $book->price }}</td>
</tr>
</table>
<a href="{{ route('books.show') }}">一覧に戻る</a>
</body>
</html>
上記では、以下のような部分が共通しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>タイトル</title>
</head>
<body>
</body>
</html>
bodyの中は異なりますがそれ以外はほぼ共通です。titleも異なりますが、ここではtitleも共通とみなします。特にheadのmeta部分はすべてのページで共通となり、設定できる項目も豊富なため、各ビューごとに同じ内容を記述するのは非効率です。そこで、Laravelではコンポーネントというシステムで共通化を図っています。
Laravelのコンポーネント
コンポーネントにはクラスベースのコンポーネントと無名コンポーネントがあります。ここでは、クラスベースのコンポーネントを作成します。以下のコマンドを使用してコンポーネントのひな型を作成します。コンポーネント名はBookBaseとします。
php artisan make:component BookBase
上記を実行すると、app/View/Components/BookBase.phpとresources/views/components/book-base.blade.phpが作成されます。まずは、BookBase.phpを編集します。ここでは、共通化する部分のうち、titleタグに挿入するデータを受け渡しできるように設定します。
<?php
namespace App\View\Components;
use Closure;
use Illuminate\Contracts\View\View;
use Illuminate\View\Component;
class BookBase extends Component
{
/**
* Create a new component instance.
*/
public $title;
public function __construct($title)
{
$this->title = $title;
}
/**
* Get the view / contents that represent the component.
*/
public function render(): View|Closure|string
{
return view('components.book-base');
}
}
クラスのパブリックプロパティにtitle変数を追加し、コンストラクターでtitle変数の初期化を行います。次に、book-base.blade.phpを編集します。以下のように編集し、外部からtitleタグの内容を受け取れるようにし、headのmetaデータは一括してこのファイルに記述するようにします。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title }}</title>
</head>
<body>
<h1>MyBooks</h1>
{{ $slot }}
</body>
</html>
titleはコンポーネント呼び出し時に指定できるようにします。slotは共通化できない部分を埋め込むために設定しています。また、変化がわかるように共通部分としてページの先頭にh1タグでMyBooksと表示するように設定しています。次に、共通化したい各ビューを以下のように変更します。共通化したところを取り除き、x-book-baseタグで囲うだけです。
<x-book-base title="Books一覧">
<table>
<tr>
<th>ID</th>
<th>Title</th>
<th>詳細</th>
<th>更新</th>
<th>削除</th>
</tr>
@foreach ($books as $book)
<tr>
<td>{{ $book->id }}</td>
<td>{{ $book->title }}</td>
<td><a href="{{ route('books.detail', $book) }}">詳細</a></td>
<td><a href="{{ route('books.edit', $book) }}">更新</a></td>
<td>
<form action="{{ route('books.destroy', $book) }}" method="POST">
@csrf
@method("DELETE")
<button type="submit">削除</button>
</form>
</td>
</tr>
@endforeach
</table>
<a href="{{ route('books.create') }}">新規作成</a>
</x-book-base>
x-book-baseのtitle属性は、book-base.blade.phpのtitleに引き渡されます。http://localhost/books/showにアクセスして画面が正常に表示されれば成功です。
これで、ビューの共通化に成功しました。ヘッダーやフッターも共通化できるので、できれば試してみてください。
次:ミドルウェア