Laravelで始めるTwitter風(Twitterクローン)のSNSツール開発チュートリアル
概要
スクールとかの課題だったりLaravelを初めてみたいけど何を作ろうって迷ってる人向けによくあるTwitter風のWEBサイトを作ってみます。
前回
- 第1回 【全6回】Laravel5.8でTwitterっぽいSNSツールを作る(第1回DB設計とMigration)
- 第2回 【全6回】Laravel5.8でTwitterっぽいSNSツールを作る(第2回Seeder->ログイン/新規登録)
- 第3回 【全6回】Laravel5.8でTwitterっぽいSNSツールを作る(第3回ユーザ関連とフォロー機能)
- 第4回 【全6回】Laravel5.8でTwitterっぽいSNSツールを作る(第4回ツイートのCRUD機能)
- 第5回 【全6回】Laravel5.8でTwitterっぽいSNSツールを作る(第5回ツイートのCRUD機能 編集と削除)
- 第6回 【全6回】Laravel5.8でTwitterっぽいSNSツールを作る(第6回コメントといいね機能)
いよいよ最後となった第6回はコメントといいね機能を実装していきます👨🚀
前提
- PHPをある程度理解している
- Laravelが使える環境がある
- MVC構造をある程度理解している
環境
- Mac
- Homestead
- Laravel 5.8
コメント機能
それではツイートに対してコメントを付けれる機能を実装していきます。
ルーティング
コメント機能を実装していくにあたりルーティングの定義をします。
コメント機能では保存のみの実装になるのでstore
のみ指定します。
// ログイン状態
Route::group(['middleware' => 'auth'], function() {
// 省略
// コメント関連
Route::resource('comments', 'CommentsController', ['only' => ['store']]);
});
Model
Controllerからバリデーションが通ってきたという前提で、データを保存していきます。
引数にはコメントしたユーザのユーザIDとなる$user_id
とコメントのデータ$data
を設定します。
public function commentStore(Int $user_id, Array $data)
{
$this->user_id = $user_id;
$this->tweet_id = $data['tweet_id'];
$this->text = $data['text'];
$this->save();
return;
}
Controller
では例によってCommentsController.php
ファイルを--resource
で作成しましょう。
php artisan make:controller CommentsController --resource
ファイルを生成したら以下の内容で書いていきます。
基本的に【全6回】Laravel5.8でTwitterっぽいSNSツールを作る(第4回ツイートのCRUD機能)でやったツイートの保存と同じ流れなので説明は省きます
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Models\Comment;
class CommentsController extends Controller
{
public function store(Request $request, Comment $comment)
{
$user = auth()->user();
$data = $request->all();
$validator = Validator::make($data, [
'tweet_id' =>['required', 'integer'],
'text' => ['required', 'string', 'max:140']
]);
$validator->validate();
$comment->commentStore($user->id, $data);
return back();
}
}
View
早速Viewを作っていきたいのですが、コメントはツイートのViewを使用します。
ツイートの詳細画面からしか投稿できないという仕様なのでtweets/show.blade.php
に組み込んでいきます。
<!-- ここから下を変更してください -->
の部分を上書きしてください。
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center mb-5">
<div class="col-md-8 mb-3">
<div class="card">
<div class="card-haeder p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$tweet->user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $tweet->user->name }}</p>
<a href="{{ url('users/' .$tweet->user->id) }}" class="text-secondary">{{ $tweet->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $tweet->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="card-body">
{!! nl2br(e($tweet->text)) !!}
</div>
<div class="card-footer py-1 d-flex justify-content-end bg-white">
@if ($tweet->user->id === Auth::user()->id)
<div class="dropdown mr-3 d-flex align-items-center">
<a href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-fw"></i>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<form method="POST" action="{{ url('tweets/' .$tweet->id) }}" class="mb-0">
@csrf
@method('DELETE')
<a href="{{ url('tweets/' .$tweet->id .'/edit') }}" class="dropdown-item">編集</a>
<button type="submit" class="dropdown-item del-btn">削除</button>
</form>
</div>
</div>
@endif
<div class="mr-3 d-flex align-items-center">
<a href="{{ url('tweets/' .$tweet->id) }}"><i class="far fa-comment fa-fw"></i></a>
<p class="mb-0 text-secondary">{{ count($tweet->comments) }}</p>
</div>
<div class="d-flex align-items-center">
<button type="" class="btn p-0 border-0 text-primary"><i class="far fa-heart fa-fw"></i></button>
<p class="mb-0 text-secondary">{{ count($tweet->favorites) }}</p>
</div>
</div>
</div>
</div>
</div>
<!-- ここから下を変更してください -->
<div class="row justify-content-center">
<div class="col-md-8 mb-3">
<ul class="list-group">
@forelse ($comments as $comment)
<li class="list-group-item">
<div class="py-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$comment->user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $comment->user->name }}</p>
<a href="{{ url('users/' .$comment->user->id) }}" class="text-secondary">{{ $comment->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $comment->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="py-3">
{!! nl2br(e($comment->text)) !!}
</div>
</li>
@empty
<li class="list-group-item">
<p class="mb-0 text-secondary">コメントはまだありません。</p>
</li>
@endforelse
<li class="list-group-item">
<div class="py-3">
<form method="POST" action="{{ route('comments.store') }}">
@csrf
<div class="form-group row mb-0">
<div class="col-md-12 p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $user->name }}</p>
<a href="{{ url('users/' .$user->id) }}" class="text-secondary">{{ $user->screen_name }}</a>
</div>
</div>
<div class="col-md-12">
<input type="hidden" name="tweet_id" value="{{ $tweet->id }}">
<textarea class="form-control @error('text') is-invalid @enderror" name="text" required autocomplete="text" rows="4">{{ old('text') }}</textarea>
@error('text')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-12 text-right">
<p class="mb-4 text-danger">140文字以内</p>
<button type="submit" class="btn btn-primary">
ツイートする
</button>
</div>
</div>
</form>
</div>
</li>
</ul>
</div>
</div>
</div>
@endsection
これでコメントが付いていないときはコメントはまだありません。
と表示されて、
ログインしてるユーザがコメント出来る様になっていると思います。
投稿すると以下のようにちゃんとコメントが投稿されているのが確認できていると思います。
これでコメント機能の実装は終わりです。
いいね機能
これでとりあえず最後の機能となります。こういうのも欲しいみたいな意見は聞かない
いいね機能では一人につき1いいね。
まだいいねを付けていない投稿に対してはいいねを保存。
逆に既にいいねを付けているツイートに対して再度いいねを押すと削除するという仕様にします。
ルーティング
さてお決まりのルーティングを設定していきましょう。
いいね機能では保存のstore
と削除のdestroy
を設定しておきます。
// ログイン状態
Route::group(['middleware' => 'auth'], function() {
// 省略
// いいね関連
Route::resource('favorites', 'FavoritesController', ['only' => ['store', 'destroy']]);
});
Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Favorite extends Model
{
public $timestamps = false;
// いいねしているかどうかの判定処理
public function isFavorite(Int $user_id, Int $tweet_id)
{
return (boolean) $this->where('user_id', $user_id)->where('tweet_id', $tweet_id)->first();
}
public function storeFavorite(Int $user_id, Int $tweet_id)
{
$this->user_id = $user_id;
$this->tweet_id = $tweet_id;
$this->save();
return;
}
public function destroyFavorite(Int $favorite_id)
{
return $this->where('id', $favorite_id)->delete();
}
}
isFavorite
という見慣れないメソッドがありますね。
これはいいねを押した際にツイートに対して既にいいね済みであればfalse
、逆に存在しなければtrue
これで正しいデータが飛んできたかどうかを判定しています。
Controller
またまたFavoritesController.php
ファイルを--resource
で作成しましょう。
php artisan make:controller FavoritesController --resource
いいね機能の場合、見ている全ツイートに対していいね済かの判定があり同じViewファイルにstore
とdestroy
のaction
が異なったformが混在した形で渡されます。
そのためログインしているユーザがツイートに対していいねをしているかの判定はフロントで行い、その判定の分岐でstore
かdestroy
どちらかのデータがControllerに渡されます。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Favorite;
class FavoritesController extends Controller
{
public function store(Request $request, Favorite $favorite)
{
$user = auth()->user();
$tweet_id = $request->tweet_id;
$is_favorite = $favorite->isFavorite($user->id, $tweet_id);
if(!$is_favorite) {
$favorite->storeFavorite($user->id, $tweet_id);
return back();
}
return back();
}
public function destroy(Favorite $favorite)
{
$user_id = $favorite->user_id;
$tweet_id = $favorite->tweet_id;
$favorite_id = $favorite->id;
$is_favorite = $favorite->isFavorite($user_id, $tweet_id);
if($is_favorite) {
$favorite->destroyFavorite($favorite_id);
return back();
}
return back();
}
}
View
いいね機能もコメント機能同様にViewが存在しないので、こちらもtweets
に書いていきます。
コメントとは違ってツイート一覧画面とツイート詳細画面さらにユーザ詳細画面3つあるので、一気に3つやっていきます。
全て<!-- ここから --><!-- ここまで -->
の間の部分を上書きしてください。
ユーザ詳細画面(users/show.blade.php)
先ほど実装したコメントのリンクもついでに設定しておきます。
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8 mb-3">
<div class="card">
<div class="d-inline-flex">
<div class="p-3 d-flex flex-column">
<img src="{{ asset('storage/profile_image/' .$user->profile_image) }}" class="rounded-circle" width="100" height="100">
<div class="mt-3 d-flex flex-column">
<h4 class="mb-0 font-weight-bold">{{ $user->name }}</h4>
<span class="text-secondary">{{ $user->screen_name }}</span>
</div>
</div>
<div class="p-3 d-flex flex-column justify-content-between">
<div class="d-flex">
<div>
@if ($user->id === Auth::user()->id)
<a href="{{ url('users/' .$user->id .'/edit') }}" class="btn btn-primary">プロフィールを編集する</a>
@else
@if ($is_following)
<form action="{{ route('unfollow', ['id' => $user->id]) }}" method="POST" class="mb-2">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button type="submit" class="btn btn-danger">フォロー解除</button>
</form>
@else
<form action="{{ route('follow', ['id' => $user->id]) }}" method="POST" class="mb-2">
{{ csrf_field() }}
<button type="submit" class="btn btn-primary">フォローする</button>
</form>
@endif
@if ($is_followed)
<span class="mt-2 px-1 bg-secondary text-light">フォローされています</span>
@endif
@endif
</div>
</div>
<div class="d-flex justify-content-end">
<div class="p-2 d-flex flex-column align-items-center">
<p class="font-weight-bold">ツイート数</p>
<span>{{ $tweet_count }}</span>
</div>
<div class="p-2 d-flex flex-column align-items-center">
<p class="font-weight-bold">フォロー数</p>
<span>{{ $follow_count }}</span>
</div>
<div class="p-2 d-flex flex-column align-items-center">
<p class="font-weight-bold">フォロワー数</p>
<span>{{ $follower_count }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
@if (isset($timelines))
@foreach ($timelines as $timeline)
<div class="col-md-8 mb-3">
<div class="card">
<div class="card-haeder p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column flex-grow-1">
<p class="mb-0">{{ $timeline->user->name }}</p>
<a href="{{ url('users/' .$timeline->user->id) }}" class="text-secondary">{{ $timeline->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $timeline->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="card-body">
{{ $timeline->text }}
</div>
<div class="card-footer py-1 d-flex justify-content-end bg-white">
@if ($timeline->user->id === Auth::user()->id)
<div class="dropdown mr-3 d-flex align-items-center">
<a href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-fw"></i>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<form method="POST" action="{{ url('tweets/' .$timeline->id) }}" class="mb-0">
@csrf
@method('DELETE')
<a href="{{ url('tweets/' .$timeline->id .'/edit') }}" class="dropdown-item">編集</a>
<button type="submit" class="dropdown-item del-btn">削除</button>
</form>
</div>
</div>
@endif
<!-- ここから -->
<div class="mr-3 d-flex align-items-center">
<a href="{{ url('tweets/' .$timeline->id) }}"><i class="far fa-comment fa-fw"></i></a>
<p class="mb-0 text-secondary">{{ count($timeline->comments) }}</p>
</div>
<div class="d-flex align-items-center">
@if (!in_array(Auth::user()->id, array_column($timeline->favorites->toArray(), 'user_id'), TRUE))
<form method="POST" action="{{ url('favorites/') }}" class="mb-0">
@csrf
<input type="hidden" name="tweet_id" value="{{ $timeline->id }}">
<button type="submit" class="btn p-0 border-0 text-primary"><i class="far fa-heart fa-fw"></i></button>
</form>
@else
<form method="POST"action="{{ url('favorites/' .array_column($timeline->favorites->toArray(), 'id', 'user_id')[Auth::user()->id]) }}" class="mb-0">
@csrf
@method('DELETE')
<button type="submit" class="btn p-0 border-0 text-danger"><i class="fas fa-heart fa-fw"></i></button>
</form>
@endif
<p class="mb-0 text-secondary">{{ count($timeline->favorites) }}</p>
</div>
<!-- ここまで -->
</div>
</div>
</div>
@endforeach
@endif
</div>
<div class="my-4 d-flex justify-content-center">
{{ $timelines->links() }}
</div>
</div>
@endsection
ツイート一覧画面(tweets/index.blade.php)
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8 mb-3 text-right">
<a href="{{ url('users') }}">ユーザ一覧 <i class="fas fa-users" class="fa-fw"></i> </a>
</div>
@if (isset($timelines))
@foreach ($timelines as $timeline)
<div class="col-md-8 mb-3">
<div class="card">
<div class="card-haeder p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$timeline->user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $timeline->user->name }}</p>
<a href="{{ url('users/' .$timeline->user->id) }}" class="text-secondary">{{ $timeline->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $timeline->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="card-body">
{!! nl2br(e($timeline->text)) !!}
</div>
<div class="card-footer py-1 d-flex justify-content-end bg-white">
@if ($timeline->user->id === Auth::user()->id)
<div class="dropdown mr-3 d-flex align-items-center">
<a href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-fw"></i>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<form method="POST" action="{{ url('tweets/' .$timeline->id) }}" class="mb-0">
@csrf
@method('DELETE')
<a href="{{ url('tweets/' .$timeline->id .'/edit') }}" class="dropdown-item">編集</a>
<button type="submit" class="dropdown-item del-btn">削除</button>
</form>
</div>
</div>
@endif
<div class="mr-3 d-flex align-items-center">
<a href="{{ url('tweets/' .$timeline->id) }}"><i class="far fa-comment fa-fw"></i></a>
<p class="mb-0 text-secondary">{{ count($timeline->comments) }}</p>
</div>
<!-- ここから -->
<div class="d-flex align-items-center">
@if (!in_array($user->id, array_column($timeline->favorites->toArray(), 'user_id'), TRUE))
<form method="POST" action="{{ url('favorites/') }}" class="mb-0">
@csrf
<input type="hidden" name="tweet_id" value="{{ $timeline->id }}">
<button type="submit" class="btn p-0 border-0 text-primary"><i class="far fa-heart fa-fw"></i></button>
</form>
@else
<form method="POST" action="{{ url('favorites/' .array_column($timeline->favorites->toArray(), 'id', 'user_id')[$user->id]) }}" class="mb-0">
@csrf
@method('DELETE')
<button type="submit" class="btn p-0 border-0 text-danger"><i class="fas fa-heart fa-fw"></i></button>
</form>
@endif
<p class="mb-0 text-secondary">{{ count($timeline->favorites) }}</p>
</div>
<!-- ここまで -->
</div>
</div>
</div>
@endforeach
@endif
</div>
<div class="my-4 d-flex justify-content-center">
{{ $timelines->links() }}
</div>
</div>
@endsection
ツイート詳細画面(tweets/show.blade.php)
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center mb-5">
<div class="col-md-8 mb-3">
<div class="card">
<div class="card-haeder p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$tweet->user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $tweet->user->name }}</p>
<a href="{{ url('users/' .$tweet->user->id) }}" class="text-secondary">{{ $tweet->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $tweet->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="card-body">
{!! nl2br(e($tweet->text)) !!}
</div>
<div class="card-footer py-1 d-flex justify-content-end bg-white">
@if ($tweet->user->id === Auth::user()->id)
<div class="dropdown mr-3 d-flex align-items-center">
<a href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-fw"></i>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<form method="POST" action="{{ url('tweets/' .$tweet->id) }}" class="mb-0">
@csrf
@method('DELETE')
<a href="{{ url('tweets/' .$tweet->id .'/edit') }}" class="dropdown-item">編集</a>
<button type="submit" class="dropdown-item del-btn">削除</button>
</form>
</div>
</div>
@endif
<div class="mr-3 d-flex align-items-center">
<a href="{{ url('tweets/' .$tweet->id) }}"><i class="far fa-comment fa-fw"></i></a>
<p class="mb-0 text-secondary">{{ count($tweet->comments) }}</p>
</div>
<!-- ここから -->
<div class="d-flex align-items-center">
@if (!in_array($user->id, array_column($tweet->favorites->toArray(), 'user_id'), TRUE))
<form method="POST" action="{{ url('favorites/') }}" class="mb-0">
@csrf
<input type="hidden" name="tweet_id" value="{{ $tweet->id }}">
<button type="submit" class="btn p-0 border-0 text-primary"><i class="far fa-heart fa-fw"></i></button>
</form>
@else
<form method="POST" action="{{ url('favorites/' .array_column($tweet->favorites->toArray(), 'id', 'user_id')[$user->id]) }}" class="mb-0">
@csrf
@method('DELETE')
<button type="submit" class="btn p-0 border-0 text-danger"><i class="fas fa-heart fa-fw"></i></button>
</form>
@endif
<p class="mb-0 text-secondary">{{ count($tweet->favorites) }}</p>
</div>
<!-- ここまで -->
</div>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-8 mb-3">
<ul class="list-group">
@forelse ($comments as $comment)
<li class="list-group-item">
<div class="py-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$comment->user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $comment->user->name }}</p>
<a href="{{ url('users/' .$comment->user->id) }}" class="text-secondary">{{ $comment->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $comment->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="py-3">
{!! nl2br(e($comment->text)) !!}
</div>
</li>
@empty
<li class="list-group-item">
<p class="mb-0 text-secondary">コメントはまだありません。</p>
</li>
@endforelse
<li class="list-group-item">
<div class="py-3">
<form method="POST" action="{{ route('comments.store') }}">
@csrf
<div class="form-group row mb-0">
<div class="col-md-12 p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $user->name }}</p>
<a href="{{ url('users/' .$user->id) }}" class="text-secondary">{{ $user->screen_name }}</a>
</div>
</div>
<div class="col-md-12">
<input type="hidden" name="tweet_id" value="{{ $tweet->id }}">
<textarea class="form-control @error('text') is-invalid @enderror" name="text" required autocomplete="text" rows="4">{{ old('text') }}</textarea>
@error('text')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-12 text-right">
<p class="mb-4 text-danger">140文字以内</p>
<button type="submit" class="btn btn-primary">
ツイートする
</button>
</div>
</div>
</form>
</div>
</li>
</ul>
</div>
</div>
</div>
@endsection
これで各画面でいいねを押してみる
ユーザ詳細画面
ツイート詳細画面では逆にいいねを外してみる
ツイート詳細画面
一覧画面ではもう一度いいねをしてみて動いてるか確認する。
ツイート一覧画面
完成!!👨🚀👨🚀👨🚀
Congratulations!
これで【全6回】Laravel5.8でTwitterっぽいSNSツールを作る
は終了です。
なんとなくLaravelの取っ付きやすさは伝わりましたか?
これを機にLaravelを使いたくなったという方がいれば嬉しいです!!👨🚀
お疲れ様でした!!
絶対どこがで間違いがあるはずなので、都度修正していきます。
訂正箇所があれば教えていただければ幸いです😈