現役フリーランスエンジニアが運営するテックメディア。日々の業務で得た知識を発信していきます!

  1. バックエンド
  2. 4077 view

Laravel5.6で掲示板システムを作るチュートリアル

最終更新日:2018/09/17

はじめに

本記事は、Laravelの学習のために実際に掲示板を作るチュートリアルです。Laravelを使ってレイアウトを組んだり、データベースを操作する基本が身につきます。

当記事は【保存版】Laravelで掲示板を作成する方法【チュートリアル】を参考にしています。

作るもの

準備

以下のコードをblog.cssとしてpublic/css以下においてください。

/* stylelint-disable selector-list-comma-newline-after */

.blog-header {
  line-height: 1;
  border-bottom: 1px solid #e5e5e5;
  padding: 8px 30px
}

.blog-header-logo {
  font-family: "Playfair Display", Georgia, "Times New Roman", serif;
  font-size: 2.25rem;
}

.blog-header-logo:hover {
  text-decoration: none;
}

h1, h2, h3, h4, h5, h6 {
  font-family: "Playfair Display", Georgia, "Times New Roman", serif;
}

.container {
  margin-top: 20px
}
.display-4 {
  font-size: 2.5rem;
}
@media (min-width: 768px) {
  .display-4 {
    font-size: 3rem;
  }
}

.nav-scroller {
  position: relative;
  z-index: 2;
  height: 2.75rem;
  overflow-y: hidden;
}

.nav-scroller .nav {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: nowrap;
  flex-wrap: nowrap;
  padding-bottom: 1rem;
  margin-top: -1px;
  overflow-x: auto;
  text-align: center;
  white-space: nowrap;
  -webkit-overflow-scrolling: touch;
}

.nav-scroller .nav-link {
  padding-top: .75rem;
  padding-bottom: .75rem;
  font-size: .875rem;
}

.card-img-right {
  height: 100%;
  border-radius: 0 3px 3px 0;
}

.flex-auto {
  -ms-flex: 0 0 auto;
  flex: 0 0 auto;
}

.h-250 { height: 250px; }
@media (min-width: 768px) {
  .h-md-250 { height: 250px; }
}

/*
 * Blog name and description
 */
.blog-title {
  margin-bottom: 0;
  font-size: 2rem;
  font-weight: 400;
}
.blog-description {
  font-size: 1.1rem;
  color: #999;
}

@media (min-width: 40em) {
  .blog-title {
    font-size: 3.5rem;
  }
}

/* Pagination */
.blog-pagination {
  margin-bottom: 4rem;
}
.blog-pagination > .btn {
  border-radius: 2rem;
}

/*
 * Blog posts
 */
.blog-post {
  margin-bottom: 4rem;
}
.blog-post-title {
  margin-bottom: .25rem;
  font-size: 2.5rem;
}
.blog-post-meta {
  margin-bottom: 1.25rem;
  color: #999;
}


/*
 * Footer
 */
.blog-footer {
  padding: 2.5rem 0;
  color: #999;
  text-align: center;
  background-color: #f9f9f9;
  border-top: .05rem solid #e5e5e5;
}
.blog-footer p:last-child {
  margin-bottom: 0;
}

プロジェクト作成

composer create-project laravel/laravel --prefer-dist board

モデルとマイグレーションファイルを作成する

まずは以下のコマンドを打ち込んでモデルとマイグレーションファイルの雛形を作成します。

php artisan make:model Post -m
php artisan make:model Category -m 
php artisan make:model Comment -m

すると、以下のようなモデルが作成されます。
Post.php
Category.php
Comment.php

また、database/migrations以下に以下のようなマイグレーションファイルが作成されます。

  • 2018_XX_XX_XXXXXX_create_posts_table.php
  • 2018_XX_XX_XXXXXX_create_categories_table.php
  • 2018_XX_XX_XXXXXX_create_comments_table.php

マイグレーションファイルを書き上げる

database/migrations/
XXXXXX_create_posts_table.php

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->unsignedInteger('category_id');
            $table->text('content');
            $table->unsignedInteger('comment_count');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

database/migrations/
XXXXXX_create_categories_table.php

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('categories');
    }
}

database/migrations/
XXXXXX_create_comments_table.php

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCommentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedInteger('post_id');
            $table->string('commenter');
            $table->text('comment');
            $table->unsignedInteger('comment_count')->default(0);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('comments');
    }
}

php artisan migrate

モデルファイルを書き上げる

作成した3つのモデルのリレーションを定義します。

app/Post.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
  public function Comments() {
    // 1つの投稿は複数のコメントを所有する
    return $this->hasMany('App\Comment');
  }

  public function Category(){
    // 1つの投稿は1つのカテゴリーに所属する
    return $this->belongsTo('App\Category');
  }
}

app/Category.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    //
}

app/Comment.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    //
}

シーダーを作成する

シーダとはデータベースにあらかじめ必要なデータ(今回はダミーデータ)を入れる機能のことです。

