見出し画像

掲示板を作ろう(後編) #Laravel基礎 Webアプリケーションの開発

こちらはLaravelで掲示板を作成する課題の後編です。

前編はこちらです。


# テンプレートの作成

前編で次のように設計したテンプレートを作成していきます。

■ View
- 投稿一覧のためのテンプレートは「bbs_entry_list.blade.php」とする
- 投稿フォームは「part/bbs_entry_form.blade.php」として投稿一覧のページから@includeする
- Controllerからは「$item_list」で投稿一覧(BbsEntryの配列)を渡す

まず、記事一覧用のテンプレート「bbs_entry_list.blade.php」と投稿フォーム用のテンプレート「part/bbs_entry_form.blade.php」を作成します。

resources/views/bbs_entry_list.blade.php

<!-- 投稿フォーム -->
@include("parts.bbs_entry_form")

<h2>記事一覧</h2>

@foreach ($item_list as $item)
<div class="entry">
	<h5>{{ $item->title }}</h5>
	<div>
		{{ $item->body }}
	</div>
</div>
@endforeach

@if(count($item_list) < 1)
<p>投稿がありません</p>
@endif

トップページ用のテンプレートは「投稿フォームの表示」「item_listの表示」「0件の時の対応」を行います。

投稿フォームの表示
@include("parts.bbs_entry_form")

@includeで別テンプレートを呼び出しています。


記事一覧(item_list)の表示
@foreach ($item_list as $item)
<div class="entry">
<h5>{{ $item->title }} by {{ $item->author }}</h5>
<div>
{{ $item->body }}
</div>
</div>
@endforeach

@foreach〜@endforeachを使ってitem_list分ループして記事を表示させます。$itemはBbsEntryクラスなのでtitleとbodyが入っているので、そちらを表示します。


0件の時の対応
@if(count($item_list) < 1)
<p>投稿がありません</p>
@endif

@if〜@endifを利用して$item_listの個数をチェックしています。


続いて、投稿フォーム用の部品です。


resources/views/parts/bbs_entry_form.blade.php

<form method="post" action="{{ url('/create') }}">
	@csrf

	<div>
		<label>Name</label><br />
		<input type="text" name="author" value="" placeholder="お名前" />
	</div>

	<div>
		<label>Title</label><br />
		<input type="text" name="title" value="" placeholder="タイトル" />
	</div>

	<div>
		<label>Body</label><br />
		<textarea name="body"></textarea>
	</div>

	<input type="submit" value="投稿" /> 
</form>


投稿フォーム部分は一般的なHTMLのフォームですが、「action="{{ url('/create') }}"」の指定でフォームの投稿先をルーティングで設定した/createになるように設定しています。

@csrf

こちらはCSRFのフィールドを出力するための記述です。Laravelで<form>を使う時はCSRFのフィールドのの記述が必須となります。Laravel5.6未満の場合は「{{ csrf_fields }}」という記法です。


# ControllerとViewの設定

次に作成したViewを表示するようにControllerの書き換えを行います。

BbsEntryControllerのindex()メソッドを次のように編集してアクセスしたらbbs_entry_list.blade.phpが表示されるようにします。

設計通りitem_listをViewに渡すようにしましょう。

app/Http/Controllers/BbsEntryController.php

class BbsEntryController extends Controller
{
   function index(){
		
		$item_list = BbsEntry::all();
		return view("bbs_entry_list", [
			"item_list" => $item_list
		]);
	}
	(略)
}


Controllerを保存して、ブラウザで確認してください。次のように表示されると成功です。

スクリーンショット 2020-06-08 23.06.49

※ 見やすい用にCSSを設定しています。

# 投稿フォームの処理の作成

投稿フォームの遷移先はルーティングで設定したBbsEntryController#create()です。

PHPでそのまま書いた場合$_POSTなどで受け取っていたフォームの投稿内容ですが、LaravelではRequest経由で受け取ります。「name="author"」「name="title"」「name="body"」の要素からの遷移は、次のように受け取ります。

$input = $request->only('author', 'title', 'body');

only()メソッドを使って必要な値のみを取り出します。不正なフォームなどで想定していない値が来ても問題ないように考えられています。

では、入力された値をdd()を使って表示してみましょう。

