掲示板パート1【Laravel】

Pocket

前回、Laravelプロジェクトを作成ました。

今回はプロジェクトに簡単な掲示板(記事一覧、記事投稿、コメント追加、記事の絞り込み)を作成します。

参考サイト

Yaimapp(https://blog.yaimapp.net/post/112032489660/laravel5-%E3%81%A7%E6%8E%B2%E7%A4%BA%E6%9D%BF%E4%BD%9C%E6%88%90)

manablog(https://manablog.org/laravel_bulletin_board/)

手順

1. データベース準備とLaravelからの接続設定

2. データベースの構造設計とリレーション設定

3. 機能の実装(コントローラーの作成)

4. 見た目の作成(ビューの作成)

5. 3と4を機能ごとに繰り返す()

1. データベース準備とLaravelからの接続設定

dbを下記の内容で設定した場合

host:localhost

dbの名前:test

dbのユーザー名:test

パスワード:6RtgFcRI7J6k0sFT

.envファイルに下記を記述

DB_HOST=localhost
DB_DATABASE=test
DB_USERNAME=test
DB_PASSWORD=6RtgFcRI7J6k0sFT

2. データベースの構造設計とリレーション設定

testに3つのテーブルを作成します。

・記事用のposts

・記事のカテゴリ―用のcategories(一つの記事は一つのカテゴリに属している)

・記事に対するコメント用のcomments(一つの記事は複数のコメントをもつ)

上記の関係をLaravelに記述していきます。

コマンドプロンプト上で、プロジェクトファイルに移動。

cd C:\xampp\htdocs\test

その後、posts、categories、commentsを作成。

php artisan make:migration create_posts_table
php artisan make:migration create_categories_table
php artisan make:migration create_comments_table

detabase/migrations/…..create_posts_table.php

detabase/migrations/…..create_categories_table.php

detabase/migrations/…..create_comments_table.php

の3ファイルが作成されます。

detabase/migrations/…..create_posts_table.phpを修正します。

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

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->string('cat_id'); 
            $table->text('content');
            $table->timestamps();
        });
    }

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

detabase/migrations/…..create_categories_table.phpを修正します。

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

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');
    }
}

detabase/migrations/…..create_comments_table.phpを修正します。

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

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->timestamps();
        });
    }

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

修正したマイグレーションを実行し、データベースにテーブルを作成します。

php artisan migrate

エラーがでず、データーベースに作成したテーブルが定義されていればOKです。

筆者の場合、Laravelをインストールした時にデフォルトで作成されいるマイグレーションファイルでエラーが発生したので、余計なマイグレーションファイルを削除して、再度マイグレーションを実行しました。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

次は、Laravel上でリレーションの設定を記述します。

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

app/Post.php

app/Comment.php

app/Category.php

の3ファイルが作成されます。

app/Post.phpにリレーションを記述。

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
  public function Comment() {
    // 一つの記事は複数のコメントをもつ
    return $this->hasMany('App\Comment', 'post_id');
  }

  public function Category(){
    // 一つの記事は一つのカテゴリに属している
    return $this->belongsTo('App\Category', 'cat_id');
  }
}

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

リレーションの記述が完了したので、ダミーデータを作成し、データベースに登録します。

detabase/seeds/PostCommentSeeder.phpに下記ファイルを作成します。

<?php
use Illuminate\Database\Seeder;

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

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

      for( $i = 1 ; $i <= 10 ; $i++) {
        $post = new App\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 App\Comment;
          $comment->commenter = 'テストユーザ';
          $comment->comment = $commentdammy;
          $post->comments()->save($comment);
        }
      }

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

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

シーダーファイルを実行。

php artisan db:seed --class=PostCommentSeeder

エラーが出る場合は

composer dump-autoload

を実行したのち、再度シーダーを実行してください。

成功すれば、データーベースにダミーデータが保存されています。

3,4 機能の実装

<記事投稿機能作成>

記事投稿機能を作成していきます。

php artisan make:controller PostsController

