未経験からエンジニア転職をするための最強ロードマップロードマップ

【Laravel教材③】Laravelでブログシステム構築!〜MVCモデル解説から画面の共通化編〜

ファド

こんにちは!
PHPのLaravelやJavaScriptでWeb開発をしているフリラーンスエンジニアのファドと申します!

こちらの記事はLaravel教材の第3回目の記事になります。

その他のLaravel教材を学習したい方は下記リンクから直接教材へ飛ぶことができます。

目次

MVCモデル

これからの学習をよりわかりやすくするためにMVCモデルというアプリケーションを作成する際のデザインパターンについて説明していきます。

MVCモデルとはアプリケーション開発で採用されるコードの構成手法です。
ユーザーに対する入出力処理とシステムの内部処理を分離することを目的としており、システムの機能を3つの役割に分けて開発を行っていきます。

モデル(Model)

1つ目はモデルです。
主にアプリケーションのデータに対する操作を担います。
データベースへデータ登録する処理やデータ取得の処理を記述することが理想です。

ビュー(View)

2つ目はビューです。
主にユーザーに対する入出力処理を担います。
実際にユーザーが見る画面がこのViewです。

コントローラー(Controller)

そして最後はコントローラーです。
主にModelViewの橋渡しを担います。
ビューを表示させる処理やデータをモデルからビューへ渡す処理など幅広い処理を記述することができます。

3つの関連性

これら3つの頭文字をとりMVCモデルと呼ばれています。
LaravelではMVCモデルが採用されており「どのディレクトリにM・V・Cを格納するのか」がざっくり決まっています。
また、LaraveだけではなくRubyのフレームワークであるRuby on Railsなどでも採用されており、その他にもたくさんのフレームワークがMVCモデルを採用しています。

そんな汎用性の高いMVCモデルですが、それぞれ3つの関連性をわかりやすくするために図を使って説明していきます。

上の図を見てください。
MVCモデルの場合、クライアントからアクセスが来るとアクセスの処理をControllerへ割り振ります。
データの取得や変更などを行う場合は、ControllerからModelに移動してデータの処理を行います。
Modelではデータベースとの接続ができるので、受け取ったデータを処理した後にControllerへデータを渡します。
その後ControllerからViewへデータを受け渡し、Viewでサイトの表示を行うという流れになっています。

流れを確認しただけですべてを理解することはできないので、それぞれのModelViewControllerについて学習しながら、少しずつ理解していきましょう!

今の段階では、「Laravelはサイトを表示するための役割を3つに分けて実装していくのだな」というイメージを持っておいていただければOKです。

★検索ワード
・フレームワーク MVCとは
・Laravel MVC

モデルについて

それではさっそくMVCの中のモデル(Model)について学習していきます。
先ほども説明した通り、モデルはデータベースへのアクセスやデータ操作などの役割を担います。

Laravelでは、モデルを簡単に実装するための仕組みが用意されているのでさっそく使ってみましょう。

モデルファイルの作成

モデルファイルもマイグレーションファイルやシーダーファイルのように、Artisanコマンドを使用して作成することができます。
Artisanコマンドとは、php artisan ~~~~~~のコマンドのことです。

コマンドは以下の通りです。

$ ./vendor/bin/sail php artisan make:model クラス名

基本クラス名はモデルを使用して操作したいテーブル名の単数形を使用します。
そのため、articlesテーブルのデータを取得したりするモデルファイルを作成する場合のモデル名はArticleとなります。

それではarticlesテーブルのモデルファイルを作成するので、ターミナルで下記コマンドをfirst-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan make:model Article

Model created successfully.と出力されればモデルファイルの作成は完了です。
first-app/app/Models配下にArticle.phpが作成されていればOKです。

Laravelのモデルは、Eloquentモデルとも言うことができます。
EloquentとはLaravelで提供されているデータ操作のための機能であり、モデルとデータベースを紐付ける役割をしています。

それでは作成したArticle.phpを確認してみましょう。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasFactory;
}

ファイルの中にはModelクラスを継承したArticleクラスが作成されています。
ModelクラスはLaravelが初期機能として持っているクラスであり、このクラスを継承しているため、Articleクラスはモデルとしての機能を発揮することができます。

また、作成したArticleクラスとLaravelに接続しているデータベースのarticlesテーブルが、Laravelによって自動的に紐づけられます。
よって、Articleクラスを操作することで簡単にテーブルの操作を行うことができます。

Article.phpの中のArticleクラスと、データベースのarticlesテーブルで名前が単数形と複数形で異なることに注意してください。
Eloquentでは、モデルのクラス名を複数形にしてアッパーキャメルケースだったものをスネークケースにしたものが、紐づけ先のテーブルとして自動的に認識されます。
少し難しい言葉が並んでいますが、例は下記の通りです。
※アッパーキャメルケース例:OpenHoursのように先頭の文字と単語の区切り文字を大文字している名前
※スネークケース例:open_hoursのようにアンダースコア(アンダーバー)で区切られている名前

