Laravelでデータの更新(実践編その5)

今日は、『Laravelでデータの新規作成』で作成したデータの更新方法を調べてみたいと思います。editアクションとeditビューを作成しますが、その前にindexビューから指定データへ移動できるようにしたいと思います。

1. index.blade.phpを下記のように修正します。

laravel/application/views/collection/index.blade.php

@layout('layouts.master')
@section('navigation')
 <li>{{ HTML::link('collection/index','トップページ') }}</li>
 <li>{{ HTML::link('collection/create','新規作成') }}</li>
@endsection
@section('content')
<table class="table table-striped table-bordered">
 <tr>
 <th>id</th>
 <th>タイトル</th>
 <th>作成日</th>
 <th>更新日</th>
 <th>保管場所</th>
 <th>処理</th>
 </tr>
@foreach($collections as $row)
 <tr>
 <td>{{ $row->id }}</td>
 <td>{{ $row->title }}</td>
 <td>{{ $row->created_at }}</td>
 <td>{{ $row->updated_at }}</td>
 <td>{{ $row->save_space }}</td>
 <td>{{ HTML::link_to_action('collection@edit','更新',array($row->id)) }}</td>
 </tr>
@endforeach
</table>
{{ $links }}
@endsection
  • 2~5行目:マスタービューのnavigationをビューファイルから修正するために記述しています。マスタービューを書き直さなくてもこのような使い方で、既存のナビゲーションを修正できます。下図①
  • 23行目:link_to_actionメソッドで、コントローラアクションへのリンクを生成します。第1引数がコントローラアクションのパス、第2引数が表示文字列、第3引数がワイルドカード値です。下図②。下記のようなリンクを生成します。
     http://localhost/laravel/public/collection/edit/183 
  • 27行目:ページネーション用のリンクです。下図③

※尚、collection@editで使用しているパスの指定方法ですが、公式ドキュメントでアットマーク”@”になっていたので、”@”で記述していますが、ピリオド”.”でも、スラッシュ”/”でも同じURLを生成します。この違いが今のところ不明です。理由が判明したら後日お知らせしたいと思います。

2. ブラウザではこんな感じになります。

http://localhost/laravel/public/collection/

Fluentクエリービルダーでデータの更新

3. collectionコントローラにeditアクションを作成します。

laravel/application/controllers/collection.php 

//更新ページeditアクション
 public function action_edit($id=null){
 //もしデータが送信されたら
 if($input=Input::all()){
 //バリデーションルールの定義
 $rules=array(
 'title'=>'required|max:100',
 'col_code'=>'required|alpha_dash',
 'save_space'=>'required',
 );
 //バリデーションをインスタンス化
 $val=Validator::make($input,$rules);
 //バリデーションNGなら
 if($val->fails()){
 //エラーと一緒に現ページへリダイレクト
 return Redirect::to(URL::current())
 ->with_errors($val)
 }else{
 //Fluentクエリービルダーでデータの更新
 $update=DB::table('collections')
 // Where句でデータの選択
 ->where('id','=',Input::get('id'))
 /* 動的Where句でデータの選択
 ->where_id(Input::get('id'))*/
 ->update($input);
 //トップページへリダイレクト
 return Redirect::to('collection/index');
 }
 }
 //Fluentクエリービルダーでデータを取得
 $data['collections']=DB::table('collections')->find($id);
 return View::make('collection/edit',$data);
 }
  • 16行目:リダイレクト先は、ワイルドカードも一緒に指定しないといけないので、現在のURLを取得するURL::current()メソッドを使用しています。
  • 24行目:コメントアウトしていますが、22行目と全く同じ動作をします。Laravelでは、動的Whereメソッドを使用することにより、コードの記述をこのように簡略化できます。

3. editビューを下記のように作成します。

laravel/application/views/collection/edit.blade.php

@layout('layouts.master')
@section('navigation')
 <li>{{ HTML::link('collection/index','トップページ') }}</li>
 <li>{{ HTML::link('collection/create','新規作成') }}</li>
@endsection
@section('content')
 {{ Form::open(URL::current(),'POST',array('class'=>'form-horizontal')) }}
 <fieldset>
 <div class="control-group {{ $errors->has('title') ? 'error' : '' }}">
 {{ Form::label('title','タイトル名',array('class'=>'control-label')) }}
 <div class="controls">
 {{ Form::text('title',$collections->title) }}
 {{ $errors->has('title') ? $errors->first('title','<p><span class="label label-important">:message</span></p>') : '' }}
 </div>
 </div>
 <div class="control-group">
 {{ Form::label('col_code','コード番号',array('class'=>'control-label')) }}
 <div class="controls">
 {{ Form::text('col_code',$collections->col_code) }}
 {{ $errors->has('col_code') ? $errors->first('col_code','<p><span class="label label-important">:message</span></p>') : '' }}
 </div>
 </div>
 <div class="control-group">
 {{ Form::label('save_space','保管場所',array('class'=>'control-label')) }}
 <div class="controls">
 {{ Form::text('save_space',$collections->save_space) }}
 {{ $errors->has('save_space') ? $errors->first('save_space','<p><span class="label label-important">:message</span></p>') : '' }}
 </div>
 </div>
 <div class="form-actions">
 {{ Form::hidden('id',$collections->id) }}
 {{ Form::submit('データ更新',array('class'=>'btn btn-primary')) }}
 </div>
 </fieldset>
 {{ Form::close() }}