app/Http/Controllers/PostsController.phpが作成されます。

①投稿一覧ページ

routes/web.php編集

<?php

use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::resource('bbs', 'PostsController');//bbsにアクセスした際にPostsControllerに処理させる

app/Http/Controllers/PostsController.php編集

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Post;


class PostsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::all();//全記事取得
        return view('bbs.index')->with('posts', $posts);//index.blade.phpに値をわたす
    }
}

resources/viwes/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>

resources/viwes/bbs/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>
<?php
  echo $post->comments->count();
?>
    件のコメント</p>
    <p>{{ $post->content }}</p>
    <p>{{ link_to("/bbs/{$post->id}", '続きを読む', array('class' => 'btn btn-primary')) }}</p>
@endforeach
</div>
@stop

http://localhost/test/public/bbsにアクセスするとこのような画面が表示されればOK

エラーが出た場合は、Laravelのバージョン違いによるlink_toのサポート切れだと思われます。(筆者もエラーがでました。)

link_toを使えるように、composerを使用して外部からパッケージをインストールします。

link_toを使用するにはilluminate/htmlやlaravelcollective/htmlを使えばいけると記事が散見されました。ただ、illuminate/htmlはアップデートが終了しているからやめた方が良いよ的な記事も見たので(嘘だったらごめんなさい)、laravelcollective/htmlを使用します。

https://laravelcollective.com/docs/6.0/html

コマンドプロンプトで以下を実行。

composer require laravelcollective/html

これで、link_toが使えるようになり、エラーが解消されると思います。

エラーが出る場合はcomposer update後に再度ページを確認してください。

これでもエラーで出る場合は、違う箇所に問題があるかもです。

composer update

②続きを読むページを作成

app/Http/Controllers/PostsController.php編集

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Post;


class PostsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::all();//全記事取得
        return view('bbs.index')->with('posts', $posts);//index.blade.phpに値をわたす
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Post  $post
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $post = Post::find($id);
        return View('bbs.single')->with('post', $post);
    }
}

resources/viwes/bbs/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 />
<div>
<p>{{ link_to("/bbs", '一覧に戻る', array('class' => 'btn btn-primary')) }}</p>
</div>
<h3>コメント一覧</h3>
<p>
<?php
  echo $post->comments->count();
?>
件のコメント</p>
<br />
@foreach($post->comments as $single_comment)
    <h4>{{ $single_comment->commenter }}</h4>
    <p>{{ $single_comment->comment }}</p><br />
@endforeach
</div>
@stop

http://localhost/test/public/bbsから続きを読むを押すことで、記事の詳細ページがひらきます。

③記事投稿機能

<表示機能>

resources/viwes/bbs/index.blade.php編集

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

<div class="col-xs-8 col-xs-offset-2">
<div class="">
<p>{{ link_to("/bbs/create", '新規作成', array('class' => 'btn btn-primary')) }}</p>
</div>
@foreach($posts as $post)
    <h2>タイトル:{{ $post->title }}
        <small>投稿日:{{ date("Y年 m月 d日",strtotime($post->created_at)) }}</small>
    </h2>
    <p>カテゴリー:{{ $post->category->name }}</p>
    <p>
<?php
  echo $post->comments->count();
?>
    件のコメント</p>
    <p>{{ $post->content }}</p>
    <p>{{ link_to("/bbs/{$post->id}", '続きを読む', array('class' => 'btn btn-primary')) }}</p>
@endforeach
</div>
@stop

app/Http/Controllers/PostsController.php編集

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Post;


class PostsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::all();//全記事取得
        return view('bbs.index')->with('posts', $posts);//index.blade.phpに値をわたす
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('bbs.create');
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Post  $post
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $post = Post::find($id);
        return View('bbs.single')->with('post', $post);
    }
}

resources/viwes/bbs/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' => 'bbs.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">カテゴリーその1</option>
				<option value="2" name="2">カテゴリーその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() }}
<a href="{{ action('PostsController@index') }}" class="btn btn-primary">一覧に戻る</a>
</div>
@stop

