「プロフェッショナルWebプログラミングLaravel」の感想・備忘録5

スポンサーリンク

ログイン機能

Laravel Breeze

  • Laravel BreezeはLaravelを使ったユーザー登録、ログイン、パスワード再設定、などを手軽に提供してくれるPHPパッケージである。

インストール

  1. sail composer require laravel/breeze --dev
  2. sail artisan breeze:install
    ※ route/web.phpが上書きされるので注意
    ※ Tailwind CSSもインストールされる

ルーティング

  • route/web.phpが更新され、route/auth.phpが追加される。
  • ルートはguestミドルウェアとauthミドルウェアのグループに分かれている。

ミドルウェア

ミドルウェアとは

  • コントローラのアクションの前後に処理を挟み込むときに使う。
1. sail artisan make:middleware Xxxで生成
public function handle($request, Closure $next)
{
    // ここにアクション前に実行させたい処理を書く
    $response = $next($request);
    // ここにアクション後に実行させたい処理を書く
    return $response;
}
2. App\Http\Kernelにミドルウェアを登録する
// グローバルミドルウェアとしてアプリ全体に作用させる場合は$middleware配列に追加する。
protected $middleware = [
    \App\Http\Middleware\Xxx::class,
    // 以下省略
// ルートミドルウェアとして特定のルートだけに作用させたい場合は$routeMiddleware連想配列に追加する。
(Laravel10からは$middlewareAliases)
protected $middlewareAliases = [
    'hoge’ => \App\Http\Middleware\Xxx::class, // ルーティングでhogeを指定すると作用する
    // 以下省略

ログイン処理で使われているミドルウェア

guestミドルウェア
  • ガードを使ってログイン状況を確認し、ログイン済みの場合はHOMEに飛ばす。
  • ガードとは「管理者」「会員」などログイン機構の種類を表す。
    ログイン画面の数だけガードがある、というイメージ。
  • config/auth.phpに設定があり、driverはログイン状態をどこに保存するか、providerはユーザー情報の取得方法、が定義されている。
authミドルウェア

ログインしていない場合はAuthenticationExceptionを投げ、ログイン画面に飛ばす。

登録・ログイン後、ログアウトのページを変更する

登録・ログイン後

app/Providers/RouteServiceProvider.phpのHOME変更するだけ。
public const HOME = '/';

ログアウト後

app/Http/Controllers/Auth/AuthenticatedSessionController.phpのdestroyメソッド内にあるredirect()を修正するだけ。
return redirect('/tweet');

ログインユーザーのみに許可する

特定のルーティングをログインユーザーだけに許可する場合は->middleware('auth')を追加する。

Route::post('/tweet/create', \App\Http\Controllers\Tweet\CreateController::class)
    ->middleware('auth')
    ->name('tweet.create');

Route::middleware()を使うと複数のルートにミドルウェアを指定することができる。

Route::middleware('auth')->group(function () {
    // ルート定義
}

テンプレートで@authと@endauthで囲まれた場所はログインユーザーだけに表示される。
@geustと@endguestで囲まれた場所はゲストユーザーだけに表示される。

@auth
<div>
    <p>投稿フォーム</p>
    @if (session('feedback.success'))
        <p style="color: green">{{ session('feedback.success') }}</p>
    @endif
    <form action="{{ route('tweet.create') }}" method="post">
        @csrf
        <label for="tweet-content">つぶやき</label>
        <span>140文字まで</span>
        <textarea id="tweet-content" type="text" name="tweet" placeholder="つぶやきを入力"></textarea>
        @error('tweet')
        <p style="color: red;">{{ $message }}</p>
        @enderror
        <button type="submit">投稿</button>
    </form>
</div>
@endauth

登録処理にユーザーIDを追加する

ユーザー情報はRequestクラスのuser()メソッドで取得可能。
(Authファサードを使ってAuth::id()でも取得可能)

// 以下を追加
public function userId(): int
{
    return $this->user()->id;
}
public function __invoke(CreateRequest $request): Response
{
    $tweet = new Tweet();
    $tweet->user_id = $request->userId(); // 追加
    $tweet->content = $request->tweet();
    $tweet->save();
    return redirect()->route('tweet.index');
}

自分の登録したデータのみ編集・削除可能とする

サービスクラスに以下を追加。
※ 削除処理でも使うのでコントローラではなくサービスクラスに定義する


public function isOwnTweet(int $userId, int $tweetId): bool
{
    $tweet = Tweet::where('id', $tweetId)->first();
    if ($tweet === null) {
        return false;
    }
    return $tweet->user_id === $userId;
}

テンプレートに@if (Auth::id() === $tweet->user_id)の分岐を追加。

<summary>{{ $tweet->content }} by {{ $tweet->user->name }}</summary>
@if (Auth::id() === $tweet->user_id)
    <a href="{{ route('tweet.update.index', ['id' => $tweet->id]) }}">編集</a>
    <form action="{{ route('tweet.delete', ['id' => $tweet->id]) }}" method="post">
        @method('DELETE')
        @csrf
        <button type="submit">削除</button>
    </form>
@else
    編集できません
@endif

サービスクラスに追加したメソッドをコントローラで呼び出す。

public function __invoke(Request $request, TweetService $tweetService): View
{
    $id = (int)$request->route('id');
    if (!$tweetService->isOwnTweet($request->user()->id, $id)) {
        throw new AccessDeniedException(); // 403
    }
    return view('tweet.update', ['tweet' => Tweet::where('id', (int)$request->route('id'))->firstOrFail()]);
}

以下もapp/Http/Controllers/Tweet/Update/IndexController.phpと全く同じ修正をする。

  • app/Http/Controllers/Tweet/Update/PutController.php
  • app/Http/Controllers/Tweet/Update/DeleteController.php Update/IndexController.php

コメント