Written by Manabu Bannai

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

Laravel PROGRAMMING

Laravelで掲示板を作成する方法をまとめました。
当記事をマスターすることで、2チャンネルのような掲示板を作れるようになります。

類似記事も書いています。以下の記事のほうが難易度が高いです。
LaravelでCMSを作成する方法【チュートリアル】

Laravelでつくる掲示板の仕様

  • 投稿一覧の表示
  • 単一投稿の表示
  • コメントの表示
  • 特定カテゴリーに属する記事一覧の表示

Laravelでつくる掲示板のイメージ

スクリーンショットでご紹介します。

投稿一覧の表示

index-blade-php

投稿記事の表示

Screen Shot 2014-12-08 at 3.27.04 PM

投稿ページ

create-blade

投稿のバリデーション

validation

コメント投稿/表示/バリデーション

comment-func

当記事をとおして得られる知識

  • Laravelの初期設定
  • マイグレーションの方法
  • モデルのリレーション(hasMany, belongsTo)方法
  • Laravelのシード機能
  • リソースコントローラーの使い方
  • CRUD処理

では、まとめていきます。

Laravelの初期セットアップ

medium_5749192025

Laravelをインストールします

$ composer create-project laravel/laravel bbc --prefer-dist

DB接続の設定をする

編集ファイル:app/config/database.php

'mysql' => array(
	'driver'    => 'mysql',
	'host'      => 'localhost',
	'database'  => 'bbc',
	'username'  => 'root',
	'password'  => 'root',
	'charset'   => 'utf8',
	'collation' => 'utf8_unicode_ci',
	'prefix'    => '',
),

デバッグ機能を有効化する

編集ファイル:app/config/app.php

'debug' => true,

マイグレーションでDBを作成する

medium_10037916843
以下3つのテーブルを作成します。

1. ポストテーブル

$ php artisan migrate:make create_posts_table

2. カテゴリーテーブル

$ php artisan migrate:make create_categories_table

3. コメントテーブル

$ php artisan migrate:make create_comments_table

※Laravelの規約に従うために、データベース名は必ず複数形にします。

マイグレーションで生成されたファイルにカラムの情報を書き込む

編集ファイル:app/database/migrations/2014_12_00_000000_create_posts_table


<?php

use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;

class CreatePostsTable extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
		Schema::create('posts', function($table){
			$table->increments('id');
			$table->string('title');
			$table->string('cat_id'); // ポストテーブルとカテゴリーテーブルの紐付けに利用します
			$table->text('content');
			$table->unsignedInteger('comment_count'); // 投稿に何件のコメントがついたのかをカウントします
			$table->timestamps();
		});
	}

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

}

編集ファイル:app/database/migrations/2014_12_00_000000_create_categories_table


<?php

use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;

class CreateCategoriesTable extends Migration {

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

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

}

編集ファイル:app/database/migrations/2014_12_00_000000_create_commets_table


<?php

use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;

class CreateCommentsTable extends Migration {

	/**
	 * Run the migrations.
	 *
	 * @return void
	 */
	public function up()
	{
		Schema::create('comments', function($table){
			$table->increments('id');
			$table->unsignedInteger('post_id'); // ポストテーブルとコメントテーブルの紐付けに利用します
			$table->string('commenter');
			$table->text('comment');
			$table->timestamps();
		});
	}

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

}

マイグレーションを実行する

$ php artisan migrate

モデルのリレーションを設定する

medium_2304874364
以下、3つのファイルを作成します。
新規作成ファイル:app/models/Post.php


<?php
class Post extends Eloquent{

	public function Comments(){
		// 投稿はたくさんのコメントを持つ
		return $this->hasMany('Comment', 'post_id');
	}

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

}

新規作成ファイル:app/models/Category.php


<?php
class Category extends Eloquent{}

新規作成ファイル:app/models/Comments.php


<?php
class Comment extends Eloquent{}

LaravelのSeed機能を使ってDBにダミーデータを送信する

medium_8318656649
新規作成ファイル:app/database/seeds/PostCommentSeeder.php


<?php

class PostCommentSeeder extends Seeder{

public function run(){
	$content = 'この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。文字の大きさ、量、字間、行間等を確認するために入れています。この文章はダミーです。';

	$commentdammy = 'コメントダミーです。ダミーコメントだよ。';

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

		$maxComments = mt_rand(3, 15);
		for ($j=0; $j <= $maxComments; $j++) {
			$comment = new Comment;
			$comment->commenter = '名無しさん';
			$comment->comment = $commentdammy;

			// モデル(Post.php)のCommentsメソッドを読み込み、post_idにデータを保存する
			$post->comments()->save($comment);
			$post->increment('comment_count');
		}
	}