例えば「admin_statuses」というテーブルに紐づけたい場合のクラス名は、下記のようになります。
①単数形にする(admin_statuses->admin_status)
②アッパーキャメルケースにする(admin_status->AdminStatus)
つまり、php artisan make:model AdminStatusというコマンドになります。
今回は、articlesテーブルに紐づけたいので、Articleというファイル名にしてあります。
※モデルのクラス名に拡張子が付いたものがモデルのファイル名になります。

モデルの記述

モデルファイルはほとんど中身を変更せずに使用することができますが、追加しておいた方がいいこともあります。

まずは、下記の通りfirst-app/app/Models/Article.phpを編集してください。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasFactory;

    // テーブル名
    protected $table = 'articles';

    // 可変項目
    protected $fillable = [
        'title',
        'content',
    ];
}

まず追加したのは下記のコードです。
protected $table = 'articles';
先ほど説明した通り、モデルファイルはテーブル名の単数形であり、アッパーキャメルケースであれば、自動的にテーブルとモデルが紐付けられますが、protected $tableを使用することで任意のテーブル名を指定することもできます。

もしモデルクラス名とテーブル名が全く違う場合などはこのように記述してください。
今回のコードであれば、記述しなくても自動的にモデルファイルとテーブルは結びついていますが、解説のためにこちらも記述しております。

次に追加したのが下記のコードです。

// 可変項目
protected $fillable = [
    'title',
    'content',
];

こちらのコードはコントローラーなどでデータベースに登録する際に使用するcreateメソッドを使うために記述します。
createメソッドを使用しない場合は必要ありませんが、将来的に使用するので初めに記述しておきましょう。

まずはprotected $fillable = []と記述し、[]の中にはテーブルの可変項目のカラム名を記述していきます。
今回はarticlesテーブルの2つのカラムtitlecontentは、各レコードによって入れたい値が可変になるので[]に記述しています。

基本$fillableにはidカラムcreated_atカラムupdated_atカラム以外のカラムを入れておけばOKです。
状況に応じてidカラムcreated_atカラムupdated_atカラムなども入れておきましょう。

これでモデルファイルの作成は終わりです。
モデルを学習しただけだと全体像が掴めないと思うので、次に進んでみましょう。

★検索ワード
・Laravel モデル作成
・Laravel Eloquent
・Laravel fillable guarded
・Laravel モデル テーブル名指定

ルート(Route)について

LaravelにはMVCの他にルート(Route)という機能が存在しています。
今回はそんなルートについて学習していきましょう。

ルートとは

ルートとはLaravelでルーティングを行う機能です。
ルーティングとはブラウザからアクセスがあった際に、どのコントローラーのどの処理を動かすのかを定義することを言います。
もう少しわかりやすく言うと、「あるURLへリクエストがあったとき、コントローラーのどのメソッドを実行するのかを命令する機能」です。

MVCの図にルートを追加してもう一度確認してみましょう。

このようにブラウザからあるURLへアクセスがあると、始めにルートにたどり着き、どのコントローラーのどのメソッドに処理を振り分けるか決定します。
そこから振り分けられたコントローラーが指定されたメソッドを実行するというイメージです。

では、なぜルートという機能が必要なのでしょうか?
それは、コントローラーはアプリケーション内に複数あることが普通であり、URLごとにどのコントローラーのどのメソッドに振り分けるのかを決める必要があるからです。

つまり、ルートがないとURLにアクセスがあった時に、どのコントローラーのどのメソッドを実行すればいいかLaravelが認識できないので、ページを表示することができなくなってしまいます。

このように、ルートはページを表示させるためには無くてはならない機能なのです。

web.phpについて

Laravelではルーティングをfirst-app/routes/web.phpファイルで行います。
web.phpはすでに下記のような記述がされています。

<?php

use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

※余計なコメントなどは消しています。

Route::get()というコードが記述されていますが、第一引数に「指定したいパス」、第二引数には「第一引数のパスへアクセスがあった場合に実行する処理」を記述します。
この場合、パスは/だけなのでhttp://localhostが開かれたら、return view(‘welcome’);を実行する、という意味になります。
このルーティングこそが最初に見た下記画面を表示しているルートです。

なお通常、第二引数にはコントローラーとメソッド名を記述しますが、デフォルトの記述のように無名関数を使用してweb.phpにそのまま処理を記述することもできます。

return view('welcome')は、ヘルパーメソッドのViewを使用して、first-app/resources/views/welcome.blade.phpというBladeファイルを表示するという意味になります。
※ヘルパーメソッドは、Laravelの中に最初から組み込まれている関数のことです。

また、今回始めてBladeファイルというものが出てきました。
詳しくはビューのレクチャーで説明でしますが、このBladeファイルがLaravelで見た目を表示するためのファイルです。

少しwelcome.blade.phpを見てみましょう。
VSCodeでfirst-app/resources/views/welcome.blade.phpを開いてください。