@endsection

4.  ブラウザで確認してみます。

http://localhosst/laravel/pulbic/collection/edit/183

5. タイトル名を修正してみます。下記のようになりました。

EloquentORMでデータの更新

6. 次はEloquentORMでデータを更新してみたいと思います。editアクションを下記のように修正します。

laravel/public/contorollers/collection.php 

//更新ページeditアクション
 public function action_edit($id=null){
 //もしデータが送信されたら
 if($input=Input::all()){
 //バリデーションルールの定義
 $rules=array(
 'title'=>'required|max:100',
 'col_code'=>'required|alpha_dash',
 'save_space'=>'required',
 );
 //バリデーションをインスタンス化
 $val=Validator::make($input,$rules);
 //バリデーションNGなら
 if($val->fails()){
 //エラーを取得して現ページへリダイレクト
 return Redirect::to(URL::current())
 ->with_errors($val);
 }else{
 //EloquentORMでデータの更新
$update=Collection::where_id(Input::get('id'))
 ->update($input);
//トップページへリダイレクト
 return Redirect::to('collection/index');
 }
 }
 //EloquentORMでデータを取得
 $data['collections']=Collection::find($id);
 return View::make('collection/edit',$data);
 }

7. データを更新してブラウザで確認してみます。

8. データは更新されているのですが、updated_atの値が更新されていません。timestampプロパティをtrueにして、モデルに記述したりしてみたのですが、やはり、updated_atは更新されません。createメソッドでは、created_atとupdated_atが自動的に記述されるのですが、updateメソッドでは、自動的に更新されるようになっていないみたいです。

9. updated_atを自動更新するには、findメソッドでプライマリーキーを指定し、モデルの各プロパティに値を入力後、saveメソッドを使う必要があるみたいです。19~21行目を下記のように修正します。

//EloquentORMでデータの更新
 $update=Collection::find(Input::get('id'));
 $update->title=Input::get('title');
 $update->col_code=Input::get('col_code');
 $update->save_space=Input::get('save_space');
 $update->save();

10. これで、再度データを更新したら、updated_at(更新日)も更新されていました。updateメソッドでもupdated_atを自動更新する方法があったら後日ご報告します。

本日は、以上です。

このエントリーを含むはてなブックマーク Buzzurlにブックマーク livedoorクリップ Yahoo!ブックマークに登録

トラックバック&コメント

この投稿のトラックバックURL:

トラックバック

コメント

  1. HiroKws より:

    こんにちは
    6.の書き方でタイムスタンプの更新日が更新されないのは、多分バグでしょう。ただ、ORMはデータベースを通常のモデルとして扱うために使用するわけです。ですからSQL擬似メソッドをチェーンで指定するFluentの記法で書くことは、できるんですが、本来の使用法ではたぶんありません。(使う人がいないため、バグとして潜んでいるのでしょう。)
    9.の方法がEloquent的には正しいということになります。コードを見てSQLを感じさせるのではなく、あくまでモデルに対する操作のように読めます。(他のORMと呼ばれているライブライリーがSQLを感じさせすぎるのでしょうね。正直、私はEloquentを使用するまで、ORMのメリットがよく理解できませんでした。Laravel全体の読みやすさ重視という主張の流れで、Eloquentを見て、こういうORMなら使いたいと思いました。)
    ちなみに例で上げられているように、ビューのフィールド名とデータベースのカラム(フィールド・属性)名が一致している場合、複数代入 http://laravel.kore1server.com/docs/database/eloquent#mass-assignment が便利に使用できますよ。便利ですが、これを使用するときはホワイトリストを設定するか、もしくはInputクラスを直接使用せず、更新に必要な項目を予め配列に移しておくことをおすすめします。array_only()という便利なヘルパーメソッドも用意されています。$inputs = array_only(Input::all, array(‘title’, ‘col_code’,’save_space’))でしょうか。(試していません)

  2. HiroKws より:

    input::all()でしたね。

  3. HiroKws より:

    多少情報を追加しておりますが、修正していただくという意図は持っておりません。念の為。 😉
    あくまで、情報提供が目的です。
    array_only()を使うよりは、Input::only()を使用したほうが、スマートでした。自分の過去のコード読んで、思い出しました。
    input::get()は一項目取り出す時に使用し、項目が見つからない場合、第二パラメーターで指定したデフォルト値がリターンされます。
    input::only()は項目一つの場合は、文字列で、二つ以上の場合は配列で指定します。指定項目が入力で見つからない場合は、空配列がリターンされます。(コードを読む限り。 😀 リターンされないコードを書いたことがありませんから、試していません。 😉 )

    • nakada より:

      川瀬 様
      いつも貴重な情報をありがとうございます。
      川瀬様のコメントを楽しみに読ませていただいています。
      本当にLaravelは楽しいですよね。
      PHPを覚え立ての頃の感動が蘇ってくるようです。
      これからもよろしくお願いします。
      WinRoad徒然草管理人 中田


コメントをどうぞ

このページの先頭へ