	// カテゴリーを追加する
	$cat1 = new Category;
	$cat1->name = "電化製品";
	$cat1->save();

	$cat2 = new Category;
	$cat2->name = "食品";
	$cat2->save();

}
}

以下のコマンドで実行します。

$ php artisan db:seed --class= PostCommentSeeder

リソースコントローラーを生成する

medium_13709317623
以下のコマンドでリソースコントローラーを生成します。

$ php artisan controller:make PostsController

つぎに、以下のようにルーティングの設定をしておきます。
編集ファイル:app/routes.php

Route::resource('bbc', 'PostsController');

※hogehoge.com/bbcにアクセスすることでリソースコントローラーが実行されます。

投稿記事を表示するためのコントローラーをつくっていく

medium_6017883879

投稿一覧の表示ページを作成する

編集ファイル:app/controller/PostsController.php


public function index()
{
	$posts = Post::all();
	return View::make('bbc.index')->with('posts', $posts);
}

つぎに、ビューを作ります。
まずは、マスターテンプレートを作成します。
新規作成ファイル:app/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/3.3.0/css/bootstrap.min.css">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap-theme.min.css">
	<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
	<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>

	<title>Laravelの掲示板</title>
</head>
<body>

@yield('content')

</body>
</html>

では、投稿一覧を表示してみます。
新規作成ファイル:app/bbc/index.blade.php

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

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

@foreach($posts as $post)

	<h2>タイトル:{{ $post->title }}
		<small>投稿日:{{ date("Y年 m月 d日",strtotime($post->created_at)) }}</small>
	</h2>
	<p>カテゴリー:{{ $post->category->name }}</p>
	<p>{{ $post->content }}</p>
	<p>{{ link_to("/bbc/{$post->id}", '続きを読む', array('class' => 'btn btn-primary')) }}</p>
	<p>コメント数:{{ $post->comment_count }}</p>
	<hr />
@endforeach

</div>

@stop

※$post->category->nameに関して
Post.phpモデルのCategory()メソッドからカテゴリー名を取得しています。
Eloquent ORMの便利な機能です。

以上で、以下のようなページが完成します。
URLは、hogehoge.com/bbcとなります。

index-blade-php

続きを読むボタンを作っていく

現状では、続きを読むボタンは動きません。
続きを読むボタンを動かすためにコントローラーを作ります。
編集ファイル:app/controller/PostsController.php


public function show($id)
{
	$post = Post::find($id);
	return View::make('bbc.single')->with('post', $post);
}

つぎにビューをつくります。
新規に作成ファイル:app/views/bbc/single.blade.php

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

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

<h2>タイトル:{{ $post->title }}
	<small>投稿日:{{ date("Y年 m月 d日",strtotime($post->created_at)) }}</small>
</h2>
<p>カテゴリー:{{ $post->category->name }}</p>
<p>{{ $post->content }}</p>

<hr />

<h3>コメント一覧</h3>
@foreach($post->comments as $single_comment)
	<h4>{{ $single_comment->commenter }}</h4>
	<p>{{ $single_comment->comment }}</p><br />
@endforeach

</div>

@stop

以下のページが完成しました。
Screen Shot 2014-12-08 at 3.27.04 PM

投稿機能を作成する

medium_13403806285
まずはビューをつくります。
新規作成ファイル:app/views/bbc/create.blade.php

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

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

<h1>投稿ページ</h1>

{{-- 投稿完了時にフラッシュメッセージを表示 --}}
@if(Session::has('message'))
	<div class="bg-info">
		<p>{{ Session::get('message') }}</p>
	</div>
@endif

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

{{ Form::open(['route' => 'bbc.store'], array('class' => 'form')) }}

	<div class="form-group">
		<label for="title" class="">タイトル</label>
		<div class="">
			{{ Form::text('title', null, array('class' => '')) }}
		</div>
	</div>

	<div class="form-group">
		<label for="cat_id" class="">カテゴリー</label>
		<div class="">
			<select name="cat_id" type="text" class="">
				<option></option>
				<option value="1" name="1">電化製品</option>
				<option value="2" name="2">食品</option>
			</select>
		</div>
	</div>

	<div class="form-group">
		<label for="content" class="">本文</label>
		<div class="">
			{{ Form::textarea('content', null, array('class' => '')) }}
		</div>
	</div>

	<div class="form-group">
		<button type="submit" class="btn btn-primary">投稿する</button>
	</div>

{{ Form::close() }}

</div>

@stop

以下のページが完成しました。
create-blade