http://localhost/test/public/bbs/createにアクセス

<dbへの登録とバリデーション機能>

app/Http/Controllers/PostsController.php編集

use Illuminate\Support\Facades\Validator;
use Redirect;

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Post;

use Illuminate\Support\Facades\Validator;
use Redirect;

class PostsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::all();//全記事取得
        return view('bbs.index')->with('posts', $posts);//index.blade.phpに値をわたす
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('bbs.create');
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Post  $post
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $post = Post::find($id);
        return View('bbs.single')->with('post', $post);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $rules = [
            'title' => 'required',
            'content'=>'required',
            'cat_id' => 'required',
        ];

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

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

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

空欄で投稿を押すと、エラーが返ってくる。必須項目を入力すれば、記事を登録することができる。

④カテゴリー別による記事の表示

resources/viwes/bbs/index.blade.php編集

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

<div class="col-xs-8 col-xs-offset-2">
<div class="">
<p>{{ link_to("/bbs/create", '新規作成', array('class' => 'btn btn-primary')) }}</p>
</div>
@foreach($posts as $post)
    <h2>タイトル:{{ $post->title }}
        <small>投稿日:{{ date("Y年 m月 d日",strtotime($post->created_at)) }}</small>
    </h2>
    <p>カテゴリー:{!!  link_to("/bbs/category/{$post->category->id}", $post->category->name, array('class' => '')) !!}</p>
    <p>
<?php
  echo $post->comments->count();
?>
    件のコメント</p>
    <p>{{ $post->content }}</p>
    <p>{{ link_to("/bbs/{$post->id}", '続きを読む', array('class' => 'btn btn-primary')) }}</p>
@endforeach
</div>
@stop

routes/web.php編集

<?php

use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::resource('bbs', 'PostsController');//bbsにアクセスした際にPostsControllerに処理させる
Route::get('bbs/category/{id}', 'PostsController@showCategory');

app/Http/Controllers/PostsController.php編集

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Post;

use Illuminate\Support\Facades\Validator;
use Redirect;

class PostsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $posts = Post::all();//全記事取得
        return view('bbs.index')->with('posts', $posts);//index.blade.phpに値をわたす
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('bbs.create');
    }

    /**
     * Display the specified resource.
     *
     * @param  \App\Post  $post
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $post = Post::find($id);
        return View('bbs.single')->with('post', $post);
    }
    public function showCategory($id)
    {
        $category_posts = Post::where('cat_id', $id)->get();
        return view('bbs.category')
            ->with('category_posts', $category_posts);
    }
    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $rules = [
            'title' => 'required',
            'content'=>'required',
            'cat_id' => 'required',
        ];

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

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

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

http://localhost/test/public/bbsのカテゴリーを押すと、カテゴリーごとに記事を絞り込んで表示する。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

<記事へのコメント機能作成>

コメント機能機能を作成していきます。

php artisan make:controller CommentsController

app/Http/Controllers/CommentsController.phpが作成されます。

routes/web.php編集

<?php

use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::resource('bbs', 'PostsController');//bbsにアクセスした際にPostsControllerに処理させる
Route::get('bbs/category/{id}', 'PostsController@showCategory');

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

app/Http/Controllers/CommentsController.php編集

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Comment;
use Illuminate\Support\Facades\Validator;
use Redirect;

class CommentsController extends Controller
{
	public function store(Request $request)
	{
		$rules = [
			'commenter' => 'required',
			'comment'=>'required',
		];

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

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

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

resources/viwes/bbs/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 />
<div>
<p>{{ link_to("/bbs", '一覧に戻る', array('class' => 'btn btn-primary')) }}</p>
</div>
<h3>コメント一覧</h3>
<p>
<?php
  echo $post->comments->count();
?>
件のコメント</p>
<br />
@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

これで記事の詳細ページの下部にコメント投稿部分が追加されました。

長くなりましたが、以上です。

パート2でページャー、記事の削除、編集を追加します。