<!-- ここから上は省略 -->

<div class="p-6">
    <div class="flex items-center">
        <svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" class="w-8 h-8 text-gray-500"><path d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path></svg>
        <div class="ml-4 text-lg leading-7 font-semibold"><a href="https://laravel.com/docs" class="underline text-gray-900 dark:text-white">Documentation</a></div>
    </div>

    <div class="ml-12">
        <div class="mt-2 text-gray-600 dark:text-gray-400 text-sm">
            Laravel has wonderful, thorough documentation covering every aspect of the framework. Whether you are new to the framework or have previous experience with Laravel, we recommend reading all of the documentation from beginning to end.
        </div>
    </div>
</div>

<!-- ここから下は省略 -->

今回はwelcome.blade.phpのすべてを表示するととても長くなってしまうので、下記画像の赤枠部分のみを抜粋しています。

ファイルの中身を見ると、DocumentationというテキストやLaravel has wonderful...という文章が記述されているのがわかると思います。

例えばDocumentationドキュメントと変更して、ファイルを保存すると下記画像のようになります。

Bladeファイルについては後ほど学習するので、現時点で気にする必要はありません。

ルートの記述

では、このweb.phpへ新たに1つのルートを追加してみましょう。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ArticleController; // ここを追加

Route::get('/', function () {
    return view('welcome');
});

// 投稿一覧を表示
Route::get('/articles', [ArticleController::class, 'showArticles'])->name('showArticles'); // ここを追加

まず、後ほど作成するArticleコントローラーを使えるように下記の1文を追加しています。
use App\Http\Controllers\ArticleController;
ArticleControllerはまだ作成していません。

このuse文を使用することで、後ほど作成するコントローラーをweb.phpで使用することができるようになります。
web.phpで他のコントローラーを使用する場合はuse App\Http\Controllers\コントローラーのクラス名を記載しましょう。

初めてのルーティングとして、投稿一覧を表示するためのルートを記述したいので、Route::get('/articles', [ArticleController::class, 'showArticles'])->name('showArticles');というコードを追加しました。

ルートファイルでは、Routeファサードという便利機能を使用することができます。
Route::と記述したあとにHTTPリクエストを記述してください。
今回は記事一覧をただ表示するだけなので、HTTPリクエストはgetを指定していますが、他にもpostなどが使用できます。

第一引数では先ほど学んだ通り'/articles'というパスを設定しています。
そのため、http://localhost/articlesというURLにアクセスすると、ここへルーティングされるということです。

第二引数内に記述しているArticleCotroller::classは、後ほど作成するArticleコントローラーを指定しています。
また、showArticlesArticleコントローラー内に定義されているメソッド名です。

つまり[ArticleController::class, 'showArticles']と記述することで、http://localhost/articlesへアクセスがあった場合にArticleコントローラーshowArticlesメソッドが実行されるということです。

また、Laravelのヘルパーメソッドであるnameメソッドを使用することによって、ルートごとに名前を付けることができます。
今回の場合だと、記事一覧を表示させる画面のルートにshowArticlesと名前を付けたことになります。

この段階では何が便利かわかりにくいですが、ルートに名前を指定しておけばルートを指定する時にとても便利なので、なるべくわかりやす名前を付けておきましょう!

まとめると、Route::get('/articles', [ArticleController::class, 'showArticles'])->name('showArticles');と記述することで、http://localhost/articlesにアクセスがあった場合、ArticleコントローラーshowArticlesメソッドが実行されるということです。

今のArticleコントローラーを作成する前の状態でhttp://localhost/articlesにアクセスしても、下記画像のようなエラーが発生します。

ArticleCotrollerがないよ!としっかりエラーが出ていますね!
Laravelはエラー画面がとてもわかりやすいのも特徴です!

★検索ワード
・Laravel ルーティング
・Laravel ルート 記述方法

コントローラー(Controller)について

ルートの説明でArticleコントローラーが登場したので、次はMVCのCであるコントローラーについて説明します。

コントローラーでは、ビューを表示させる処理やモデルからビューへデータを渡す処理など幅広い処理を記述することができます。
Laravelでは、コントローラーを簡単に実装するための仕組みが用意されているのでさっそく使ってみましょう。

コントローラーファイルの作成

コントローラーファイルもArtisanコマンドを使用して作成することができます。
コマンドは以下の通りです。

$ ./vendor/bin/sail php artisan make:controller クラス名

基本クラス名はテーブル名の単数形にControllerを連結させたものです。
そのため、articlesテーブルのコントローラーを作成する場合のクラス名はArticleControllerとなります。

それではコントローラーファイルを作成するので、ターミナルで下記コマンドをfirst-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan make:controller ArticleController

Controller created successfully.と出力されればコントローラーファイルの作成は完了です。
first-app/app/Http/Controllers配下にArticleController.phpが作成されていればOKです。