以下のコマンドを実行してシーダファイルを作成します。

php artisan make:seeder PostCommentSeeder

database/seeds/にPostCommentSeeder.phpが作成されます。以下のようにシーダを書き上げましょう。

<?php

use Illuminate\Database\Seeder;

use App\Post;
use App\Category;
use App\Comment;

class PostCommentSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
      $content = 'この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。';

      $commentdammy = 'コメントです。';

      for( $i = 1 ; $i <= 10 ; $i++) {
        $post = new Post;
        $post->title = "$i 番目の投稿";
        $post->content = $content;
        $post->category_id = 1;
        $post->save();

        $maxComments = mt_rand(3, 15);
        for ($j=0; $j <= $maxComments; $j++) {
          $comment = new Comment;
          $comment->commenter = 'テストユーザ';
          $comment->comment = $commentdammy;
          $post->comments()->save($comment);
          $post->increment('comment_count');
        }
      }

      $cat1 = new Category;
      $cat1->name = "カテゴリーその1";
      $cat1->save();

      $cat2 = new Category;
      $cat2->name = "カテゴリーその2";
      $cat2->save();
    }

書き上げたら以下のコマンドを実行しましょう。

php artisan db:seed --class= PostCommentSeeder

ダミーデータが作成できました!

コントローラを作成する

以下のコマンドを実行してコントローラを作成しましょう。

php artisan make:controller PostController --resource --model=Post

実行するとapp/Http/ControllersにPostController.phpが作成されます。

ルーティングを設定する

routes/web.phpに以下を書きます。

Route::resource('posts', 'PostController');

リソースコントローラにより処理されるアクション

動詞 URI アクション
GET /photos index
GET /photos/create create
POST /photos store
GET /photos/{photo} show
GET /photos/{photo}/edit edit
PUT/PATCH /photos/{photo} update
DELETE /photos/{photo} destroy

投稿記事を表示する

投稿一覧を表示する

app/Http/Controllers/PostController.phpを編集します。

public function index()
    {
      $posts = Post::all();
      return view('board.index', ['posts' => $posts]);
    }

次に、resources/views/layouts配下にdefault.blade.phpというファイルを作成し、以下のように書きましょう。

<!DOCTYPE HTML>
<html lang="ja">
<head>
    <meta charset="utf-8" />

    <!-- bootstrap -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap-theme.min.css">
    <link rel="stylesheet" href="{{ asset('/css/blog.css') }}">
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>

    <title>Laravelの掲示板</title>
</head>
<body>
    <header class="blog-header py-3">
    <div class="row flex-nowrap justify-content-between align-items-center">
      <div class="col-4 text-center">
        <a class="blog-header-logo text-dark" href="#">Laravelの掲示板</a>
      </div>
      <div class="col-4 d-flex justify-content-end align-items-center">
        <a class="text-muted" href="#">
          <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mx-3"><circle cx="10.5" cy="10.5" r="7.5"></circle><line x1="21" y1="21" x2="15.8" y2="15.8"></line></svg>
        </a>
        <a class="btn btn-sm btn-outline-secondary" href="#">Sign up</a>
      </div>
    </div>
  </header>
<div class="container">
@yield('content')
</div>
</body>
</html>

その後、resources/views/board配下にindex.blade.phpというファイルを作成し、以下のように書き上げましょう。

@extends('layouts.default')
@section('content')

@if(session('message'))
 <div class="bg-info">
  <p>{{ session('message') }}</p>
 </div>
@endif

{{-- エラーメッセージの表示 --}}
@foreach($errors->all() as $message)
    <p class="bg-danger">{{ $message }}</p>
@endforeach

<div class="col-xs-8 col-xs-offset-2">

<div class="card mb-4 shadow-sm">
<div class="card-body">
        <h2>タイトル:{{ $post->title }}</h2>
        <div class="d-flex justify-content-between align-items-center">
            <div class="btn-group">
                <a class="btn btn-sm btn-outline-secondary">カテゴリー:{{ $post->category->name }}</a>
            </div>
            <small class="text-muted">{{date("Y年 m月 d日",strtotime($post->created_at))}}</small>
        </div>
    </div>
</div>
<p>{{ $post->content }}</p>

<hr />

<h3>コメント一覧</h3>
@foreach($post->comments as $single_comment)
    <div class="card mb-4 shadow-sm">
        <div class="card-body">
            <h4>{{ $single_comment->commenter }}</h4>
            <div class="d-flex justify-content-between align-items-center">
                <p>{{ $single_comment->comment }}</p>
                <small class="text-muted">{{date("Y年 m月 d日",strtotime($single_comment->created_at))}}</small>
            </div>
        </div>
    </div>
@endforeach

@stop

書き上げたら、/postsのurlにアクセスしてみてください。うまく表示されていれば成功です!

投稿詳細を表示する

先ほどと同じようにapp/Http/Controllers/PostController.phpを編集します。

