Lravel5入門(その2)POSTするフォーム作り

Laravel5でフォームを作るのは結構簡単です。Symfony2より全然簡単です。
まず前段としてFormタグ自体をLaravel5のVendarから作成する方法と直にHTMLタグでFormタグを作成する方法があります。前者はLarabel5の開発から独立して現在有志で開発と保守を行っています。これにはHtmlとFormのファサード(Facade)というものを利用します。
HTML,Formのファサードの使い方はいろいろな記事にのっているのでそこを参照してみてください。Composerでインストールするのがいちばん楽です。またインストール後にはオートローダーに組み込む必要もあります。
ここでは、普通にFormタグを組む方法で説明します。

Formを作成する

ビューを作成して入力フォームを作成します。GETメソッドでアクセスできるページを1つ作っておきます。なんでもいいのですが、ここでは、
/form
というパスにアクセスすることにしましょう。コントローラは
Form/FormController@index
でよいかと思います。

ルーティング

project/app/Http/routes.php
Route::get('/form', 'Form/FormController@index');
/formにアクセスしたら表示できるようにしておきます。

コントローラ

ルーティングからFormController@indexにアクセスできるようにコントローラを作成します。
$ php artisan make:controller Form/FormController
コントローラのindexメソッドにビューを返します。
public function index()
{
return view('form/form');
}

ビュー

/resources/views/form/form.blade.phpを作成します。ここでは普通にFormタグを作成するだけです。さて問題はactionの向け先ということになります。
<p>Form</p>
<form action="" method="POST">
<input type="text" name="sample_name" name="sample_name">
<input type="submit" value="送信">
</form>

とここまで作れたらOKです。/formでアクセスして無事普通に簡単なフォームが機能しているはずです。

確認画面をつくる

submitとした先がどこに行くのかということになりますが、実はどこにも行かず/formのままでよいです。というのもルーティングでGET/POSTとリクエストメソッドを区別できるからです。
もう1つ注意点はtokenの使用です。POSTのリクエストメソッドにはtokenの利用がLaravel5では義務付けられています。なので、作成したビューからPOSTすると、
TokenMismatchException in VerifyCsrfToken.php line ...
というエラーが表示されるはずです。

tokenを埋め込む

ビューのテンプレートにtokenを埋め込みます。
<form action="" method="POST">
<input name="_token" type="hidden" value="{{csrf_token()}}"> これ追加
<input type="text" name="sample_name" value="">
<input type="submit" value="送信">
</form>

hiddenに持たせるわけですが、この書き方は定形です。Formを作るときはこの形でフォーム内に埋め込んでおきます。/formにアクセスしなおしてみてください。{{csrf_token()}}にはセッションが発行したトークンが自動的に格納されているはずです。
またPOSTメソッドのリクエストをLaravel5が受ける場合はこのトークンも必ず受けるという規則になっています。なのでトークンなしでのPOSTは不可能になっているのです。

ルーティングを追加する

確認ページのルーティングを追加します。今度はPOSTメソッドなので、
Route::get('/form', 'Form\FormController@index');
Route::post('/form', 'Form\FormController@confirm'); // これ追加

という風にPOSTでのリクエストを受けられるようにします。POSTで受けたときはconformメソッドが処理をするようにします。

コントローラーメソッドの作成

先ほど作成したconfirmメソッドはClassファイルの中にありません。なので自分で作る必要があります。

public function confirm(Request $request)
{
return view('form/confirm');
}

indexメソッドの下なんかに追加してつくります。ここでGETメソッドの場合とちょっと違うのは、(Request $request)という引数が入っていることです。ここではPOSTの内容を受け取ることになっているので、このように引数を与えてあげます。これがないとPOSTの内容がこのconfirmメソッドに入ってきません。
また、返すビューも作成しましょう。confirm.blade.phpが表示されるようにしています。

確認画面のビューの作成

form.blade.phpと同じ場所にconfirm.blade.phpを作成します。
<p>Form Confirm</p>
という感じでまずは簡単に書いておきましょう。
ここまででsubmit後の動作で「Form Confirm」が表示されればOKです。

Laravel5のPOSTのやり方

