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

【応用Laravel教材②】Laravelでタスク管理アプリ実装!〜テンプレートの作成からログイン画面作成編〜

ファド

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

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

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

目次

各種テンプレート作成

次はビューの元になる見た目のテンプレートを作成してきましょう。

テンプレート作成

ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ touch resources/views/layouts/layout.blade.php

task-app/resources/views/layoutsディレクトリにlayout.blade.phpが作成されるので、下記の通り編集してください。

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>@yield('title', 'タスク管理')</title>

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

    <!-- CSS -->
    <link rel="stylesheet" href="{{ asset('css/style.css') }}">
</head>

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

    <!-- コンテンツ -->
    <main>
        @yield('content')
    </main>

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

    <!-- Bootstrap -->
    <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>

Laravel教材の時と同じように、簡単あに見た目を整えるためにBootstrapをCDNで使用しています。
また、後ほど作成するCSSを読み込むための<link rel="stylesheet" href="{{ asset('css/style.css') }}">という記述もしています。
こちらについては、CSS導入時に説明します。

タイトルやヘッダー、コンテンツ、フッターなどは@yield@includeを使用しているので、この後作成していきます。

ヘッダー作成

次に共通ヘッダーを作成します。

ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ touch resources/views/layouts/header.blade.php

task-app/resources/views/layoutsディレクトリにheader.blade.phpが作成されるので、下記の通り編集してください。

<header>
    <nav class="navbar navbar-expand-lg navbar-dark" style="background-color: #1f1f1f;">
        <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">
                    @auth
                        <a class="mr-lg-3 my-lg-0 my-3 btn btn-sm btn-dark text-light nav-item nav-link" href="#">ユーザーA</a>
                        <form action="{{ route('logout') }}" method="POST">
                            @csrf
                            <button class="btn btn-sm btn-danger text-light nav-item nav-link w-100">ログアウト</button>
                        </form>
                    @else
                        <a class="mr-lg-3 my-lg-0 my-3 btn btn-sm btn-dark text-light nav-item nav-link" href="{{ route('login') }}">ログイン</a>
                        <a class="btn btn-sm btn-primary text-light nav-item nav-link" href="{{ route('register') }}">新規登録</a>
                    @endauth
                </div>
            </div>
        </div>
    </nav>
</header>

ヘッダーには必ず左上にアプリ名であるタスク管理というリンクを設定しておきます。
また、右上には未ログインユーザーかログインユーザーかで出し分けるボタンを設置します。

未ログインの場合はログインボタン新規登録ボタンを右上に表示します。
一方でログイン済みの場合はユーザー名ログアウトボタンを表示します。

Bladeテンプレートでは@authと記述することでログイン済みの時の処理を記述することができます。
@authで囲まれている部分は下記のようにユーザー名ログアウトボタンを記述しています。

@auth
    <a class="mr-lg-3 my-lg-0 my-3 btn btn-sm btn-dark text-light nav-item nav-link" href="#">ユーザーA</a>
    <form action="{{ route('logout') }}" method="POST">
        @csrf
        <button class="btn btn-sm btn-danger text-light nav-item nav-link w-100">ログアウト</button>
    </form>
@else

ログアウトボタンはPOST送信のためform要素として処理しています。
formを使用する際は@csrfを忘れないようにしましょう。
また、action属性の属性値に{{ route('logout') }}と記述されていますが、これはLaravel Breezeで導入した場合のログアウト用のルート名がlogoutだからです。

ちなみにLaravelでは現在設定されているルートをコマンドで確認することができます。
ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan route:list

コマンドを実行すると下記のような実行結果が表示されます。