つぎに、フォームのバリデーションとDBへの保存機能をつくります。
編集ファイル:app/controllers/PostsController.php


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

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

	$validator = Validator::make(Input::all(), $rules, $messages);

	if ($validator->passes()) {
		$post = new Post;
		$post->title = Input::get('title');
		$post->content = Input::get('content');
		$post->cat_id = Input::get('cat_id');
		$post->save();
		return Redirect::back()
			->with('message', '投稿が完了しました。');
	}else{
		return Redirect::back()
			->withErrors($validator)
			->withInput();
	}
}

これで完成です。
バリデーションエラーがおきると以下のようになります。

validation

特定のカテゴリーに属する記事一覧が表示できるようにする

medium_3230179037
まずはビューをつくります。
編集ファイル:app/views/bbc/index.blade.php

<!-- <p>カテゴリー:{{ $post->category->name }}</p> -->
<p>{{ link_to("/category/{$post->category->id}", $post->category->name, array('class' => '')) }}</p>
</code></pre>

これで、カテゴリーをクリックできるようになります。
つぎにコントローラーを作成します。
編集ファイル:app/controller/PostController.php
<pre><code class="language-php">
public function showCategory($id)
{
	$category_posts = Post::where('cat_id', $id)->get();

	return View::make('category')
		->with('category_posts', $category_posts);
}
</code></pre>

つぎに、ビューをつくります。
新規作成ファイル:app/views/bbc/category.blade.php
<pre><code class="language-php">
@extends('layouts.default')
@section('content')

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

@foreach($category_posts as $category_post)

	<h2>タイトル:{{ $category_post->title }}
		<small>投稿日:{{ date("Y年 m月 d日",strtotime($category_post->created_at)) }}</small>
	</h2>

	<p>{{ $category_post->content }}</p>

	<p>{{ link_to("/bbc/{$category_post->id}", '続きを読む', array('class' => 'btn btn-primary')) }}</p>
	<p>コメント数:{{ $category_post->comment_count }}</p>
	<hr />
@endforeach

</div>

@stop

以上で、特定カテゴリーに属する記事の一覧ページが完成しました。

コメントの投稿機能を作成する

medium_14076554725
まずは。コメントのビューを作成します。
編集ファイル:app/views/bbc/single.blade.php

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

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

<h2>タイトル:{{ $post->title }}
	<small>投稿日:{{ date("Y年 m月 d日",strtotime($post->created_at)) }}</small>
</h2>
<p>カテゴリー:{{ $post->category->name }}</p>
<p>{{ $post->content }}</p>

<hr />

<h3>コメント一覧</h3>
@foreach($post->comments as $single_comment)
	<h4>{{ $single_comment->commenter }}</h4>
	<p>{{ $single_comment->comment }}</p><br />
@endforeach

<h3>コメントを投稿する</h3>
{{-- 投稿完了時にフラッシュメッセージを表示 --}}
@if(Session::has('message'))
	<div class="bg-info">
		<p>{{ Session::get('message') }}</p>
	</div>
@endif

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

{{ Form::open(['route' => 'comment.store'], array('class' => 'form')) }}

	<div class="form-group">
		<label for="commenter" class="">名前</label>
		<div class="">
			{{ Form::text('commenter', null, array('class' => '')) }}
		</div>
	</div>

	<div class="form-group">
		<label for="comment" class="">コメント</label>
		<div class="">
			{{ Form::textarea('comment', null, array('class' => '')) }}
		</div>
	</div>

	{{ Form::hidden('post_id', $post->id) }}

	<div class="form-group">
		<button type="submit" class="btn btn-primary">投稿する</button>
	</div>


{{ Form::close() }}


</div>

@stop

つぎにコントローラーを作成します。

$ php artisan controller:make CommentsController

生成されたファイルに以下の記述します。


public function store()
{
	$rules = [
		'commenter' => 'required',
		'comment'=>'required',
	];

	$messages = array(
		'commenter.required' => 'タイトルを正しく入力してください。',
		'comment.required' => '本文を正しく入力してください。',
	);

	$validator = Validator::make(Input::all(), $rules, $messages);

	if ($validator->passes()) {
		$comment = new Comment;
		$comment->commenter = Input::get('commenter');
		$comment->comment = Input::get('comment');
		$comment->post_id = Input::get('post_id');
		$comment->save();
		return Redirect::back()
			->with('message', '投稿が完了しました。');
	}else{
		return Redirect::back()
			->withErrors($validator)
			->withInput();
	}
}

さいごにルーティングの設定をします。
編集ファイル:app/routes.php

Route::resource('comment', 'CommentsController');

以上でコメント投稿機能が完成しました。
comment-func

以上で掲示板が完成しました( ՞ٹ՞)

おわりに…

medium_168516836
Laravelで掲示板を作成するチュートリアルがネット上になかったので作成してみました。
すこしでも記事が役に立てば幸いです。
コードの間違いなどありましたらご連絡いただけると助かります。
質問などはTwitterでうけつけます。