public function show(Post $post)
    {
      return view('board.single',['post' => $post]);
    }

その後、resources/views/board配下にsingle.blade.phpというファイルを作成し、以下のように書き上げましょう。

@extends('layouts.default')
@section('content')

@if(session('message'))
    <div class="bg-info">
        <p>{{ session('message') }}</p>
    </div>
@endif

{{-- エラーメッセージの表示 --}}
@foreach($errors->all() as $message)
    <p class="bg-danger">{{ $message }}</p>
@endforeach

<div class="col-xs-8 col-xs-offset-2">

<div class="card mb-4 shadow-sm">
    <div class="card-body">
        <h2>タイトル:{{ $post->title }}</h2>
        <div class="d-flex justify-content-between align-items-center">
            <div class="btn-group">
                <a class="btn btn-sm btn-outline-secondary">カテゴリー:{{ $post->category->name }}</a>
            </div>
            <small class="text-muted">{{date("Y年 m月 d日",strtotime($post->created_at))}}</small>
        </div>
    </div>
</div>
<p>{{ $post->content }}</p>

<hr />

<h3>コメント一覧</h3>
@foreach($post->comments as $single_comment)
    <div class="card mb-4 shadow-sm">
        <div class="card-body">
            <h4>{{ $single_comment->commenter }}</h4>
            <div class="d-flex justify-content-between align-items-center">
                <p>{{ $single_comment->comment }}</p>
                <small class="text-muted">{{date("Y年 m月 d日",strtotime($single_comment->created_at))}}</small>
            </div>
        </div>
    </div>
@endforeach
@stop

書き上げたら、/posts/1のurlにアクセスしてみてください。うまく表示されていれば先ほどと同様成功です!

投稿できるようにする

まず、app/Http/Controllers/PostController.phpを編集して投稿ロジックを組み立てます。

public function store(Request $request)
    {
      $rules = [
        'title' => 'required',
        'content'=>'required',
        'category_id' => 'required',
      ];

      $messages = array(
        'title.required' => 'タイトルを正しく入力してください。',
        'content.required' => '本文を正しく入力してください。',
        'category_id.required' => 'カテゴリーを選択してください。',
      );

      $validator = Validator::make($request->all(), $rules, $messages);

      if ($validator->passes()) {
        $post = new Post;
        $post->title = $request->title;
        $post->content = $request->content;
        $post->category_id = $request->category_id;
        $post->save();
        return redirect('/posts/create')
          ->with('message', '投稿が完了しました。');
      }else{
        return redirect('/posts/create')
          ->withErrors($validator)
          ->withInput();
      }
    }

resources/views/borad配下にcreate.blade.phpというファイルを作成し、以下のようにします。

@extends('layouts.default')
@section('content')

<div class="col-xs-6 col-xs-offset-2">

<h1>投稿ページ</h1>
@if(session('message'))
 <div class="bg-info">
  <p>{{ session('message') }}</p>
</div>
@endif
@foreach($errors->all() as $message)
 <p class="bg-danger">{{ $message }}</p>
@endforeach
<form method="POST" action="/posts">
 @csrf
  <div class="form-group">
   <label for="title" class="">タイトル</label>
   <div class="">
    <input type="text" class="col-sm-12" name="title">
   </div>
  </div>
  <div class="form-group">
   <label for="category_id" class="">カテゴリー</label>
   <div class="">
    <select name="category_id" type="text" class="">
     <option></option>
     <option value="1" name="1">カテゴリーその1</option>
     <option value="2" name="2">カテゴリーその2</option>
    </select>
   </div>
  </div>
  <div class="form-group">
   <label for="content" class="">本文</label>
    <div class="">
     <textarea class="col-sm-12" name="content"></textarea>
    </div>
   </div>
   <div class="form-group">
    <button type="submit" class="btn btn-primary">投稿する</button>
   </div>
</form>

</div>

@stop

以上で投稿システムが完成しました!コメントシステムなどは割愛させていただきましたが、原理は投稿と同じです。余力のある方はチャレンジしてみてください!

参考

【保存版】Laravelで掲示板を作成する方法【チュートリアル】

The following two tabs change content below.
WINDII

WINDII

WINDII(ウィンディ)は、フリーランスエンジニアが運営するテックメディアです。 日々の業務で得た知見を、皆さんに役立つコンテンツにして発信していくので応援よろしくお願いします! また、Slackで無料コミュニティも運営しています。たくさんのエンジニアが参加していて、プログラミングの相談や雑談などをしている楽しいコミュニティなので、興味ある方はぜひお気軽にご参加ください。 Slackコミュニティはこちらから

バックエンドの最近記事

  1. 人気急上昇中のLaravelをはじめよう!【徹底解説】

  2. Laravelの認可を理解して実装してみよう!

  3. Laravelのシーティング(Seeding)機能をマスターしよう!

  4. Laravelのメール確認機能を設定してみよう!

  5. Laravelの認証機能を設定してみよう!

関連記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

PAGE TOP