Laravel4、UserクラスでCRUD

タグ: Laravel4  

Laravel4 ベータ4がリリースされました。

どんなふうに変わっているのかを紹介するため、認証にも使用するUserクラスを使用して、紹介していきます。

なお、現在の開発バージョンはベータ5で、正式版リリースまで後約1から2ヶ月です。5月リリース予定ですからね。正式版では変更される部分もあると思います。予めご了承ください。

なお、タイトルはCRUDですが、今回行うのはCUまでです。残りのRDは応用で、簡単ですからね。皆さん自分で試してください。

usersテーブルの準備

データベース設定ファイルの内容はほぼ変更ありません。Laravel3の時と同様に設定してください。

データベースを設定したら、マイグレーション初期化のため、管理テーブルを作成しましょう。Artisanコマンドラインツールを使用します。

  1. php artisan migrate:install

Artisanも進歩しまして、php artisanだけ打ち込むと、コマンドを表示してくれます。忘れた時の確認に使用できます。

環境の設定はLaravel3の頃と変わりません。--env=localでローカル環境、つまりconfig/localフォルダー中の設定ファイルの内容が優先して使用されます。

マイグレーション初期化が終了しましたら、usersテーブルを生成するマイグレーションを書きましょう。usersテーブルの生成はコマンドによる自動化がされていません。私はこれに賛成します。なぜなら、usersテーブルにどの様な情報を入れるか、どの項目を認証に使用するかは、開発者やプロジェクトごとに差がある部分ですから、自動化する意味があまりないと思っています。(ぶっちゃけ、一度作成した他のプロジェクトからコピーしたほうが早いし、分かりやすいですからね。)

まずは、マイグレーションファイルを生成しましょう。

  1. php artisan migrate:install CreateUsersTable

基本的にはLaravel3と変わりません。Laravel4からcomposerに乗っかりPSR-0とかPSR−1とか2とかに準拠する関係上、関数名はローアーキャメル、クラス名はアッパーキャメル記法ですので、それに合わせています。

コマンド実行するとapp/database/migratationsに作成日時と指定したクラス名のファイル名がついたphpファイルが生成されます。それをエディターで開いてください。

内容を以下のように更新し、保存します。

  1. <?php
  2.  
  3. use Illuminate\Database\Migrations\Migration;
  4.  
  5. class CreateUsersTable extends Migration
  6. {
  7.  
  8. /**
  9. * Run the migrations.
  10. *
  11. * @return void
  12. */
  13. public function up()
  14. {
  15. Schema::create( 'users',
  16. function($table)
  17. {
  18. $table->increments( 'id' );
  19. $table->string( 'username', 32 );
  20. $table->string( 'email', 320 );
  21. $table->string( 'password', 64 ); // 最低60文字
  22. $table->integer('rank');
  23. $table->timestamps();
  24. } );
  25. }
  26.  
  27. /**
  28. * Reverse the migrations.
  29. *
  30. * @return void
  31. */
  32. public function down()
  33. {
  34. Schema::dropIfExists('users');
  35. }
  36.  
  37. }

テーブル生成はLaravel3と同じです。ドロップでは、dropIfExistsメソッドが追加されました。これは、メソッド名が示す通り、テーブルが存在する場合にドロップを行うものです。マイグレーションの順番を間違えたり、生成でエラーが置きたりした結果、テーブルができていないのにdown()のドロップを行い、エラが発生し、マイグレーションのロールバックが上手く動作しないことがLaravel3ではありました。それを防ぐためこのメソッドが作成された様子です。基本、down()メソッドの中では、このdropIfExistsメソッドを使用しましょう。

マイグレーションファイルを作成したら、マイグレーションを実行しましょう。

  1. php artisan migrate

実際に作成されていることを、ツール類で確認してみましょう。

Userクラスの定義

続いてサンプルデータの生成を行いたいところですが、先にUserクラスを作リましょう。現在のベータ4ではUserクラスのひな形がapp/modelsディレクトリーに用意されています。以下のように多少変更してください。

  1. <?php
  2.  
  3. use Illuminate\Auth\UserInterface;
  4. use Illuminate\Auth\Reminders\RemindableInterface;
  5.  
  6. class User extends Eloquent implements UserInterface, RemindableInterface {
  7.  
  8. /**
  9. * このモデルで使用されるデータベース名
  10. *
  11. * @var string
  12. */
  13. protected $table = 'users'; // デフォルト通りのため、必要なし
  14.  
  15. /**
  16. * JSON形式への変換時に、対象外にするフィールド
  17. *
  18. * @var array
  19. */
  20. protected $hidden = array('password');
  21.  
  22. // 以下のプロパティ追加
  23. /**
  24. * 複数代入禁止フィールド指定
  25. *
  26. * @var array
  27. */
  28. protected $guarded = array('id');
  29.  
  30. /**
  31. * ユーザーを一意に特定するIDを取得
  32. *
  33. * @return mixed
  34. */
  35. public function getAuthIdentifier()
  36. {
  37. return $this->getKey();
  38. }
  39.  
  40. /**
  41. * ユーザーのパスワードを取得
  42. *
  43. * @return string
  44. */
  45. public function getAuthPassword()
  46. {
  47. return $this->password;
  48. }
  49.  
  50. /**
  51. * パスワードリマンダーを送信するメールアドレスの取得
  52. *
  53. * @return string
  54. */
  55. public function getReminderEmail()
  56. {
  57. return $this->email;
  58. }
  59.  
  60. // 以下のメソッド追加
  61. /**
  62. * パスワードセッター
  63. *
  64. * @param string $value
  65. */
  66. public function setPasswordAttribute($value)
  67. {
  68. $this->attributes['password'] = Hash::make($value);
  69. }
  70.  
  71. }