それでは作成したArticleController.phpを確認してみましょう。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ArticleController extends Controller
{
    //
}

ファイルの中にはControllerクラスを継承したArticleControllerクラスが作成されています。
ControllerクラスはLaravelが初期機能として持っているクラスであり、このクラスを継承しているため、ArticleControllerクラスはコントローラーとしての機能を発揮することができます。

もう一度web.phpに追加したコードを確認してみましょう。

Route::get('/articles', [ArticleController::class, 'showArticles'])->name('showArticles');

上記のコードをweb.phpへ追加しましたが、簡単に言うとhttp://localhost/articlesへアクセスがあった場合、ArticleコントローラーshowArticlesメソッドを実行するという意味でした。

コントローラーの記述

ここまででArticleコントローラーは作成できたので、showArticlesメソッドを作成していきましょう。
first-app/app/Http/Controllers/ArticleController.phpを下記のように編集してください。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ArticleController extends Controller
{
    // --- ここから追加 ---
    /**
     * 記事一覧を表示する
     */
    public function showArticles()
    {
        return view('articles.index');
    }
    // --- ここまで追加 ---
}

まず、ルーティングで指定したshowArticlesメソッドを作成します。
web.phpで指定したメソッドをコントローラーファイル内で定義する場合は、public function メソッド名(){}と記述してください。
そして{}内にメソッドの処理を記述していきます。

今回はreturn view('articles.index')showArticlesメソッドの処理として記述されています。
このreturn view()は以前ルーティングのところでも説明しましたが、ヘルパーメソッドのViewメソッドを使用して、first-app/resources/views配下のBladeファイルを表示するという意味です。

また、()内に'articles.index'と記述されているので、first-app/resources/views/articles/配下のindex.blade.phpというBladeファイルを表示するという処理になっています。

さらに下記のコメントのようなものが、メソッドの上に追加されています。

/**
 * 記事一覧を表示する
 */

これはPHPDocと呼ばれていて、クラスやメソッドの上に記述することでどのようなクラスやメソッドなのかを説明することができる機能です。

現段階でPHPDocについて意識する必要は全くないので、コメント程度に思っておいていただければOKです!

ビューを表示する

コントローラーの作成から記述までが終わったので、さっそくhttp://localhost/articlesへアクセスしてみましょう。

アクセスすると下記のようなエラーが出ると思います。

エラーの内容はfirst-app/resources/views/articles配下にindex.blade.phpというファイルが存在しないという内容です。

showArticlesメソッドreturn view('articles.index')と指定しましたが、まだBladeファイルを作成していないので当然のエラーですね。

では、さっそくBladeファイルを作成してみましょう。
コマンドでも画面上でそのまま作成してもどちらでも大丈夫です。

まずはfirst-app/resources/views配下にarticlesディレクトリを作成してください。
コマンドで作成する場合は、ターミナルで下記コマンドをfirst-appディレクトリ上で実行してください。

$ mkdir resources/views/articles

次に作成したarticlesディレクトリにindex.blade.phpを作成してください。
コマンドで作成する場合は、ターミナルで下記コマンドをfirst-appディレクトリ上で実行してください。

$ touch resources/views/articles/index.blade.php

作成したindex.blade.phpを開いて、下記の通り編集してください。

Laravelで初めての画面出力

編集して保存したらhttp://localhost/articlesへアクセスしてください。
ブラウザにLaravelで初めての画面出力と表示されていればOKです。

詳しいBladeファイルの記述方法はビューの解説で説明しますので、まずはコントローラーでBladeファイルを表示する順序だけわかっていただければOKです。

画面表示の流れの確認

一度Bladeファイルを表示する流れをおさらいしておきましょう。

