速習Larave3(その12)、役割の導入No.2
Tags : Laravel3
前回は、役割を認証に導入する準備を整えました。今回は続いて実際の処理を入れて行きましょう。
まずはRoleモデルです。
<?php class Role { const GUEST = 0; // ゲスト const REGISTER = 1; // 登録者 const AUTHOR = 10; //投稿者 const ADMINISTRATOR = 100; // 管理者 public static function check_register() { return Auth::check() && Auth::user()->role >= self::REGISTER; } public static function check_author() { return Auth::check() && Auth::user()->role >= self::AUTHOR; } public static function check_administrator() { return Auth::check() && Auth::user()->role >= self::ADMINISTRATOR; } }
役割に関わるところはこのクラスに閉じ込めます。本当はこのクラスを作らず、コーディングし、動作確認した後に見なおしたところ、コードが汚いなあと思い、やはりまとめたほうが良いねという神の声が聞こえたので、クラスに閉じ込めたのです。
check_...
はAuth::check
にあわせて、この名前にしました。それぞれの名前が示す役割以上の権限を持っている場合、trueが返ります。正直、初めのAuth::check() &&
は要らないと言えば、要らないのです。Auth::user()
は存在しないプロパティーを指定された場合、nullを返します。ログインしていないゲストの場合、roleは存在していません。ですから、nullになります。nullは右辺の定数より大きな数字ではないので、成り立ちません。ですから、ゲストの場合、いつもfalseになるため、左のAuth::check()
は無くても構いません。
なぜ書いたのかと言えば、やっていることを明確にするためです。ログインをチェックしていると、読んで分かるからです。もうひとつの理由は、Auth::user()に存在しないプロパティーを指定した場合の値がいつもnullになるというのが、ある時突然変更になっても動作するようです。(まあ、Laravel4の開発も進んでいるので、Laravel3の仕様が大きく変化するとは考えづらいのですけどね。)
続いて、ルートの定義をしましょう。routes.php
を開いて、ルートの定義の部分を以下のとおりに変更してください。
/* * ルーティング定義 */ // トップページ:一覧表示 Route::get('/', array( 'as' => 'post-index', 'uses' => 'post@index' )); // 記事表示 Route::get('/post/(:num)', array( 'as' => 'post-show', 'uses' => 'post@show' )); // ログイン Route::get('/login', array( 'as' => 'login', 'uses' => 'auth@login' )); Route::post('/login', array( 'as' => 'login', 'before' => 'csrf', 'uses' => 'auth@login' )); // ログアウト Route::get('/logout', array( 'as' => 'logout', 'uses' => 'auth@logout' )); // 登録者権限が必要な領域 Route::group(array( 'before' => 'register' ), function() { // 現状なし }); // 投稿者権限が必要な管理者領域 Route::group(array( 'before' => 'author' ), function() { // 記事追加/編集 // フォーム表示 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' )); }); // 管理者権限が必要な管理者領域 Route::group(array( 'before' => 'administrator' ), function() { // 記事削除 // フォーム表示 Route::get('/post/delete/(:num)', array( 'as' => 'post-delete', 'uses' => 'post@delete' )); // フォーム処理 Route::post('/post/delete/(:num)', array( 'as' => 'post-delete', 'before' => 'csrf', 'uses' => 'post@delete' )); });
あれれ、register
とか、author
、administrator
なんて、見慣れないフィルターが増えています。
その通りです。フィルターを追加しました。
Route::filter('register', function() { if ( ! Role::check_register() ) { return Redirect::to_route('login') ->with('message', 'ログインが必要です。'); } }); Route::filter('author', function() { if ( ! Role::check_author() ) { return Redirect::to_route('login') ->with('message', 'ログインが必要です。'); } }); Route::filter('administrator', function() { if ( ! Role::check_administrator() ) { return Redirect::to_route('login') ->with('message', 'ログインが必要です。'); } });
Laravelのルーティングの強力なところは、このように自由にフィルターを定義できることです。自由に定義し、自由に組み合わせることができます。
さらっと書きましたが、とても使いやすく、便利です。このフィルターがあるため、大抵のルートの制限は簡単に既述できます。もちろん、複雑にしたければ、認証ドライバーを作成することもできますし、ルートをDBから読み込んで動的に定義することも可能です。なにせRouteクラスで登録するだけですからね。
さて、動作テストの前に、index.blade.php
も修正しておきましょう。今度は役割に合わせて、できる、できないが変わりました。それに従い、役割に応じて使用できるリンクは表示し、できないリンクは初めから表示しない方針を貫きましょう。
@layout('template') @section('title') 一覧表示 @endsection @section('content') <style> .pagination li { display: inline; margin: 0 5px; } </style> <table> <tr> <th>タイトル</th> <th>作成日</th> @if ( Role::check_author() ) <th>更新</th> @endif @if ( Role::check_administrator() ) <th>削除</th> @endif </tr> @foreach($posts as $post) <tr> <td>{{ HTML::link_to_route('post-show', $post->title ,array($post->id)) }}</td> <td>{{ $post->created_at }}</td> @if( Role::check_author() ) <td>{{ HTML::link_to_route('post-edit', '✜', array($post->id)) }}</td> @endif @if ( Role::check_administrator() ) <td>{{ HTML::link_to_route('post-delete', '✖', array($post->id)) }}</td> @endif </tr> @endforeach </table> {{ $link }} @endsection
もうひとつ、レイアウトも一部変更です。template.blade.php
でしたね。
@section('sidenavi') <li>{{ HTML::link_to_route('post-index', 'ホーム') }}</li> @if ( Auth::guest() ) <li>{{ HTML::link_to_route('login','ログイン') }}</li> @else @if ( Role::check_author() ) <li>{{ HTML::link_to_route('post-edit', '記事追加') }}</li> @endif <li>{{ HTML::link_to_route('logout', 'ログアウト') }}</li> @endif @yield_section
では、動作テストしましょう。ユーザーは3つ用意しました。admin
、auth
、reg
です。
regでは未ログイン時と変わりません。
authでは、記事の追加/更新だけができます。
adminでは、記事削除もできます。
最後に、皆さんに宿題です。ユーザーの追加、変更、削除、一覧表示などを組み込んでください。できる方だけで結構です。これまで行なってきたことが身に付いているか、自分自身でチェックしてください。(私はコーディングしませんから、ソースには入っていませんよ。きっと皆さん、私より上手く作ることでしょう。)
ユーザーに対する操作は、管理者のみができるようにしましょうね。