app/Http/Controllers/BbsEntryController.php

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\BbsEntry;

class BbsEntryController extends Controller
{
   function index(){
		(略)
	}

	function create(Request $request){
		$input = $request->only('author', 'title', 'body');
		dd($input);
	}

}

ファイルを保存したらトップページを表示して投稿フォームをテストしてみましょう。

次のように表示されたら成功です。

スクリーンショット 2020-06-08 23.09.27


動作しない場合は次のことを確認してください

・create()の引数は「Request $request」になっていますか?
・「use Illuminate\Http\Request;」の表記はありますか?
・フォームが正しく設定できているか「name="title"」「name="body"」が正しいかを確認

# フォームの値をデーターベースに保存する

入力値を「$request->only()」経由で受け取ることができました。

続いて、この入力値からBbsEntryクラスのオブジェクトを作成し、データーベースに保存していきます。

Modelクラスにはsave()というデータを保存する便利なメソッドがあります。create()メソッドを次のように書き換えてください。

function create(Request $request){
	$input = $request->only('author', 'title', 'body');
	
	$entry = new BbsEntry();
	$entry->author = $input["author"];
	$entry->title = $input["title"];
	$entry->body = $input["body"];
	$entry->save();

	return redirect('/');
}
return redirect('/');

書き込み後、トップページに遷移するためにredirect()関数を使います。

書き込みが上手く出来ているか、実際にフォームを使って確認してみてください。

次のように投稿した内容が表示されていれば成功です。

スクリーンショット 2020-06-08 23.11.41

# 表示順の変更

現在はBbsEntry::all()を使ってitem_listを作成しているため、新しいものが上に来ていません。

並び順を指定するにはModelのorderBy()関数を使います。

BbsEntry::all()

BbsEntry::orderBy("id", "desc")->get()
Modelクラス::orderBy(カラム名, 順番)

の形で指定します。

新しいものが上ということはIDが大きいものから小さいものに表示するので、「id」「desc=逆順」の指定になっています。

書き換え後、リロードして新しいものが上に来ることを確認してください。

スクリーンショット 2020-06-08 23.17.47


# 本文を改行する

本文には改行情報が含まれていますが、{{ $item->body }}での表示では改行が表示されません。

PHPにはnl2brという改行を<br>に変換する機能があります。こちらを利用すると、次のように書くことができます。

{!! nl2br($item->body) !!}

{!! 〜 !!}は{{ 〜 }}と違ってエスケープ処理をしない構文です。

エスケープ処理は簡単に言うと「HTMLタグを出力させない機能」です。

ユーザーの入力値やデーターベースに保存された値をそのまま出してしまうと、悪意のあるコードを埋め込むことが出来てしまうため、エスケープ処理が必須となっています。

このままではエスケープせずに本文を出してしまうので、セキュリティの危険性が高いです。

そのため、一度エスケープした後にnl2brを実行する以下の形に書き換えるのが正解です。

{!! nl2br(e($item->body)) !!}

resources/views/bbs_entry_list.blade.php

<!-- 投稿フォーム -->
@include("parts.bbs_entry_form")

<h2>記事一覧</h2>
@foreach ($item_list as $item)
<div class="entry">
	<h5>{{ $item->title }} by {{ $item->author }}</h5>
	<div>
		{!! nl2br(e($item->body)) !!}
	</div>
</div>
@endforeach

@if(count($item_list) < 1)
<p>投稿がありません</p>
@endif

ブラウザで表示を確認してみましょう。

スクリーンショット 2020-06-09 0.41.46


# まとめ

LaravelでWebアプリケーションを作成する最小の要素だけでも覚えなければならないことが非常に多いですが、一個一個積み重ねていけばきっと理解出来るようになるはずです。

今回の課題を通して次のことを確認してください。

・Model-View-Controllerのそれぞれの役割
・LaravelでのModel、View、Controllerそれぞれの作成方法について
・フォームの値の受け取り方

Webアプリケーションの基礎として避けることが出来ないバリデーションなどを応用例として別記事にしました。

バリデーションを含んだ全てのサンプルコードはこちらで公開しています。


おつかれさまでした!


--



完成まで突っ走る意気込みです。サポートしていただけると非常に嬉しいです。応援よろしくお願いします。