まず、URL(http://localhost/articles)にアクセスがされると、ルーティングの処理(Route::get('/articles', [ArticleController::class, 'showArticles'])->name('showArticles');)が実行されます。

ルーティングでは、ArticleコントローラーshowArticlesメソッドを実行するように処理が記述されています。
そのため、first-app/app/Http/Controllers/ArticleController.phpの中のArticleControllerクラスshowArticlesメソッドを実行します。

showArticlesメソッドにはreturn view('articles.index')と記述されており、first-app/resources/views/articles/index.blade.phpを表示する処理になっています。

index.blade.phpを確認するとLaravelで初めての画面出力とテキストが記述されているので、URL(http://localhost/articles)にアクセスがされると、ブラウザにLaravelで初めての画面出力というテキストが表示されることになります。

今回はテキストのみの表示だけだったので、データベースへの接続がない分モデルは登場しませんでした。
なので、下記画像の②データ処理③DB接続は行っていません。

後ほど記事一覧を表示させる時に②と③の方法については説明します。

★検索ワード
・Laravel コントローラー作成
・PHPDocとは

ビュー(View)について

コントローラーの説明で作成したfirst-app/resources/views/articles/index.blade.phpですが、このBladeファイルこそがLaravelのビュー(View)にあたります。

Bladeテンプレートとは

そもそもBladeファイルはBladeテンプレートというテンプレートエンジンで作成されたファイルのことです。

テンプレートエンジンとは、テンプレート部分とデータを合成してドキュメントを出力するソフトウェアのことを指します。
いまいちイメージが湧かないかもしれませんが、HTMLとPHPが直接記述できる便利機能だと思っていただければ大丈夫です。

また、Bladeテンプレートではテンプレートの継承データの受け渡しを簡単に行うことができるようになっており、Laravelを扱う上で必須の知識となるので、さっそく学習していきましょう。

ちなみにテンプレートエンジンはBladeの他にもSmartyTwigなどがありますが、LaravelではBladeを採用しています。

Bladeテンプレートの使い方

Bladeテンプレートには使用できる構文が存在しており、わかりやすいように主なものを表にまとめておきます。

構文説明
@extends(‘Bladeファイル’)()内のBladeファイルを継承することができる
@yield(‘セクション名’)()内のセクション名が同じ@section~@endsectionまでを読み込むことができる
@section(‘セクション名’) ~ @endsection@section@endsectionで囲まれた部分を@yield部分に追加する
@include(‘Bladeファイル’)()内のファイルを読み込むことができる

これらの構文を使用することでHTMLファイルやPHPファイルをそのまま使用するよりも遥かに管理しやすい状態で見た目(View)を作成することができるようになります。
使い方は見た目を実装しながら、順番に説明していきます。

Bladeの記述

先ほども少し触れた通り、BladeファイルにはHTMLをそのまま記述することができます。
なので、ざっくりとした見た目を最初に作成してしまいましょう。

それでは、以前作成したfirst-app/resources/views/articles/index.blade.phpを下記のように編集してください。

<!DOCTYPE HTML>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ブログ</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
</head>

<body>
    <!-- ヘッダー -->
    <header>
        <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
            <div class="container-fluid">
                <a class="navbar-brand" href="#">ブログ</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse justify-content-end" id="navbarNavAltMarkup">
                    <div class="navbar-nav">
                        <a class="nav-item nav-link active" href="#">記事一覧 <span class="sr-only"></span></a>
                        <a class="nav-item nav-link" href="#">記事投稿</a>
                    </div>
                </div>
            </div>
        </nav>
    </header>

    <!-- コンテンツ -->
    <div class="container mt-4">
        <div class="row">
            <h2>記事一覧</h2>
            <table class="table table-bordered table-hover ">
                <thead class="bg-info text-light">
                    <tr>
                        <th scope="col">#</th>
                        <th scope="col">タイトル</th>
                        <th scope="col">内容</th>
                        <th scope="col">日付</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>1</td>
                        <td>テスト1</td>
                        <td>テスト1です。</td>
                        <td>2022/01/01</td>
                    </tr>
                    <tr>
                        <td>2</td>
                        <td>テスト2</td>
                        <td>テスト2です。</td>
                        <td>2022/01/02</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>

    <!-- フッター -->
    <footer class="footer bg-primary  fixed-bottom">
        <div class="container text-center">
            <span class="text-light">©︎Laravel教材</span>
        </div>
    </footer>

    <!-- JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
</body>

</html>

編集が終わったら保存してhttp://localhost/articlesへアクセスしてみましょう。
下記画像のように画面が表示されればOKです。

まず、記事一覧に表示されている記事自体はHTMLで直接記述しているものになります。
後ほどデータベースから記事を取得して表示させますが、まずはHTMLで直接記述することで記事の表示をしておきます。

また、今回は見た目部分を整えるためにBootstrapというフレームワークを使用しています。
Bootstrapは複雑なCSSやJavaScriptを記述しなくてもHTMLにclassidを指定することで、簡単に見た目を整えることができるので重宝されています。

そんな便利なBootstrapですが、CDNでお手軽に使用することができます。
Bootstrapを使用する際のCDNは下記のようになっています。

<!-- CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">

<!-- JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>

本教材はLaravelを学習するための教材なのでBootstrapについての解説は省きますが、興味のある方は公式ドキュメントがあるので見てみてください。
※Bootstrapの基本的な使い方は、ドキュメントに記述しているコードをコピペして使用していきます。

Bladeの共通化

それでは、index.blade.phpに全て記述していた見た目部分をBladeの力を使用してヘッダーやコンテンツ、フッターと共通化させていきます。

共通化の流れは下記の通りです。

  1. 共通のテンプレートであるlayout.blade.phpを作成する
  2. 共通のヘッダーを作成する
  3. 共通のフッターを作成する
  4. index.blade.phpに共通のテンプレートであるlayout.blade.phpを継承させる

共通化継承と言われてもなかなかイメージがしにくいと思うので、まずは実装していきましょう。

layout.blade.phpの作成

それでは共通のテンプレートにするためのlayout.blade.phpを作成しましょう。
first-app/resources/viewsディレクトリにlayout.blade.phpをコマンドかVSCode上で作成してください。
コマンドで作成する場合は、ターミナルで下記コマンドをfirst-appディレクトリ上で実行してください。

$ touch resources/views/layout.blade.php

作成したlayout.blade.phpindex.blade.phpの内容をそのまま貼り付けてください。

<!DOCTYPE HTML>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ブログ</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
</head>

<body>
    <!-- ヘッダー -->
    <header>
        <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
            <div class="container-fluid">
                <a class="navbar-brand" href="#">ブログ</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse justify-content-end" id="navbarNavAltMarkup">
                    <div class="navbar-nav">
                        <a class="nav-item nav-link active" href="#">記事一覧 <span class="sr-only"></span></a>
                        <a class="nav-item nav-link" href="#">記事投稿</a>
                    </div>
                </div>
            </div>
        </nav>
    </header>

    <!-- コンテンツ -->
    <div class="container mt-4">
        <div class="row">
            <h2>記事一覧</h2>
            <table class="table table-bordered table-hover ">
                <thead class="bg-info text-light">
                    <tr>
                        <th scope="col">#</th>
                        <th scope="col">タイトル</th>
                        <th scope="col">内容</th>
                        <th scope="col">日付</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>1</td>
                        <td>テスト1</td>
                        <td>テスト1です。</td>
                        <td>2022/01/01</td>
                    </tr>
                    <tr>
                        <td>2</td>
                        <td>テスト2</td>
                        <td>テスト2です。</td>
                        <td>2022/01/02</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>

    <!-- フッター -->
    <footer class="footer bg-primary  fixed-bottom">
        <div class="container text-center">
            <span class="text-light">©︎Laravel教材</span>
        </div>
    </footer>

    <!-- JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
</body>

</html>

これで今回作成したfirst-app/resources/views/layout.blade.phpfirst-app/resources/views/articles/index.blade.phpのコードは全く同じ状態です。

共通ヘッダーの作成

次にどのページにも共通するヘッダーであるheader.blade.phpの作成を行っていきます。
first-app/resources/viewsディレクトリにheader.blade.phpをコマンドかVSCode上で作成してください。

コマンドで作成する場合は、ターミナルで下記コマンドをfirst-appディレクトリ上で実行してください。

$ touch resources/views/header.blade.php

作成したheader.blade.phplayout.blade.phpのヘッダー部分をコピーして、下記の通り貼り付けてください。

<header>
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
        <div class="container-fluid">
            <a class="navbar-brand" href="#">ブログ</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse justify-content-end" id="navbarNavAltMarkup">
                <div class="navbar-nav">
                    <a class="nav-item nav-link active" href="#">記事一覧 <span class="sr-only"></span></a>
                    <a class="nav-item nav-link" href="#">記事投稿</a>
                </div>
            </div>
        </div>
    </nav>
</header>

また、layout.blade.phpのヘッダー部分を下記の通り編集してください。

<!DOCTYPE HTML>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ブログ</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
</head>

<body>
    <!-- ヘッダー -->
    @include('header')

    <!-- コンテンツ -->
    <div class="container mt-4">
        <div class="row">
            <h2>記事一覧</h2>
            <table class="table table-bordered table-hover ">
                <thead class="bg-info text-light">
                    <tr>
                        <th scope="col">#</th>
                        <th scope="col">タイトル</th>
                        <th scope="col">内容</th>
                        <th scope="col">日付</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>1</td>
                        <td>テスト1</td>
                        <td>テスト1です。</td>
                        <td>2022/01/01</td>
                    </tr>
                    <tr>
                        <td>2</td>
                        <td>テスト2</td>
                        <td>テスト2です。</td>
                        <td>2022/01/02</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>

    <!-- フッター -->
    <footer class="footer bg-primary  fixed-bottom">
        <div class="container text-center">
            <span class="text-light">©︎Laravel教材</span>
        </div>
    </footer>

    <!-- JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
</body>

</html>

このように@include('header')と記述することでfirst-app/resources/views/header.blade.phpを読み込むことができます。

つまり、本来であればヘッダー部分をlayout.blade.phpに直接記述していましたが、ヘッダー部分だけをheader.blade.phpで管理することによって、ヘッダーを編集したい場合はheader.blade.phpのみを編集すればいいことになります。

このようにヘッダー部分を別ファイルで管理することによってメンテナンス性の向上可読性に繋がります。

共通フッターの作成

それではヘッダーと同じように、どのページにも共通するフッターfooter.blade.phpの作成を行っていきます。
first-app/resources/viewsディレクトリにfooter.blade.phpをコマンドかVSCode上で作成してください。

コマンドで作成する場合は、ターミナルで下記コマンドをfirst-appディレクトリ上で実行してください。

$ touch resources/views/footer.blade.php

作成したfooter.blade.phplayout.blade.phpのフッター部分をコピーして、下記の通り貼り付けてください。

<footer class="footer bg-primary  fixed-bottom">
    <div class="container text-center">
        <span class="text-light">©︎Laravel教材</span>
    </div>
</footer>

また、layout.blade.phpもフッター部分を下記の通り編集してください。

<!DOCTYPE HTML>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ブログ</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
</head>

<body>
    <!-- ヘッダー -->
    @include('header')

    <!-- コンテンツ -->
    <div class="container mt-4">
        <div class="row">
            <h2>記事一覧</h2>
            <table class="table table-bordered table-hover ">
                <thead class="bg-info text-light">
                    <tr>
                        <th scope="col">#</th>
                        <th scope="col">タイトル</th>
                        <th scope="col">内容</th>
                        <th scope="col">日付</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>1</td>
                        <td>テスト1</td>
                        <td>テスト1です。</td>
                        <td>2022/01/01</td>
                    </tr>
                    <tr>
                        <td>2</td>
                        <td>テスト2</td>
                        <td>テスト2です。</td>
                        <td>2022/01/02</td>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>

    <!-- フッター -->
    @include('footer')

    <!-- JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
</body>

</html>

ヘッダーと同じく@include('footer')と記述することでfirst-app/resources/views/footer.blade.phpを読み込むことができます。

これでフッター部分はfooter.blade.phpで管理することができるようになりました。

index.blade.phpにlayout.blade.phpを継承させる

それでは、残っているコンテンツ部分を@yield@section~@endsectionで読み込ませるようにしてから、index.blade.phplayout.blade.phpを継承させていきます。

コンテンツの表示

まずはコンテンツ部分を@yield@section~@endsectionを使用して読み込ませる記述をしていきます。

layout.blade.phpを下記の通り編集してください。

<!DOCTYPE HTML>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>ブログ</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
</head>

<body>
    <!-- ヘッダー -->
    @include('header')

    <!-- コンテンツ -->
    <div class="container mt-4">
        @yield('content')
    </div>

    <!-- フッター -->
    @include('footer')

    <!-- JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
</body>

</html>

まず共通のレイアウトとなるlayout.blade.phpのコンテンツ部分にある<div class="container mt-4"></div>以外のコードを全て削除してから、代わりに@yield('content')と記述します。

このように@yield('content')と記述することで、あるファイルでlayout.blade.phpが継承された時に@section('content')@endsectionで囲まれた部分を@yield('content')部分に読み込ませることができます。

それではindex.blade.phplayout.blade.phpを継承して、@section('content')@endsectionで囲んだ部分にコンテンツを記述してみましょう。

index.blade.phpを下記の通り編集してください。

@extends('layout')

@section('content')
    <div class="row">
        <h2>記事一覧</h2>
        <table class="table table-bordered table-hover ">
            <thead class="bg-info text-light">
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">タイトル</th>
                    <th scope="col">内容</th>
                    <th scope="col">日付</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>1</td>
                    <td>テスト1</td>
                    <td>テスト1です。</td>
                    <td>2022/01/01</td>
                </tr>
                <tr>
                    <td>2</td>
                    <td>テスト2</td>
                    <td>テスト2です。</td>
                    <td>2022/01/02</td>
                </tr>
            </tbody>
        </table>
    </div>
@endsection

まず継承するためには@extends()を使用します。
@extends()を使用し()内に継承したいBladeファイルを記述することで、index.blade.phpに()内で指定したBladeファイルを継承することができます。

今回はindex.blade.phplayout.blade.phpを継承したいので、@extends('layout')となります。
無事にlayout.blade.phpを継承することができたので、layout.blade.phpの中に記述されている全てのコードがindex.blade.phpに記述されているのと同じ状況を作り出すことができました。

そして、最後にindex.balde.phpの先ほどlayout.blade.phpで削除したコンテンツ部分を@section('content')@endsectionで囲まれた部分に記述すればOKです。

さっそくhttp://localhost/articlesへアクセスしてみましょう。
下記画像のように画面が表示されればOKです。

これで無事にコンテンツ部分を読み込ませることに成功しましたが、実はあと1つ@yield()@section()~@endsectionで記述した方が良い箇所があります。

それはlayout.blade.phptitle要素です。

タイトル部分はページ毎に変更したいので、ここも@yield()を使用してページ毎に変更可能にさせましょう。

それでは、layout.blade.phpを下記の通り編集してください。

<!DOCTYPE HTML>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <title>@yield('title', 'ブログ')</title> 
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/css/bootstrap.min.css" integrity="sha384-r4NyP46KrjDleawBgD5tp8Y7UzmLA05oM1iAEQ17CSuDqnUK2+k9luXQOfXJCJ4I" crossorigin="anonymous">
</head>

<body>
    <!-- ヘッダー -->
    @include('header')

    <!-- コンテンツ -->
    <div class="container mt-4">
        @yield('content')
    </div>

    <!-- フッター -->
    @include('footer')

    <!-- JavaScript -->
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/5.0.0-alpha1/js/bootstrap.min.js" integrity="sha384-oesi62hOLfzrys4LxRF63OJCXdXDipiYWBnvTl9Y9/TRlw5xlKIEHpNyvvDShgf/" crossorigin="anonymous"></script>
</body>

</html>

変更した箇所は、title要素の中身です。
変更前はブログというテキストのみを記述していましたが、このままだと全てのページでtitle要素がブログになってしまいます。

代わりに@yield('title', 'ブログ')と記述することで、layout.blade.phpを継承したファイルで@section('title')~@endsectionを使用することで、ページ固有のタイトルを決めることができるようになります。

また、万が一継承したファイルに@section('title')~@endsectionがない場合も@yield()の第二引数であるブログがページのタイトルになるので、設定し忘れたとしてもしっかりとタイトルブログが表示されます。

では、次にindex.blade.phpを下記の通り編集してください。

@extends('layout')

@section('title')
    記事一覧
@endsection

@section('content')
    <div class="row">
        <h2>記事一覧</h2>
        <table class="table table-bordered table-hover ">
            <thead class="bg-info text-light">
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">タイトル</th>
                    <th scope="col">内容</th>
                    <th scope="col">日付</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>1</td>
                    <td>テスト1</td>
                    <td>テスト1です。</td>
                    <td>2022/01/01</td>
                </tr>
                <tr>
                    <td>2</td>
                    <td>テスト2</td>
                    <td>テスト2です。</td>
                    <td>2022/01/02</td>
                </tr>
            </tbody>
        </table>
    </div>
@endsection

追加したコードは以下の通りです。

@section('title')
    記事一覧
@endsection

layout.blade.php@yield('title')と記述したので、index.blade.phpでは@section('title')~@endsectionと記述します。
また、index.blade.phpは記事一覧を表示させるためのページなので、記事一覧というページタイトルにしています。

それでは改めてhttp://localhost/articlesへアクセスしてみましょう。
下記画像のように画面が表示されていて、Chromeのタブ部分であるページタイトルが記事一覧になっていればOKです。

このようにBladeで共通化してもユーザーが見る見た目はindex.blade.phpへ全てのHTMLを記述したときとまったく変わっていません。
その代わりindex.blade.phpの内容はlayout.blade.phpを継承したことで大きく変わっています。

これからBladeファイルを作成するときはlayout.blade.phpを継承し、titlecontent部分だけを記述すればページが完成します。

まだ記事一覧ページしか作成していないのでBladeの恩恵を感じにくいかもしれませんが、これから記事詳細画面や記事作成画面、記事編集画面を作成していく中でより恩恵を感じられると思います。

ひとまず記事一覧画面の見た目の作成はこれで完了です。

★検索ワード
・Laravel view 作成
・Laravel view 共通化
・Laravel @extends
・Laravel @yield
・Laravel @section @endsection
・Laravel @include
・Bootstrap 使い方

次の教材

次の教材は下記から簡単に飛ぶことができます!
引き続きプログラミングを楽しんでいきましょう!

あわせて読みたい
【Laravel教材④】Laravelでブログシステム構築!〜全記事一覧画面実装から記事詳細画面実装編〜 こちらの記事はLaravel教材の第4回目の記事になります。 その他のLaravel教材を学習したい方は下記リンクから直接教材へ飛ぶことができます。 【全ての記事を取得して一...

プログラミング学習サポートについて

「独学で挫折した。。。」

「一人でのプログラミング学習がしんどい。。。」

「未経験からエンジニア転職をしたいけど何をしたら良いかわからない。。。」

このような悩みをお持ちの方向けに、本教材作成者のファドがMENTAという学習サイトにてあなたのプログラミング学習とエンジニア転職を徹底サポートいたします!

サポート価格はなんと1日あたりたったの約300円!

教材で分からない箇所のサポートはもちろんのこと、本サイトで公開しているすべての課題の解答も公開しております。
また、MENTAで学習を終わらせていただいた方限定で懇意にしていただいている企業さんを紹介することもあります!

なお、サポート内容の詳細は下記の通りです。

  • 目標設定
  • マインドセット
  • オリジナル教材見放題
  • オリジナル課題見放題
  • オリジナル課題の解答見放題
  • 課題コードレビュー
  • 教材への無制限質問
  • 課題への無制限質問
  • ポートフォリオ作成アドバイス
  • 褒めのコーチング

いくつかのプランを用意させていただいておりますので、下記より一度ご覧ください!

あわせて読みたい
【プログラミング学習】1日あたりたったの「300円」のみでプログラミングを学び、最短で転職or稼ぐ!|【ME... プログラミングを学びたいすべての方へこれからの時代は格安でプログラミングを学び、最短で稼げ自己紹介はじめまして!この度はプランをご覧いただき、誠にありがとうござ...

コメント

    この記事が気に入ったら
    フォローしてね!

    よかったらシェアしてね!
    • URLをコピーしました!

    コメント

    コメントする

    目次