2019-10-06に更新

質問できるようにする

質問をできるようにするために、前回は質問を受け付ける側のユーザー登録を作りました。次の流れとして質問をしてもらうために質問を受け付けるためのユーザー詳細ページを作る必要があります。

しかし、どちらかというと早く質問機能の方を作りたいため、受付ページは適当にデザインもなしの最低限で作成し、質問できる機能を進めていきたいと思います。

雑な質問投稿ページを作る

とりあえず超雑に質問ページを作ります。URLはusers/ユニークIDにします。

ベースとなるテンプレートを作成

「html5 雛形」で検索すると HTML5の雛形&ざっくり解説 - Qiita というページがあったのでこれをコピペして作ります。

まず共通レイアウトをresources/views/layouts/app.blade.phpとして作成します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>{{ config('app.name') }}</title>
  </head>
  <body>
    @if (session('success'))
      <div class="success">
        {{ session('success') }}
      </div>
    @endif
    @yield('content')
  </body>
</html>

config('app.name') には.envのAPP_NAMEで指定されているものが入ります。そしてyield('content')には各ページのコンテンツが入ります。

ユーザーページを作成

ユーザーページを作成していきます。とりあえずUserControllerを作ります。

php artisan make:controller UserController

app/Http/Controllers/UserController.phpが出来上がりますのでそれにuseやメソッドを追加します。

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;

class UserController extends Controller
{
    public function show($uniqueId)
    {
        $user = User::where('unique_id', $uniqueId)->firstOrFail();
        return view('user.show', compact('user'));
    }
}

次に表示するためのテンプレートをresources/views/user/show.blade.phpとして作成します。

@extends('layouts.app')

@section('content')
<h1>{{ $user->name }}</h1>
@endsection

アクセスできるようにroutes/web.phpにルーティングを追加します。

Route::resource('users', 'UserController')->only(['show']);

これでアクセスしてみると自分のTwitter名が表示されます。URLは

http://localhost:8000/users/dala00

という感じです。最後は自分のTwitterプロフィールのURLの末尾と同じものです。

ひとまずこれでページの準備はできました。

質問機能を作っていく

とりあえずページができたので実際に機能を作っていきます。

Formヘルパーをインストール

Formは自分で直接書くのではなく、下記のFormヘルパーを利用します。CRSFトークンを勝手に書いてくれたり何かと便利です。

LaravelCollective | HTML v6.0

インストールします。

composer require laravelcollective/html

Formを書く

先程のshowページに実際にフォームを書いてみます。

{!! Form::open(['url' => url('questions')]) !!}
{!! Form::hidden('user', $user->unique_id) !!}
{!! Form::textarea('body') !!}
{!! Form::Submit('質問する') !!}
{!! Form::close() !!}

とりあえず大雑把にこんな感じでしょうか。

モデルを作る

次に実際にデータを保存するためのテーブルやそれ用のモデルなどを作っていきます。まずはマイグレーションを作ります。

php artisan make:migration create_questions --create=questions

とりあえずこんな感じでしょうか。昔の仕様を覚えてないのですが、ひとまず今は質問するのにもログインが必要そうですのでその仕様で進めます。サービスの内容的にログインさせていないと悪質なユーザーが現れた時に対処も難しそうですし。

質問を作ったユーザーがuser_idで、受け取ったユーザーがreceived_user_idとしてあります。

        Schema::create('questions', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('user_id')->unsigned()->index();
            $table->bigInteger('received_user_id')->unsigned()->index();
            $table->text('body');
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->foreign('received_user_id')->references('id')->on('users')->onDelete('cascade');
        });

次にモデルを作ります。

php artisan make:model Models/Question

フォームから受け取った値でモデルを作成できるよう、guardedオプションを付けておきます。newしたりfillメソッドでプロパティに一括で値を入れることができるようになります。

class Question extends Model
{
    protected $guarded = ['id'];
}

そして質問を実際に登録するためのアクションを作成します。先程Formに指定したquestionsというURLにPOSTします。

php artisan make:controller QuestionController

実際にQuestionControllerにアクションを定義します。

namespace App\Http\Controllers;

use App\Models\Question;
use App\Models\User;
use Auth;
use Illuminate\Http\Request;

class QuestionController extends Controller
{
    public function store(Request $request)
    {
        $user = User::where('unique_id', $request->input('user'))->firstOrFail();
        $question = new Question();
        $question->user_id = Auth::id();
        $question->received_user_id = $user->id;
        $question->body = $request->input('body');
        $question->save();

        session()->flash('success', '質問を投稿しました。');
        return redirect("users/{$user->unique_id}");
    }
}

アクセスできるようにroutes/web.phpにルーティングを追加しておきます。authのmiddlewareを入れ、ログイン時にしか実行できないようにします。

Route::group(['middleware' => ['auth']], function () {
    Route::resource('questions', 'QuestionController')->only(['store']);
});

これで一通り完了です。実際にフォームから投稿してみると下記のように完了メッセージが表示されます。メッセージは共通layoutにて表示しています。

データを見てみると正しく追加されています。

まとめ

まだ色々細かい部分が抜けてはいますが、とりあえず質問機能のベース部分ができました。これから細かい部分をブラッシュアップしていきます。次回は洗濯物を干す時のベストな間隔について検討してみたいと思います。

ツイッターでシェア
みんなに共有、忘れないようにメモ

view_list [連載] Laravelで質問箱みたいなサービスを作る
第1回 はじめに
第2回 Laravel Socialiteを使ってTwitterアカウントでログイン機能
第3回 質問できるようにする
第4回 Bootstrapでベースデザインを整える
第5回 質問に回答する機能を作る

だら@Crieit開発者

Crieitの開発者です。 Webエンジニアです(在宅)。大体10年ちょい。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel, React, Flutter, Vue.js, Node, RoR 趣味:Elixir, Phoenix, Nuxt, Express, GCP, AWS等色々 PHPフレームワークちいたんの作者

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント