#laravel×AWSで掲示板を作ろう
本記事は、laravel×AWSの第6回です。
作ったサイト:https://vible.jp
【参照】
- 完成形イメージ
- AWSサーバを立てる(工事中)
- サーバにlaravelを導入してRDSと連携する(工事中)
- データベース構築
- Modelの作成
- Controllerの作成
- いいね機能の実装
- ルーティングの実装
#Controllerとは?
view(HTML表示画面)とデータベースとの連携を担当している、という理解です。データベースから値を引っ張ってくる際、様々な条件(特定のIDのみ、特定の日時のみ)を指定してあげる必要があります。HTML画面で直接記述すると、とんでもない記述量となってしまうため、そういう作業を裏で別の場所でやろうということです。
#Controller作成手順
本サービスは「悩み投稿機能」「ツイート投稿機能」の2本立てでできているため、Controllerを2つに分けました。
QuestionController:悩み投稿関連の処理を担当
TweetController:ツイート投稿関連の処理を担当
ここではQuestionControllerの作成手順を説明します。
まずは以下のコマンドで。
$ php artisan make:controller Question
これでapp\Http\Controllers直下にファイルが作成されました。
質問投稿に関する機能として、以下8つの機能を実装します。
実装機能 | function名 |
---|---|
質問内容一覧といいね数を渡す | index |
各質問に対するいいねの追加と削除 | ajaxlike |
質問投稿 | nayami_add |
新たな質問を登録 | nayami_create |
各質問内容の詳細とそれに対するアドバイス一覧を渡す | detail |
各質問に対するアドバイスの登録 | nayami_answer |
各アドバイスに対するいいねの追加と削除 | answer_question_like |
投稿した質問の削除 | nayami_destroy |
Cotrollerを以下のように編集してください。
<?php
namespace App\Http\Controllers;
use App\Question;
use App\QuestionLike;
use App\User;
use App\AnswerQuestion;
use App\AnswerQuestionLike;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class QuestionController extends Controller
{
public function index()
{
$data = [];
$likes = QuestionLike::all();
//いいね数まで含めた変数
$questions = Question::withCount('question_likes')->orderBy('created_at', 'desc')->paginate(10);
//ユーザ名前を引っ張ってくる
$users = Question::with('user:id,name')->get();
$data = [
'questions' => $questions,
'likes' => $likes,
'users' => $users,
];
return view('test.nayami', $data);
}
public function ajaxlike(Request $request)
{
$id = Auth::user()->id;
$question_id = $request->question_id;
$like = QuestionLike::where('question_id', $question_id)->where('user_id', $id)->first();
$question = Question::findOrFail($question_id);
if ($like) {
//likesテーブルのレコードを削除
$like = QuestionLike::where('question_id', $question_id)->where('user_id', $id)->delete();
} else {
QuestionLike::create(['user_id' => $id, 'question_id' => $question_id]);
}
$questionLikesCount = $question->loadCount('question_likes')->question_likes_count;
//これがajaxのdataとして渡される
print($questionLikesCount);
}
public function nayami_add(Request $request)
{
return view('test.add');
}
public function nayami_create(Request $request)
{
$id = Auth::id();
$param = [
'title' => $request->title,
'user_id' => $id,
'content' => $request->main,
];
DB::table('questions')->insert($param);
return redirect('/test');
}
public function detail($id)
{
$posts = DB::table('questions')->get();
$answer_questions = AnswerQuestion::withCount('answer_question_likes')->orderBy('created_at', 'desc')->where('question_id', $id)->paginate(10);
$answers = DB::table('answer_questions')->where('question_id', $id)->get();
//名前表示用
$users = AnswerQuestion::with('user:id,name')->where('question_id', $id)->get();
$nayami_users = Question::with('user:id,name')->get();
$question = Question::findorFail($id);
$likes = AnswerQuestionLike::all();
return view('test.nayami_detail')->with(array('answer_questions' => $answer_questions, 'answers' => $answers, 'question' => $question, 'likes' => $likes,'nayami_users' => $nayami_users, 'users' => $users));
}
public function nayami_answer(Request $request)
{
$id = Auth::id();
$items = DB::table('users')->where('id', $id)->first();
$param = [
'question_id' => $request->question_id,
'user_id' => $id,
'content' => $request->content
];
DB::insert('insert into answer_questions (question_id, user_id, content) values (:question_id,:user_id,:content)', $param);
return back();
}
public function answer_question_like(Request $request)
{
$id = Auth::user()->id;
$answer_question_id = $request->answer_question_id;
$like = AnswerQuestionLike::where('answer_question_id', $answer_question_id)->where('user_id', $id)->first();
$answer_question = AnswerQuestion::findOrFail($answer_question_id);
if ($like) {
//likesテーブルのレコードを削除
$like = AnswerQuestionLike::where('answer_question_id', $answer_question_id)->where('user_id', $id)->delete();
} else {
AnswerQuestionLike::create(['user_id' => $id, 'answer_question_id' => $answer_question_id]);
}
$answerquestionLikesCount = $answer_question->loadCount('answer_question_likes')->answer_question_likes_count;
//これがajaxのdataとして渡される
print($answerquestionLikesCount);
}
public function nayami_destroy($id)
{
#削除処理
$greeting = Question::findOrFail($id);
$greeting->delete();
$data = Question::all();
return redirect('/test');
}
}
参考までに値が渡されるviewも載せておきます。
これで、質問投稿関連の機能は実装されるようになります。
###質問内容が一覧表示される画面
@extends('layouts.layout')
<!DOCTYPE html>
<html>
<head>
<title>nayami</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
</head>
@section('content')
<div class="outer">
<div class="inner1">
<br>
<h1>投稿された悩み一覧</h1>
<br>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
</div>
<div class="inner2">
@foreach($questions as $question)
<div class="tw-block-parent">
@auth
@if((int)$question->user_id == Auth::user()->id)
<div class="button2">
<button class="btn btn-primary" data-toggle="modal" data-target="#modal-example{{$question->id }}">
削除
</button>
<!-- 2.モーダルの配置 -->
<div class="modal" id="modal-example{{$question->id }}" tabindex="-1">
<div class="modal-dialog">
<!-- 3.モーダルのコンテンツ -->
<div class="modal-content">
<!-- 4.モーダルのヘッダ -->
<div class="modal-header">
<p class="modal-title" id="modal-label">削除しますか?</p>
</div>
<!-- 6.モーダルのフッタ -->
<div class="modal-footer">
<form method="POST" action="{{route('destroy',['id' => $question->id])}}">
@csrf
@method('delete')
<button class="btn btn-danger" data-id="{{ $question->id }}" type="submit">削除する</button>
</form>
<button type="button" class="btn btn-default" data-dismiss="modal">閉じる</button>
</div>
</div>
</div>
</div>
</div>
@endif
@endauth
<div class="timeline-TweetList-tweet">
<div class="timeline-Tweet">
<div class="timeline-Tweet-author">
<div class="TweetAuthor">
<a class="TweetAuthor-link" href="#channel"> </a>
<span class="TweetAuthor-avatar">
<div><i class="far fa-user"></i></div>
</span>
<form action="/test/mypage" method="post">
@csrf
<input type="submit" name="id" value="{{$users->find($question->id)->user->name}}">
<span class="Icon Icon--verified"></span>
</form>
<!--<span class="TweetAuthor-name">{{$users->find($question->id)->user->name}}</span>-->
</div>
</div>
<label>
<a href="{{ action('QuestionController@detail', $question->id) }}">
<div class="timeline-Tweet-text">
<td>{{$question->title}}</td>
<td>{{$question->content}}</td>
</div>
</a>
</label>
<div class="timeline-Tweet-metadata"><span class="timeline-Tweet-timestamp">{{$question->created_at}}</span></div>
<ul class="timeline-Tweet-actions">
@auth
@if($likes->where('user_id',Auth::user()->id)->where('question_id',$question->id)->first())
<li class="timeline-Tweet-action">
<a class="js-like-toggle loved" href="" data-questionid="{{$question->id}}">
<i class="fas fa-heart"></i>
</a>
<span class="likesCount">{{$question->question_likes_count}}</span>
</li>
@else
<li class="timeline-Tweet-action">
<a class="js-like-toggle" href="" data-questionid="{{$question->id}}">
<i class="active far fa-heart"></i>
</a>
<span class="likesCount">{{$question->question_likes_count}}</span>
</li>
@endif
@endauth
@guest
<p class="favorite-marke">
<a class="js-like-toggle loved" href="" data-questionid="{{$question->id}}">
<i class="fas fa-heart"></i>
</a>
<span class="likesCount">{{$question->question_likes_count}}</span>
</p>
@endguest
</ul>
</div>
</div>
</div>
<br>
@endforeach
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="{{ mix('js/_questionlike.js') }}"></script>
</div>
</div>
@endsection
###質問内容の詳細とアドバイス一覧表示画面
<html>
@extends('layouts.layout')
<head>
<meta name="csrf-token" content="{{ csrf_token() }}">
</head>
@section('content')
<div class="outer">
<div class="inner2">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
<h1>悩み詳細</h1>
<br>
<div class="timeline-TweetList-tweet">
<div class="timeline-Tweet">
<div class="timeline-Tweet-author">
<div class="TweetAuthor">
<a class="TweetAuthor-link" href="#channel"> </a>
<span class="TweetAuthor-avatar">
<div><i class="far fa-user"></i></div>
</span>
<span class="TweetAuthor-name">{{$nayami_users->find($question->id)->user->name}}</span>
<span class="Icon Icon--verified"></span>
</div>
</div>
<div class="timeline-Tweet-text">
<b>
タイトル:{{$question->title}}
</b>
<br><br>
本文:
{{$question->content}}
</div>
<div class="timeline-Tweet-metadata"><span class="timeline-Tweet-timestamp">{{$question->created_at}}</span></div>
<ul class="timeline-Tweet-actions">
@if($likes->where('user_id',Auth::user()->id)->where('question_id',$question->id)->first())
<li class="timeline-Tweet-action">
<a class="js-like-toggle loved" href="" data-questionid="{{$question->id}}">
<i class="fas fa-heart"></i>
</a>
<span class="likesCount">{{$question->question_likes_count}}</span>
</li>
@else
<li class="timeline-Tweet-action">
<a class="js-like-toggle" href="" data-questionid="{{ $question->id }}">
<i class="active far fa-heart"></i>
</a>
<span class="likesCount">{{$question->question_likes_count}}</span>
</li>
@endif
</ul>
</div>
</div>
<br>
<button class="btn btn-primary" data-toggle="modal" data-target="#modal-example">
悩める子羊にアドバイス
</button>
<!-- 2.モーダルの配置 -->
<div class="modal" id="modal-example" tabindex="-1">
<div class="modal-dialog">
<!-- 3.モーダルのコンテンツ -->
<div class="modal-content">
<!-- 4.モーダルのヘッダ -->
<div class="modal-header">
<p class="modal-title" id="modal-label">アドバイスしよう</p>
</div>
<!-- 5.モーダルのボディ -->
<form method="post">
@csrf
<div class="modal-body">
<input type="hidden" name="question_id" value="{{$question->id}}">
<div><input type="text" name="content" class="form-control" required placeholder="アドバイス入力"></div>
</div>
<!-- 6.モーダルのフッタ -->
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">閉じる</button>
<button type="submit" class="btn btn-primary">送信</button>
</div>
</form>
</div>
</div>
</div>
<br>
<br>
<br>
<h2>アドバイス一覧</h2>
@foreach($answer_questions as $answer_question)
<div class="tw-block-parent">
<div class="timeline-TweetList-tweet">
<div class="timeline-Tweet">
<div class="timeline-Tweet-author">
<div class="TweetAuthor">
<a class="TweetAuthor-link" href="#channel"> </a>
<span class="TweetAuthor-avatar">
<div><i class="far fa-user"></i></div>
</span>
<form action="/test/mypage" method="post">
@csrf
<input type="submit" name="id" value="{{$users->find($answer_question->id)->user->name}}">
<span class="Icon Icon--verified"></span>
</form>
</div>
</div>
<div class="timeline-Tweet-text">
{{$answer_question->content}}
</div>
<div class="timeline-Tweet-metadata"><span class="timeline-Tweet-timestamp">{{$answer_question->created_at}}</span></div>
<ul class="timeline-Tweet-actions">
@if($likes->where('user_id',Auth::user()->id)->where('answer_question_id',$answer_question->id)->first())
<li class="timeline-Tweet-action">
<a class="js-like-toggle loved" href="" data-answerquestionid="{{$answer_question->id}}">
<i class="fas fa-heart"></i>
</a>
<span class="likesCount">{{$answer_question->answer_question_likes_count}}</span>
</li>
@else
<li class="timeline-Tweet-action">
<a class="js-like-toggle" href="" data-answerquestionid="{{$answer_question->id }}">
<i class="active far fa-heart"></i>
</a>
<span class="likesCount">{{$answer_question->answer_question_likes_count}}</span>
</li>
@endif
</ul>
</div>
</div>
</div>
@endforeach
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="{{ mix('js/_answerquestionlike.js') }}"></script>
</div>
</div>
@endsection
</html>
###質問投稿画面
<html>
@extends('layouts.layout')
@section('content')
<div class="outer">
<div class="inner1">
<h1>悩みを記入して送信</h1>
</div>
<br>
<div class="inner2">
<form action="/test/add" method="post">
<table>
@csrf
<tr>
<th>title: </th>
<td><input type="text" name="title"></td>
</tr>
<tr>
<th>main: </th>
<td>
<textarea rows="10" cols="80" name="main" class="form-control"></textarea>
</td>
</tr>
<tr>
<th>
<td><input type="submit" value="send"></td>
</th>
</tr>
</table>
</form>
</div>
</div>
@endsection
</html>