速習Larave3(その7)、更新処理No.1
Tags : Laravel3
さて、次に更新処理を行いましょう。
- ソース:github
更新処理だけを作成するのでしたら、そう手間はかかりません。追加と更新を全く別のルート、別のアクションで処理するならば、ロジックは簡単です。ですから、初心者の方にはお勧めです。
ですが、やっぱり素人くさいですよね。なにせ大抵の場合ページ構成も全く一緒です。
そのため、今回は追加と更新を一つのコントローラー/アクションとして実現します。
実は、良い方法がないかと色々あさって見たのですが、海外のチュートリアルも「Laravelはこんなに簡単なんだよ」と表現するために、難しい部分、複雑な部分を避けているようで、実用性に欠けています。ですから、良い例が見つからなかったのです。
今回は色々な考え方ができるので、多少「こういう考え方もできるよ」と説明しながら、進みます。
実は、可能な限りベストな方法を考えるために半日以上使いました。色々試しました。とりあえず、今のところ思いついたベストな方法で、更新と追加を一緒のロジックで処理するやり方を紹介します。実際、このサイトでやっているやり方よりスマートになりました。
ルーティングをデザインする
まず考えるのがこれです。
処理 | ルート |
---|---|
追加 | /post/add |
更新 | /post/update/(ポストID) |
この方法は、認識性に優れています。ルートを読めば何をするのか一目瞭然です。もうひとつの候補はこれです。
処理 | ルート |
---|---|
追加 | /post/edit |
更新 | /post/edit/(ポストID) |
エディターを考えてください。コマンドラインから起動する時、何も指定しなければ、新規として開きます。ファイルを指定すればそのファイルの更新処理として起動します。それと同じ考えです。
何も指定されなければ、新規として扱い、ポストIDが指定されたら、そのIDの記事を更新処理と考えます。
好みの問題です。どちらを選んでも構いません。フレームワークを使用する利点の一つが、こうしたルートと実際に動作するスクリプトを自由に結び付けられることです。
今回は二番目の方法を取ります。実はルートの勉強もしようと思っています。
Route::any('post/edit', ...); Route::any('post/edit/(:num)', ...);
このように分けて書いても間違いではありません。実際、追加と更新を別のアクションで処理するのでしたら、こう書くことになります。
今回は同じアクションで処理します。すると上記のように二つに分けて書くのは二度手間です。こう書きましょう。
Route::any('post/edit/(:num?)', ...);
クエスションマーク付きは公式ドキュメントでは「オプション」という表現を使っていますが、要するにあってもなくても一致するという意味です。これですっきり書く方法が身につきました。
実際のroutes.php
は次のようになります。追加処理だけを行なっていたルート名post-add
は削除してください。add
は追加ですが、今回は更新にも使用しますからね。代わりに以下のコードで書き換えてください。
// 記事追加/編集 // フォーム表示 Route::get('/post/edit/(:num?)', array( 'as' => 'post-edit', 'uses' => 'post@edit' )); // フォーム処理 Route::post('/post/edit/(:num?)', array( 'as' => 'post-edit', 'before' => 'csrf', 'uses' => 'post@edit' ));
any()
で登録するのではなく、HTTP変数のGETとPOSTでルートを分けています。CSRFのフィルターはPOSTのみに適用したいですからね。(初心者はRoute::any
にCSRFフィルター付けて、はまりがちです。;) )
チラッ、ちっら(なんだかアクションの名前も変わっているような…)
ご察しの通り。add
からedit
に変えました。両方を担当させるにはadd
には荷が重過ぎます。言葉の意味がせま過ぎますからね。というわけで、コントローラーに移ります。
コントローラーの処理
post.php
です。get_add()とpost_add()を削除し、以下のコードに置き換えてください。
/** * 記事追加/編集フォーム表示 */ public function get_edit($id = null) { // フラッシュデーターとしてセッションに // 保存されている入力を取得 $inputs = array_only( Input::old(), array( 'title', 'body' )); // フラッシュデータが存在しない場合 // フォーム処理からのリダイレクトではなく // 初めて呼び出されたということ if ( empty($inputs) ) { // 初回処理 if ( $id === null ) { // 新規記事追加 $data = array( // ページ出力は空文字列 'title' => '', 'body' => '', ); } else { // 更新処理 $post = Post::find($id); if ( $post === null ) { return Redirect::error('404'); } $data = array( // ページ出力は既存のレコード 'title' => $post->title, 'body' => $post->body, ); } } else { // フォーム更新時 $data = array( // ページ出力はフォームの入力データー 'title' => $inputs['title'], 'body' => $inputs['body'], ); } return view('post.form') ->with('title', $data['title']) ->with('body', $data['body']); } /** * 記事追加フォーム処理 */ public function post_edit($id = null) { // バリディーションルール $rules = array( 'title' => 'required|max:50', 'body' => 'required|max:8000', ); $input = Input::only(array( 'title', 'body' )); $val = Validator::make($input, $rules); if ( $val->passes() ) { // バリデーション通過 if ( $id === null ) { // 新ポストの追加 $post = new Post($input); $post->save(); // 続けて投稿しやすいように // 再度追加処理へ(IDを付けないでリダイレクト) return Redirect::to_route('post-edit') ->with('message', '記事を投稿しました。'); } else { // 既存ポストの更新 $post = Post::find($id); if ( $post === null ) { return Redirect::error('404'); } $post->title = $input['title']; $post->body = $input['body']; $post->save(); // 同じ記事を修正しやすいように // 再度記事を表示させる return Redirect::to_route('post-edit', array( $id )) ->with_input() ->with('message', '記事を編集しました。'); // with_input()が無くても同じ記事が表示されるが // よけいなDBアクセスをさせない } } else { // バリデーション失敗 return Redirect::to_route('post-edit', array( $id )) ->with_input() ->with_errors($val); } }
まず、ルートに(:num?)
とオプション付きで指定した場合、それを受け取る引数にはデフォルト値を指定し、引数が無かった場合の値を設定することに注意してください。
表示処理がフォームの処理と同じくらい複雑になっています。ですから、追加と更新を分けたほうが簡単にはなるんですよ。でも、複雑に見えてもたいしたことありません。次の記事からゆっくり解説していきます。