速習Larave3(その7)、更新処理No.2

タグ: Laravel3  

チュートリアルの更新処理編。前記事からの続きです。

まず表示です。$dataに表示内容をセットし、ビューに渡します。

Tips!! 表示内容を渡すには、ビューを経由する方法の他、フォームの入力をInput::replaceメソッドで書き換えるという手法も取れます。研究してみてください。

$dataに配列で出力内容を受けています。今回は配列の要素をばらしてビューに渡していますが、まとめて渡してビューでキーを指定するのが好きな方もいるでしょう。お好みで通常の変数で受けてもスタンダードクラスのインスタンスで受けても、なんでも構いません。わかりやすいように書きましょう。

この$dataに状況に合わせて出力内容をセットするロジックを考えましょう。

  1. 初めてページを表示する場合は
    1. IDが指定されていれば更新処理なので、該当する記事を表示する
    2. IDが指定されていなければ新規の追加処理なので、空欄で表示する
  2. フォームからリダイレクトされた場合は、フォームに入力された内容を表示する

こうして分けて考えれば簡単ですね。それぞれは数ステップのコードで実現できます。

IDが指定されているかは簡単に判断できます。if文一つです。

ちょっと頭をひねるのは初めてページを表示する場合と、フォームからリダイレクトされてきた場合の判断です。何で判断しましょうか。

実はロジックで判断するのではなく、GETの処理を2つのルートに分けたほうが、明確で単純になります。最初のルートではデーターの取得をさせ、2番めのルートへリダイレクトさせます。その2番めのルートでフォームの表示を行います。フォームの送信内容を処理するPOSTの処理で、エラー時など同じ内容を表示させる場合は2番めのルート、全く新しいアクセスとして取り扱ってもらいたい場合は最初のルートと分けます。ルートを分ければ、ロジックで判断する必要はありません。

しかし、ルートが分かれる、つまり同じ処理に対するURIが分かれるのは好みではないため、この方法を取りませんでした。

これまで、このチュートリアルでは、フォーム表示にGETを、フォームの処理はPOSTを指定しました。これはブラウザから普通にアクセスする場合はGETメソッドですし、フォームを送信する場合はPOSTになりますから、それに一致しています。自然ですね。

POSTでフォーム内容を処理した後は、適当なページにリダイレクトします。今回のコードでは3つあります。

  1. エラー発生時に、メッセージ、入力内容とともにリダイレクト
  2. 新規追加後にIDを付けずにリダイレクト
  3. 更新時にID付きのURIへ入力内容とともにリダイレクト

入力内容と共にリダイレクトされるというのは、with()を使い、セッションの中にフラッシュデーターとして保存され、渡されるという事です。なぜ渡してやるかというと、その内容を表示してもらいたいからです。

つまり、ページで入力された項目のフラッシュデーターが存在すれば、その場合はそのデーターをそのまま表示しする場面です。逆に存在しないのは、新しくアクセスした状況として取り扱ってもらいたい場合です。このセッションデーターの有り無しで判断すれば、上手く動作できそうです。with_input()を使った場合、入力項目はたとえ未入力の状態であっても、セッションには空文字の値のアイテムとして保存されます。

このフラッシュデーターで判断する方法は、適用性があります。例えば新規で追加した後、このコードでは続けて新しく記事を追加できるようにID無しURIへダイレクトし、かつ入力データーを渡していません。ですからGETの処理ではフラッシュデーターが存在しませんし、IDも指定されていませんから、新規扱いとなり空欄で表示されます。

もしこれを「今作成した記事を表示させ、確認する仕様にしたい。変更点があればすぐに修正できるから」というように変更する場合、今度は新しく追加保存したばかりのレコードのIDを取得し、そのIDでURIへリダイレクト、その際にwith_input()で入力を渡してやることで、入力データー=追加されたデーターを再表示できます。

つまり、フラッシュデーターを渡すか渡さないかで、GETのロジックに初期処理扱いをさせるか、それとも渡したデーターを表示させるか、リダイレクト元で指定できます。どうやらこの方法で、変更時にも対応できそうです。

後はフラッシュデーターのチェック方法です。フラッシュデーターの取得はInput::old()を使います。このメソッドは引数なしで入力項目全部を配列で受け取るか、一つの項目を指定して、入力文字列を受け取るか、どちらかの使い方になります。残念ながら、only系メソッドのように配列で指定し、欲しい入力項目だけを受け取る使い方ができません。

フラッシュデーターの存在をチェックするInput::had()も存在しますが、これは単項目のチェックしか出来ません。しかも入力が空、つまりページでその項目が入力されなかった場合、セッションにフラッシュデーターとして存在していてもfalseが返ってきます。存在は存在でも、入力値が存在するかをチェックするメソッドのようです。

そこで、Input::old()でフラッシュデーターとして保存されている入力を全部受け取り、array_only()で必要な2項目に絞ります。そしてその結果が空配列である、つまり有効なセッションデーターが存在しない場合は初回のアクセスとして取り扱い、空配列でない、つまり有効なセッションデーターが存在する場合は、その内容を表示するように処理します。

ちょっとややこしいですが、パターンを決めてしまえば、毎回やることは同じです。

チラ、チラ、チラ、なんだか…ビューの名前も…違っているような。

おや、バレちゃいましたか。add.blade.phpは追加だけをするビューでは無くなったので、form.blade.phpに名前を変えてください。内容は以下の通りです。

@layout('template')

@section('title')
    記事追加/編集
@endsection

@section('content')
    {{ Form::open() }}
        <div>
            {{ Form::label('title', 'タイトル') }}<br>
            {{ Form::text('title', $title) }}
            @if ($errors->has('title'))
                <p style="color: red;">{{ $errors->first('title') }}</p>
            @endif
        </div>
        <div>
            {{ Form::label('body', '本文') }}<br>
            {{ Form::textarea('body', $body) }}
            @if ($errors->has('body'))
                <p style="color: red;">{{ $errors->first('body') }}</p>
            @endif
        </div>
        <div>
            {{ Form::submit('送信') }}
        </div>
    {{ Form::token() }}
    {{ Form::close() }}
@endsection

今回の追加/更新のビューでは表示が単純です。ビューにwith()で出力が渡されますから、$title$bodyは必ず表示されます。表示内容の状況に合わせてセットされていますので、単純に表示するだけです。

さて、では動作を確認してみましょ…う、うーん。動作のためにポストIDを指定するのは面倒ですね。先にindex.blade.phpも変更しましょう。

@layout('template')

@section('title')
    一覧表示
@endsection

@section('content')
    <table>
        <tr>
            <th>タイトル</th>
            <th>作成日</th>
            <th>更新</th>
            <th>削除</th>
        </tr>
        @foreach($posts as $post)
            <tr>
                <td>{{ HTML::link_to_route('post-show', $post->title ,array($post->id)) }}</td>
                <td>{{ $post->created_at }}</td>
                <td>{{ HTML::link_to_route('post-edit', '✜', array($post->id)) }}</td>
                <td>{{ HTML::link_to_route('post-delete', '✖', array($post->id)) }}</td>
            </tr>
        @endforeach
    </table>
@endsection

更新へのリンクを付け加えただけです。もう、どこが違うか分かりますよね。