速習Larave3(その12)、役割の導入No.2
タグ: 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では、記事削除もできます。
最後に、皆さんに宿題です。ユーザーの追加、変更、削除、一覧表示などを組み込んでください。できる方だけで結構です。これまで行なってきたことが身に付いているか、自分自身でチェックしてください。(私はコーディングしませんから、ソースには入っていませんよ。きっと皆さん、私より上手く作ることでしょう。)
ユーザーに対する操作は、管理者のみができるようにしましょうね。