GET|HEAD   / ............................................................................................................ 
POST       _ignition/execute-solution ..... ignition.executeSolution › Spatie\LaravelIgnition › ExecuteSolutionController
GET|HEAD   _ignition/health-check ................. ignition.healthCheck › Spatie\LaravelIgnition › HealthCheckController
POST       _ignition/update-config .............. ignition.updateConfig › Spatie\LaravelIgnition › UpdateConfigController
GET|HEAD   api/user ..................................................................................................... 
GET|HEAD   confirm-password .................................. password.confirm › Auth\ConfirmablePasswordController@show
POST       confirm-password .................................................... Auth\ConfirmablePasswordController@store
GET|HEAD   dashboard .......................................................................................... dashboard
POST       email/verification-notification ....... verification.send › Auth\EmailVerificationNotificationController@store
GET|HEAD   forgot-password ................................... password.request › Auth\PasswordResetLinkController@create
POST       forgot-password ...................................... password.email › Auth\PasswordResetLinkController@store
GET|HEAD   login ..................................................... login › Auth\AuthenticatedSessionController@create
POST       login .............................................................. Auth\AuthenticatedSessionController@store
POST       logout .................................................. logout › Auth\AuthenticatedSessionController@destroy
GET|HEAD   register ..................................................... register › Auth\RegisteredUserController@create
POST       register ................................................................. Auth\RegisteredUserController@store
POST       reset-password ............................................ password.update › Auth\NewPasswordController@store
GET|HEAD   reset-password/{token} .................................... password.reset › Auth\NewPasswordController@create
GET|HEAD   sanctum/csrf-cookie .............................................. Laravel\Sanctum › CsrfCookieController@show
GET|HEAD   verify-email ........................... verification.notice › Auth\EmailVerificationPromptController@__invoke
GET|HEAD   verify-email/{id}/{hash} ........................... verification.verify › Auth\VerifyEmailController@__invoke

これが現在ルーティングされているルート一覧です。
ログアウトに関するルーティングは下記の通りです。

POST       logout .................................................. logout › Auth\AuthenticatedSessionController@destroy

この一文を読み解くと、POST通信でhttp://localhost//logoutというURLにアクセスでき、ルート名はlogoutで、アクセスがあるとAuth\AuthenticatedSessionControllerというコントローラーのdestroyメソッドが実行されるということです。

また、実行結果をよく見るとregisterloginといった新規登録とログインのルーティングもされていることがわかります。

それらのルート名を使用して、未ログイン時の2つのボタンも作成することができます。
未ログイン時の記述は@else以下の処理です。

@else
    <a class="mr-lg-3 my-lg-0 my-3 btn btn-sm btn-dark text-light nav-item nav-link" href="{{ route('login') }}">ログイン</a>
    <a class="btn btn-sm btn-primary text-light nav-item nav-link" href="{{ route('register') }}">新規登録</a>
@endauth

ログイン用のルート名はloginなので、{{ route('login') }}となります。
また、新規登録用のルート名はregisterなので{{ route('register') }}となります。

フッター作成

次に共通フッターを作成します。

ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ touch resources/views/layouts/footer.blade.php

task-app/resources/views/layoutsディレクトリにfooter.blade.phpが作成されるので、下記の通り編集してください。

<footer class="footer fixed-bottom" style="background-color: #1f1f1f;">
    <div class="container text-center">
        <span class="text-light">©︎Laravel応用教材</span>
    </div>
</footer>

フッターは特に難しいことはしていません。

トップページ作成

次にテンプレートが完成したのでトップページを作成していきましょう。
http://localhost/へアクセスされた場合に表示されるwelcome.blade.phpを変更していきましょう。

task-app/resources/views/welcome.blade.phpを下記の通り編集してください。

@extends('layouts.layout')

@section('title')
    タスク管理
@endsection

@section('content')
    <div class="top-page d-flex flex-column justify-content-center align-items-center ">
        <div class="h1 text-center">
            <h1 class="text-light">タスク管理</h1>
            <h2 class="text-light">いつでもどこでも簡単に♪</h2>
        </div>
        <div class="d-flex">
            @auth
                <a href="#" class="btn btn-success">プロジェクト一覧</a>
            @else
                <a href="{{ route('register') }}" class="btn btn-success">まずは無料で登録する</a>
            @endauth
        </div>
    </div>
@endsection

ヘッダーと同じように@authを使用して、ログイン時と未ログインの時のボタン出し分けを行っています。
ログイン時はプロジェクト一覧へ遷移できるボタンを表示し、未ログインの時は新規登録画面へ遷移するためのボタンを表示するようにしています。

次に、独自のCSSで背景などを指定したいので、CSSファイルを作成します。
LaravelでCSSを使用するにはいくつか方法がありますが、まずは一番簡単に実装できる方法で実装します。

task-app/publicディレクトリにcssフォルダを作成し、その中にstyle.cssを作成してください。
コマンドでもVSCode上で作成してもどちらでもOKです。

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