Eloquentモデルです。デフォルトではクラス名複数型の小文字がテーブル名になります。

Laravel3と大きく異なるのはコンストラクタやfillメソッドで、配列を指定することでキーと同じ名前のインスタンスのプロパティーに代入してくれる複数代入の機能です。Laravel3では、デフォルトでは全項目代入可能になっていました。Laravel4ではセキュリティー的に強化するため、全項目代入禁止になっています。

$guardedか$fillableプロパティーを指定し、代入禁止、もしくは代入許可を指定する必要があります。

セッター(ミューテーター)のメソッド名も変更になりました。set属性名Attributeです。属性名は先頭一文字大文字、残りは小文字です。

シーディング

さて、シーディングへ戻りましょう。

データベースの初期データ設定をシーディング(seeding)と言います。シーディングのための機能も追加されました。ベータ期間中も、かなり変更されている部分です。

app/database/seedsディレクトリーにシーディングのためのクラスを定義しましょう。今回はUsersTableSeeder.phpファイルです。

  1. <?php
  2.  
  3. class UsersTableSeeder extends Seeder
  4. {
  5.  
  6. public function run()
  7. {
  8. DB::table( 'users' )->delete();
  9.  
  10. User::create( array (
  11. 'username' => 'user1',
  12. 'password' => 'pass1',
  13. 'email' => 'user1@x.com',
  14. 'rank' => 100, // 管理者
  15. ) );
  16.  
  17. User::create( array (
  18. 'username' => 'user2',
  19. 'password' => 'pass2',
  20. 'email' => 'user2@x.com',
  21. 'rank' => 1,
  22. ) );
  23.  
  24. User::create( array (
  25. 'username' => 'user3',
  26. 'password' => 'pass3',
  27. 'email' => 'user3@x.com',
  28. 'rank' => 1,
  29. ) );
  30. }
  31.  
  32. }

シーディングに使用するクラスはSeederクラスを拡張し、中にrunメソッドを用意します。

内容はご覧の通りです。先にユーザークラスを作成していますので、パスワードなどもそのまま記述できます。

これを実行するには以下のArtisanコマンドを実行します。

  1. php artisan db:seed UsersTableSeeder

これでUsersテーブルにサンプルデータが生成されました。しかし、いちいちクラス名を指定するのは面倒です。

実はクラス名を指定しない時のデフォルトはapp/database/seedsのDatabaseSeeder.phpで定義されているDatabaseSeederクラスになっています。このrunメソッドから、自分で作成したシーディングクラスを呼び出すようにすることで、まとめてシーディングが実行できるようになっています。

  1. <?php
  2.  
  3. class DatabaseSeeder extends Seeder {
  4.  
  5. /**
  6. * Run the database seeds.
  7. *
  8. * @return void
  9. */
  10. public function run()
  11. {
  12. Eloquent::unguard(); // 複数代入の保護機能を停止
  13.  
  14. $this->call('UsersTableSeeder');
  15. // 他のシーディングも同様に続けて書いておく
  16. }
  17.  
  18. }

これで、まとめてシーディングを実行したい時はクラスを指定しないでdb:seedを実行し、個別にシーディングしたい場合はクラス名を指定して実行するというように、使い分けができるようになりました。

新規作成

説明が長くなりますので、今回ルートはコントローラではなくrouts.phpに記述します。

  1. Route::get( '/user/add', function()
  2. {
  3. return View::make( 'user.create' );
  4. } );
  5.  
  6. Route::post( '/user/add',
  7. array ( 'before' => 'csrf', function()
  8. {
  9. $inputs = Input::only( array ( 'username', 'email', 'password' ) );
  10.  
  11. $rules = array (
  12. 'username' => array ( 'required', 'min:4', 'max:32', 'unique:users' ),
  13. 'password' => array ( 'required', 'min:6', 'max:30' ),
  14. 'email' => array ( 'required', 'email', 'max:320', 'unique:users' ),
  15. );
  16.  
  17. $val = Validator::make( $inputs, $rules );
  18.  
  19. if ( $val->fails() )
  20. {
  21. return Redirect::back()->withErrors( $val )->withInput();
  22. }
  23.  
  24. $inputs['rank'] = 1;
  25. User::create( $inputs );
  26.  
  27. return Redirect::back();
  28. } ) );
  29.  

