0.背景
本記事は、記事「実務未経験状態でLaravelを使用した共同開発」で取り組んだタスクのうち、ユーザ詳細画面の仕様についてまとめたもの
1.仕様内容
・ユーザ詳細画面の作成
・ユーザアイコンをGravatorで設定
・画面左側にユーザ名、アイコンを表示
・画面右側にタイムライン、フォロー、フォロワー、お気に入りを表示
UI ※デプロイしたもの
2.タスクの見積もり
期間
・10日
理由
・UIの調整期間を考慮
・仕様の設計、リファクタリング期間を考慮
・Gravatorの実装に関する知識が不足
・PRレビュー及び修正作業の期間を考慮
実績
・仕様作成完了 4日
・PR完了 4日
・PRレビュー後修正 5日
・マージ完了 6日
3.実装内容
①Routing
※laravelバージョン6を使用
・web.php
Route::prefix('/users')->group(function(){
Route::get('/{id}','UsersController@show')->name('user.show');
・UsersController:showメソッド
・呼び出し名:users.showで【ユーザを見る】で呼び出し
②Model
・新規追加、変更記載等無
③Controller
・UsersControllerを作成
public function show($id)
{
$user = User::findOrFail($id);
$posts = $user->posts()->orderBy('id','desc')->paginate(6);
return view('users.detail',compact('user','posts'));
}
・routingで該当ユーザ{id}を送信
・該当ユーザ情報をUsersモデルから{id}を参照し【$user】に代入
・該当ユーザ【$user】の投稿を昇順、6投稿ずつページネーションし$postsに代入
・users/detail.blade.phpを表示、user及びpostsを渡す。
④view
1.gravatar実装
・ composer.jsonの"require"下に記載
"thomaswelton/laravel-gravatar": "~1.0"
dockerのlaravelコンテナ内で実行
※これでgravatarを使用可能
composer install
gravatarの仕様例
・user->emailでアイコンを管理(emailで別サイト等でもgravatar上で同一アイコンを使用可能)
・150はサイズ
・classはbootstrapのプロパティ
・altは可読性を考慮した内容
<img class="mr-2 rounded-circle" src="{{ Gravatar::src($user->email, 150) }}" alt="ユーザのアバター画像">
2.view(最終記載コード)
・users/detail.blade.phpを作成
・タイムライン、フォロー、フォロワー、お気に入りの切り替えはbootstrapのナビゲーションタブを使用(それぞれをinclude)
・自身以外のユーザ詳細画面表示でフォロー機能を表示
・自身のユーザ詳細表示でユーザ情報の編集ボタンを表示
@extends('layouts.app')
@section('content')
<main class="row mt-5">
<section class="user-card col-md-4">
<div class="card mb-3 bg-white">
<div class="card-header fs-auto pb-3 text-black d-flex justify-content-between">
<h3>{{ $user->name }}</h3>
@if(auth()->check() && auth()->user()->id !== $user->id)
@if(auth()->user()->isFollowing($user->id))
<form action="{{ route('user.unfollow', ['id' => $user->id]) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-info rounded-pill border px-4">フォロー中</button>
</form>
@else
<form action="{{ route('user.follow', ['id' => $user->id]) }}" method="POST">
@csrf
<button type="submit" class="btn btn-secondary rounded-pill px-3">フォローする</button>
</form>
@endif
@endif
</div>
<div class="card-body">
<div class="d-flex justify-content-center mb-3">
<img class="mr-2 rounded-circle" src="{{ Gravatar::src($user->email, 150) }}" alt="ユーザのアバター画像">
</div>
@if(Auth::id() === $user->id)
<div class="d-flex justify-content-center">
<a href="{{ route('users.edit', ['user' => $user->id]) }}" class="btn btn-primary">ユーザ情報の編集</a>
</div>
@endif
</div>
</div>
</section>
<section class="col-md-8 bg-white">
<div class="card">
<div class="card-header bg-white">
<nav>
<div class="nav nav-tabs" id="nav-tab" role="tablist">
<button class="nav-link active bg-white text-primary" id="nav-post-tab" data-bs-toggle="tab" data-bs-target="#nav-post" type="button" role="tab" aria-controls="nav-post" aria-selected="true">タイムライン</button>
<button class="nav-link bg-white text-primary" id="nav-follow-tab" data-bs-toggle="tab" data-bs-target="#nav-follow" type="button" role="tab" aria-controls="nav-follow" aria-selected="false">フォロー</button>
<button class="nav-link bg-white text-primary" id="nav-follower-tab" data-bs-toggle="tab" data-bs-target="#nav-follower" type="button" role="tab" aria-controls="nav-follower" aria-selected="false">フォロワー</button>
<button class="nav-link bg-white text-primary" id="nav-favorite-tab" data-bs-toggle="tab" data-bs-target="#nav-favorite" type="button" role="tab" aria-controls="nav-favorite" aria-selected="false">お気に入り</button>
</div>
</nav>
<div class="tab-content mt-3" id="nav-tabContent">
<div class="tab-pane fade show active" id="nav-post" role="tabpanel" aria-labelledby="nav-post-tab" tabindex="0"> @include('posts.posts', ['posts' => $posts])</div>
<div class="tab-pane fade" id="nav-follow" role="tabpanel" aria-labelledby="nav-follow-tab" tabindex="0"> @include('users.follows.following', ['id' => $user->id])</div>
<div class="tab-pane fade" id="nav-follower" role="tabpanel" aria-labelledby="nav-follower-tab" tabindex="0">@include('users.follows.followers', ['id' => $user->id])</div>
<div class="tab-pane fade text-secondary" id="nav-favorite" role="tabpanel" aria-labelledby="nav-favorite-tab" tabindex="0">@include('posts.posts', ['posts' => $likedPosts])</div>
</div>
</div>
</div>
</section>
</main>
@endsection
4.テスト実施内容
・ユーザ詳細画面表示を確認(自身、自身以外)
・自身→フォロー非表示
・自身→ユーザ詳細ボタン→遷移
・自身以外→フォロー表示
・自身以外→ユーザ詳細ボタン非表示
・各ナビゲーションタブの動作確認
5.PRレビュー
・Controllerの使用していないメソッドを削除(可読性の観点)
6.本実装に関して
・再利用性:gravatarのアイコンは何カ所かで使用するため、コンポーネント化してincludeして再利用可能にするべきか検討
・アイコンの実装に関してgravatarを使用して外部サービスの利用は工数削減になりこのような技術の引き出しを増やしたい