$ mkdir public/css && touch public/css/style.css

作成したtask-app/public/css/style.cssを下記の通り編集してください。

.top-page {
    background-image: url('../images/test.jpg');
    background-color:rgba(0, 0, 0, .6);
    background-blend-mode:darken;
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
    background-attachment: fixed;
    min-height: calc(100vh - 80px);
}

CSSで背景に画像を指定していますが、画像がまだないので写真を用意して設定していきます。
皆さんが持っている画像でも大丈夫ですが、https://unsplash.com/photos/cckf4TsHAuwからダウンロードしていただいてもOKです。
※画像URLが開けない場合はこちらから好きな写真を選んでダウンロードしてください。

Laravelで画像を表示させるためにtask-app/publicディレクトリにimagesフォルダを作成します。
さっそくpublicディレクトリにimagesフォルダを作成しましょう。
コマンドでもVSCode上で作成してもどちらでもOKです。

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

$ mkdir public/images

作成したtask-app/public/imagesディレクトリに画像を入れてください。
画像の名前はCSSで指定した通り、test.jpgとしています。

これでトップページを表示することができるようになりました。
http://localhost/にアクセスして、下記画像のようになっていればOKです!

認証画面編集

次に、新規登録画面やログイン画面の見た目を変更していきましょう。
Laravel Breezeで認証機能を実装した場合、自動的にtask-app/resources/viewsディレクトリにauthディレクトリが作成され、その中に認証用のBladeファイルがいくつか作成されています。

新規登録画面

まず、新規登録画面はtask-app/resources/views/auth/register.blade.phpを変更することで、オリジナルの新規登録画面を作成することができます。

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

@extends('layouts.layout')

@section('title')
    新規登録
@endsection

@section('content')
    <div class="container mt-4">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header text-center">新規登録</div>
     
                    <div class="card-body">
                        <form method="POST" action="{{ route('register') }}">
                            @csrf
     
                            <div class="form-group d-flex flex-column flex-md-row">
                                <label for="name" class="col-md-4 col-form-label text-md-right">ユーザー名:</label>
                                <div class="col-md-6">
                                    <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>
                                    @error('name')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group d-flex flex-column flex-md-row mt-3">
                                <label for="email" class="col-md-4 col-form-label text-md-right">メールアドレス:</label>
                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
                                    @error('email')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group d-flex flex-column flex-md-row mt-3">
                                <label for="password" class="col-md-4 col-form-label text-md-right">パスワード:</label>
                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
                                    @error('password')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group d-flex flex-column flex-md-row mt-3">
                                <label for="password_confirmation" class="col-md-4 col-form-label text-md-right">パスワード確認:</label>
                                <div class="col-md-6">
                                    <input id="password_confirmation" type="password" class="form-control @error('password_confirmation') is-invalid @enderror" name="password_confirmation" required autocomplete="new-password">
                                    @error('password_confirmation')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>
     
                            <div class="form-group d-flex mt-3 mb-0">
                                <div class="col-md-10 col-12 d-flex justify-content-end">
                                    <button type="submit" class="btn btn-primary">登録</button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

編集が完了したら、http://localhost/registerへアクセスし、下記の通り画面が表示されればOKです。

それでは実装内容について2つのポイントを説明します。
まず1つ目は、formでPOST送信をしているということです。
action属性にはroute('register')を記述していますが、これは以前ルーティング一覧をコマンドで確認した時に新規登録用のルート名がregisterであったためです。

念の為、もう一度ルーティング一覧を確認できるコマンドを復習しておきましょう。

$ ./vendor/bin/sail php artisan route:list

心配な方はもう一度新規登録のルート名がregisterなのか確認しておくと良いでしょう。

2つ目にパスワード一致のバリデーション機能についてです。
Laravelでは、confirmedルールというバリデーションルールが実装されています。
このルールはname属性がある属性値(仮にpasswordとします)の入力値とある属性値+confirmationという属性値(今回の場合はpassword_confirmation)の入力値が一致することを検証します。

よく使う場面として、パスワードを入力させた後に確認としてもう一度パスワードを入力させる時のバリデーションとして使用します。

今回もパスワードの確認用inputにはpassword_confirmationというname属性にしています。

ログイン画面