ビューです。app/views/user/create.blade.phpです。

  1. {{ Form::open() }}
  2. <p>
  3. {{ Form::label('username', 'ユーザー名') }}
  4. {{ Form::text('username', Input::old('username', '')) }}
  5. @if ($errors->has('username'))
  6. {{ $errors->first('username') }}
  7. @endif
  8. </p>
  9. <p>
  10. {{ Form::label('password', 'パスワード') }}
  11. {{ Form::password('password') }}
  12. @if ($errors->has('password'))
  13. {{ $errors->first('password') }}
  14. @endif
  15. </p>
  16. <p>
  17. {{ Form::label('email', 'メール') }}
  18. {{ Form::text('email', Input::old('email', '')) }}
  19. @if ($errors->has('email'))
  20. {{ $errors->first('email') }}
  21. @endif
  22. </p>
  23. {{ Form::submit('登録') }}
  24. {{ Form::token() }}
  25. {{ Form::close() }}

Formクラスが復活したため、Laravel3とたいして違いがありません…

…実は、違わないように書いてみました。このように、ほぼ同じようにかけます。ですから、Laravel3で身につけたスキルが無駄になるわけでありません。

これでは面白くありませんね。Laravel4の機能を活用して、今度は更新処理を書いてみましょう。

更新処理

ルートの部分です。

  1. // Laravel4の新機能
  2.  
  3. Route::model( 'user', 'User' ); // {user}とUserクラスを結びつける
  4.  
  5. Route::get( '/user/{user}', // 存在しないIDなら、404
  6. function(User $user)
  7. {
  8. // この時点で$userは存在しているレコード
  9. return View::make( 'user.update' )->with( 'user', $user );
  10. } );
  11.  
  12. Route::post( '/user/{user}', // 存在しないIDなら、404
  13. array ( 'before' => 'csrf', function(User $user)
  14. {
  15. // この時点で$userは存在しているレコード
  16. $inputs = Input::only( array ( 'username', 'email', 'password' ) );
  17.  
  18. $rules = array (
  19. 'username' => array ( 'required', 'min:4', 'max:32', 'unique:users,username,'.$user->id ),
  20. 'password' => array ( 'required', 'min:6', 'max:30' ),
  21. 'email' => array ( 'required', 'email', 'max:320', 'unique:users,email,'.$user->id ),
  22. );
  23. $val = Validator::make( $inputs, $rules );
  24.  
  25. if ( $val->fails() )
  26. {
  27. return Redirect::back()->withErrors( $val )->withInput();
  28. }
  29.  
  30. $user->fill( $inputs )->save();
  31.  
  32. return Redirect::back();
  33. } ) );

Laravel4ではルートの可変部分に名前を付けられるようになりました。他のフレームワークでもできるものが多いですよね。更に、その名前にEloquentモデルを結びつけることができます。

後は、ルートをご覧いただくと分かります。{user}部分にIDが来るわけです。そのIDがテーブルに存在しなければ、404エラーになります。Laravel3でまともに動作するCRUDを書けば必ずIDのチェックは必要でした。(Laravel3でなくても、何を使おうと必要です。)Laravel4はIDのチェックを取り込んでしまいました。

ですから、ルートの内側に制御が渡ってきた時点で$userのユーザー情報はテーブル上に存在しており、$userはそれを獲得したものですので、安心して使用できます。

今度はビューをご覧ください。app/views/user/update.blade.phpです。

  1. {{ Form::model($user) }}
  2. <p>
  3. {{ Form::label('username', 'ユーザー名') }}
  4. {{ Form::text('username') }}
  5. @if ($errors->has('username'))
  6. {{ $errors->first('username') }}
  7. @endif
  8. </p>
  9. <p>
  10. {{ Form::label('password', 'パスワード') }}
  11. {{ Form::password('password') }}
  12. @if ($errors->has('password'))
  13. {{ $errors->first('password') }}
  14. @endif
  15. </p>
  16. <p>
  17. {{ Form::label('email', 'メール') }}
  18. {{ Form::text('email') }}
  19. @if ($errors->has('email'))
  20. {{ $errors->first('email') }}
  21. @endif
  22. </p>
  23. {{ Form::submit('登録') }}
  24. {{ Form::token() }}
  25. {{ Form::close() }}

createビューとどこが違うか、分かりますか。

フォームのオープンがopenメソッドの代わりにmodelメソッドを使用しています。これが新機能です。

たぶん、この機能のためにFormクラスを復活させたのだと思われます。

modelメソッドで開くと、フォームの入力要素の生成メソッドで、渡したEloquentモデルのインスタンスの属性名と同じフィールド名の値を表示してくれるのです。

しかも、フォーム入力内容の処理でバリデーションエラーが発生した場合、リダイレクトに対してwithInputメソッドで入力値をフラッシュデーターとしてセッションに保存しますが、セッション中に入力項目と同じキーのアイテムが保存されている場合、優先的にそちらを表示してくれます。

つまり、上記のコードの通り、いちいちフォームに表示する内容を、例えばForm::text('name', Input::old('name', ...)))なんて形で指定する必要がありません。ご覧の通り、すっきりです。

楽しいでしょう?次は認証を見てみましょう。こちらも便利になっていますよ。