さて話を簡単にするために、confirmメソッド内かconfirm.blade.php内のどちらかでvar_dumpしてみます。ここではコントローラ内でやってみましょう。
public function confirm(Request $request)
{
var_dump($request);
return view('form/confirm');
}

var_dump($request);をしてsubmitするとこれまたすごいたくさんの値がダンプされます。そしてこの中にフォームからsubmitされた値とtokenを見つけることができます。よくよく調べると、
$request['_token']
$request['sample_name']

で取得できていることがわかります。これはフォームからPOSTされた値です。$_POSTからも取得が可能ですがLaravel5を使っている意味がなくなってしまうので、$requestから取り出しましょう。

さて昨今のセキュリティーの問題で言えば「なんとかふぉーじぇり」とかあの辺りの問題を解決するためにtokenを利用しています。このトークンはPOST元を正しく判定することとシステム上の処理順序をクライアントに順守させるためにあります。*セキュリティーの話はここではしません。別項で。
なのでPOSTされたtoken(インターネット上で渡ってきたPOST値)とサーバー内で保持しているtokenが同じでなければならないということになります。Laravel5ではすでに自動的に発行してくれたtokenをセッションにも格納してくれています。
use Session;
でセッションクラスを呼んでから、メソッド内で
$_token = Session::get('_token');
すればサーバー内で保持しているtokenにアクセスできます。

故にPOSTを受けるメソッド内でやることは、
・POSTのバリデーションとサニタイズ
・tokenの確認
・POSTデータの出力
になります。
POSTのバリデーションとサニタイズに関しては共通クラスなどで一括して行うのがよいでしょう。いろいろとポリシーがあると思うので割愛します。
(ですが、基本的なエスケープなどはbladeに出力する際に行います。これはJavascriptによる攻撃なんかを阻止するためです。{{...}}で出力された値はすべてすでにエスケープされているので特に特別な処理をする必要がありません。)

ビューに値を渡す

確認画面でPOST値を表示さえるにはbladeに値を送ってあげる必要があります。送り方は、コントローラーの最後でview()にwithしてあげるだけで大丈夫です。
return view('form/confirm')->with('sample_name',$request['sample_name']);
ビューの方では、
{{$sample_name}}で表示させてあげるだけです。

ちょっと整えて書いてあげるとこんなかたちになるかと思います。
project/resources/views/form/confirm.blade.php
public function confirm(Request $request)
{
if (mb_check_encoding($request['sample_name'], 'UTF-8')) {
$request['sample_name'] = htmlspecialchars($request['sample_name'], ENT_QUOTES, 'UTF-8');
}

return view('form/confirm')->with('sample_name',$request['sample_name']);
}

with('VALUE_NAME',$VALUE)という単純な形式です。複数ある場合はメソッドを連ねてゆけばOKです。
配列も格納できます。

project/resources/views/form/confirm.blade.php
<p>Form Confirm</p>
{{$sample_name}}

これでPOST値を表示できます。

ここまでで基本的なフォームの使い方がわかったと思います。あとはセキュリティーの部分と全体の構成の問題にからめて自分で作ってみてください。

確認画面から完了画面へ

確認画面から完了画面へと遷移するためにはもう一度POSTしてあげる必要があります。しかし従来のhiddenに値を持たす必要はLaravel5ではもうすでにありません。理屈上確認された値なのですからsessionなどに持たせた方がが無難でしょう。またhiddenに持たせたとしてもsessionとの値で再度値の妥当性を検証する必要が出てくる筈です。

project/resources/views/form/confirm.blade.php
<p>Form Confirm</p>
確認: {{$sample_name}}
<form action="/complete" method="POST">
<input name="_token" type="hidden" value="{{csrf_token()}}">
<input type="hidden" name="sample_name" value="{{$sample_name}}">
<input type="submit" value="登録">
</form>

app/Http/routes.php
Route::get('/form', 'Form\FormController@index');
Route::post('/form', 'Form\FormController@confirm');
Route::post('/complete', 'Form\FormController@complete');

project/app/Http/Controllers/Form/FormController.php
public function complete(Request $request)
{
// DBに格納したりメール送信したり
$request['sample_name'];

return view('form/complete');
}

project/resources/views/form/complete.blade.php
<p>Form Complete</p>
<a href="/form">最初から</a>

ここまででFormの一連の動作は終わり。MCVって感じですね。