次にログイン画面の編集を行っていきます。
ログイン画面はtask-app/resources/views/auth/login.blade.phpを変更することで、オリジナルのログイン画面を作成することができます。

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

@extends('layouts.layout')

@section('title')
    ログイン
@endsection

@section('content')
    <div class="container mt-4">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header text-center">ログイン</div>
     
                    <div class="card-body">
                        <form method="POST" action="{{ route('login') }}">
                            @csrf
     
                            <div class="form-group d-flex flex-column flex-md-row">
                                <label for="email" class="col-md-4 col-form-label text-md-right">メールアドレス:</label>
                                <div class="col-md-6">
                                    <input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
                                    @error('email')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>

                            <div class="form-group d-flex flex-column flex-md-row mt-3">
                                <label for="password" class="col-md-4 col-form-label text-md-right">パスワード:</label>
                                <div class="col-md-6">
                                    <input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
                                    @error('password')
                                        <span class="invalid-feedback" role="alert">
                                            <strong>{{ $message }}</strong>
                                        </span>
                                    @enderror
                                </div>
                            </div>
     
                            <div class="form-group d-flex mt-3 mb-0">
                                <div class="col-md-10 col-12 d-flex justify-content-end">
                                    <button type="submit" class="btn btn-primary">ログイン</button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

編集が完了したら、http://localhost/loginへアクセスし、下記の通り画面が表示されればOKです。

ログイン画面は特に難しいことはありません。
新規登録画面と同じようにformでPOST送信をしています。

action属性にはroute('login')を記述していますが、Laravel Breezeで認証機能を実装した場合のログインのルート名がloginだからです。

もちろん$ ./vendor/bin/sail php artisan route:listで確認できます。

バリデーションメッセージの日本語化

これで新規登録とログイン機能は完成しましたが、新規登録時のバリデーションメッセージの一部が下記画像の通り、日本語化されていないので設定していきます。

ちなみに、新規登録機能のコントローラーはtask-app/app/Http/Controllers/Auth/RegisterdUserController.phpです。

ユーザー情報登録用のメソッドstoreは下記のようになっています。

/**
 * Handle an incoming registration request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\RedirectResponse
 *
 * @throws \Illuminate\Validation\ValidationException
 */
public function store(Request $request)
{
    $request->validate([
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => ['required', 'confirmed', Rules\Password::defaults()],
    ]);

    $user = User::create([
        'name' => $request->name,
        'email' => $request->email,
        'password' => Hash::make($request->password),
    ]);

    event(new Registered($user));

    Auth::login($user);

    return redirect(RouteServiceProvider::HOME);
}

バリデーションに関するコードは$request->validate()で囲まれた部分です。
記述方法はフォームリクエストで指定した方法と同じです。
このようにバリデーションはコントローラーで指定することもできます。

では、さっそく日本語化していきましょう。

task-app/resources/lang/ja/validation.phpを下記の通り編集してください。

// --- 以上省略 ---

/*
|--------------------------------------------------------------------------
| カスタムバリデーション属性名
|--------------------------------------------------------------------------
|
| 以下の言語行は、例えば"email"の代わりに「メールアドレス」のように、
| 読み手にフレンドリーな表現でプレースホルダーを置き換えるために指定する
| 言語行です。これはメッセージをよりきれいに表示するために役に立ちます。
|
*/

'attributes' => [
    'name' => 'ユーザー名',
    'email' => 'メールアドレス',
    'password' => 'パスワード',
],

validation.phpは、以前日本語ファイルをダウンロードした際にダウンロードされたファイルです。
そのファイルの一番下にattributes => [];となっているので、その中に翻訳した値を入力すればOKです。

もう一度新規登録画面でバリデーションに引っかかるように入力してみると、下記画像のようになります。

これで日本語化はOKです。

次の教材

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

あわせて読みたい
【応用Laravel教材③】Laravelでタスク管理アプリ実装!〜プロジェクト一覧機能実装からログイン後のリダ... こちらの記事は応用Laravel教材の第3回目の記事になります。 その他の応用Laravel教材を学習したい方は下記リンクから直接教材へ飛ぶことができます。 【プロジェクト一...

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

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

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

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

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

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

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

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

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

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

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

コメント

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

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

    コメント

    コメントする

    目次