laravel-5-boilerplateのルーティング（Backend編）

[laravel-5-boilerplateのルーティング](http://qiita.com/shiichi/items/125b4464191a4565df3f)の続きです

以前の記事で app/Http/route.php は読めたので、
次は app/Http/Routes/Backend/Access.php を読み進めます

```
//app/Http/Routes/Backend/Access.php

<?php
Route::group([
    'prefix'     => 'access',
    'namespace'  => 'Access',
    'middleware' => 'access.routeNeedsPermission:view-access-management',
], function() {
    /**
     * User Management
     */
    Route::group(['namespace' => 'User'], function() {
        Route::resource('users', 'UserController', ['except' => ['show']]);
        Route::get('users/deactivated', 'UserController@deactivated')->name('admin.access.users.deactivated');
        Route::get('users/deleted', 'UserController@deleted')->name('admin.access.users.deleted');
        Route::get('account/confirm/resend/{user_id}', 'UserController@resendConfirmationEmail')->name('admin.account.confirm.resend');
        /**
         * Specific User
         */
        Route::group(['prefix' => 'user/{id}', 'where' => ['id' => '[0-9]+']], function() {
            Route::get('delete', 'UserController@delete')->name('admin.access.user.delete-permanently');
            Route::get('restore', 'UserController@restore')->name('admin.access.user.restore');
            Route::get('mark/{status}', 'UserController@mark')->name('admin.access.user.mark')->where(['status' => '[0,1]']);
            Route::get('password/change', 'UserController@changePassword')->name('admin.access.user.change-password');
            Route::post('password/change', 'UserController@updatePassword')->name('admin.access.user.change-password');
        });
    });
    /**
     * Role Management
     */
    Route::group(['namespace' => 'Role'], function() {
        Route::resource('roles', 'RoleController', ['except' => ['show']]);
    });
    /**
     * Permission Management
     */
    Route::group(['prefix' => 'roles', 'namespace' => 'Permission'], function() {
        Route::resource('permission-group', 'PermissionGroupController', ['except' => ['index', 'show']]);
        Route::resource('permissions', 'PermissionController', ['except' => ['show']]);
        Route::group(['prefix' => 'groups'], function() {
            Route::post('update-sort', 'PermissionGroupController@updateSort')->name('admin.access.roles.groups.update-sort');
        });
    });
});

```


##Laravelのルーティングの基本

###ルートの名前

```
Route::get('users/deactivated', 'UserController@deactivated')->name('admin.access.users.deactivated');

```

各ルートに名前をつけることができます
名前を設定すると redirect時などに route('admin.access.users.deactivated')でアクセスできるようになります 

###Route::resource

```
Route::resource('users', 'UserController', ['except' => ['show']]);
```

これで以下のようにコントローラーにアクセスされます

```
namespace App\Controllers;
class helloController extends BaseController
{
    // getでusers/にアクセスされた場合
    public function index()
    {
        〜
    }

    // getでusers/createにアクセスされた場合
    public function create()
    {
        〜
    }

    // postでusers/にアクセスされた場合
    public function store()
    {
        〜
    }
    
    //などなど
}
```

詳しくはこちらの記事で解説されています
http://qiita.com/michiomochi@github/items/de19c560bc1dc19d698c


##解説

まず、ルートグループで以下が設定されています
ルートのプレフィックスに /admin を利用
名前空間が App\Http\Controllers\Language\~~ のコントローラーを利用
ミドルウェア access.routeNeedsPermission:view-access-management を利用

app/Http/Kernel.phpを見に行きます

```
//app/Http/Kernel.php

<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{

    // 省略

    protected $routeMiddleware = [

        // 省略

        'access.routeNeedsRole' => \App\Http\Middleware\RouteNeedsRole::class,
        'access.routeNeedsPermission' => \App\Http\Middleware\RouteNeedsPermission::class,
    ];

```

ミドルウェア名 access.routeNeedsPermission は
app/Http/Middleware/RouteNeedsPermissionを読み込んでいることがわかります

```
//app/Http/Middleware/RouteNeedsPermission.php

<?php

namespace App\Http\Middleware;

use Closure;

class RouteNeedsPermission
{
    public function handle($request, Closure $next, $permission)
    {
        if (! access()->allow($permission)) {
            return redirect()
                ->route('frontend.index')
                ->withFlashDanger(trans('auth.general_error'));
        }

        return $next($request);
    }
}
```

このミドルウェアでは以下のことを行っています
1.  ```$request``` と ```$permission``` を受け取る
2. ```access()->allow($permission)```を評価する
3. route('frontend.index')へリダイレクトさせる  or 次のミドルウェアへ進める

では、```access()->allow($permission)``` の中身を見に行きます
access()はヘルパー関数です
Laravelデフォルトのものではなさそうなのでapp/helper.phpを確認します

```
<?php

//省略

if (! function_exists('access')) {
    /**
     * Access (lol) the Access:: facade as a simple function
     */
    function access()
    {
        return app('access');
    }
}

//省略

```
ありましたね
では次は app/Providers/AccessServiceProvider.php を確認


```
<?php

namespace App\Providers;

use App\Services\Access\Access;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;

/**
 * Class AccessServiceProvider
 * @package App\Providers
 */
class AccessServiceProvider extends ServiceProvider
{

    //省略

    private function registerAccess()
    {
        $this->app->bind('access', function ($app) {
            return new Access($app);
        });
    }

    //省略
}
```


app/Services/Access.phpが正体ですね、見てみましょう

```
//app/Services/Access

<?php

namespace App\Services\Access;

class Access
{
    public $app;

    public function __construct($app)
    {
        $this->app = $app;
    }

    public function user()
    {
        return auth()->user();
    }

    //省略

    public function allow($permission)
    {
        if ($user = $this->user()) {
            return $user->allow($permission);
        }

        return false;
    }

    //省略
}

```

allowメソッドは以下の作業を行います
ログイン中のユーザーのUserクラスのインスタンスを取得し、
```$user->allow($permission)```でパーミッションを所持しているか確認
ユーザーがログインしており、かつ求められたパーミッションを所有している場合のみtrueを返す

では、```$user->allow()``` を見に行きます
userクラスはapp/Models/Access/User.phpに記述されています

```
//app/Models/Access/User.php

<?php
namespace App\Models\Access\User;
use App\Models\Access\User\Traits\UserAccess;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Models\Access\User\Traits\Attribute\UserAttribute;
use App\Models\Access\User\Traits\Relationship\UserRelationship;

class User extends Authenticatable
{
    use SoftDeletes, UserAccess, UserAttribute, UserRelationship;

    protected $guarded = ['id'];

    protected $hidden = ['password', 'remember_token'];

    protected $dates = ['deleted_at'];
}
```

allow()が定義されてないませんが、
これは trait (トレイト)として app/Models/Access/User/Traits/UserAccess.phpを読み込んでいるからです

```
//app/Models/Access/User/Traits/UserAccess.php

<?php

namespace App\Models\Access\User\Traits;

/**
 * Class UserAccess
 * @package App\Models\Access\User\Traits
 */
trait UserAccess
{
    //省略    

    public function allow($nameOrId)
    {
        foreach ($this->roles as $role) {
            //See if role has all permissions
            if ($role->all) {
                return true;
            }

            // Validate against the Permission table
            foreach ($role->permissions as $perm) {

                //First check to see if it's an ID
                if (is_numeric($nameOrId)) {
                    if ($perm->id == $nameOrId) {
                        return true;
                    }
                }

                //Otherwise check by name
                if ($perm->name == $nameOrId) {
                    return true;
                }
            }
        }

        //Check permissions directly tied to user
        foreach ($this->permissions as $perm) {

            //First check to see if it's an ID
            if (is_numeric($nameOrId)) {
                if ($perm->id == $nameOrId) {
                    return true;
                }
            }

            //Otherwise check by name
            if ($perm->name == $nameOrId) {
                return true;
            }
        }

        return false;
    }

    //省略
}
```

ありました！

詳しくは解説しませんが、ログイン中のユーザーがパーミッションを持っているかforeachでループしながら確認しています。

長くなりましたが、これがミドルウェアaccess.routeNeedsPermissionの正体です

もう一度、app/Http/Routes/Backend/Access.phpを確認します

```
//app/Http/Routes/Backend/Access.php

<?php
Route::group([
    'prefix'     => 'access',
    'namespace'  => 'Access',
    'middleware' => 'access.routeNeedsPermission:view-access-management',
], function() {

    /*
     * ルーティング
     */

});

```

access.routeNeedsPermissionにview-access-managementを渡しています
これはミドルウェアaccess.routeNeedsPermission側で$permissionとして受けとり処理を行います

とりあえず以上
気が向いたら追記します