laravel5のリクエストURLに変数を用いる方法


### やりたいこと

* サブナビを実装したい
* Viewの中にincludeフォルダを作って、共通パーツとして読み込ませる
* 一覧,新規登録,詳細,編集,削除のリンクをつける
* 一覧,新規登録画面では一覧,新規登録だけをリンクに表示
* 詳細,編集,削除画面では上記に加え詳細,編集,削除のリンクを表示
* 自分自身のURLにアクセスした際にはactiveクラスをつける。
* 例えば新規登録にアクセスしたらサブナビの新規登録の部分にactiveクラスがつく。
* 後はそれをCSSで装飾するなりなんなり。Bootstrapならactiveクラスをつけたら色がつくはず。

### インクルード方法

ドキュメント見たらわかる話だけど念のため説明

View 「subnavi.blade.php」
パスは views/admin/items/include/subnavi.blade.php とする。
別にディレクトリ名は inc でも includes でもいいけど私はこれにしてます。

```
<ul>
	<li><a href="#">リンク名</a></li>
	<li><a href="#">リンク名</a></li>
</ul>
```

View 「index.blade.php」
パスは views/admin/items/index.blade.php とする

```
<html>
<head></head>
<body>
	<ul>
		<li><a href="#">リンク名</a></li>
		<li><a href="#">リンク名</a></li>
	</ul>
</body>
</html>

↓

<html>
<head></head>
<body>
@include('admin.items.include.subnavi')
</body>
</html>
```

あとはcreate.blade.phpとかshow.blade.phpとかそういうのにも同じように@includeの記述を書く

### 失敗例

View 「subnavi.blade.php」

```
<ul>
    <li class="{{ Request::is('admin/items') ? 'active' : '' }}">
        <a href="/admin/items">一覧</a>
    </li>
    <li class="{{ Request::is('admin/items/create') ? 'active' : '' }}">
        <a href="/admin/items/create">新規登録</a>
    </li>
    @if(!empty($item -> id))
    <li class="{{ Request::is('admin/items/{{$item -> id}}') ? 'active' : '' }}">
        <a href="/admin/items/{{$item -> id}}">詳細</a>
    </li>
    <li class="{{ Request::is('admin/items/{{$item -> id}}/edit') ? 'active' : '' }}">
        <a href="/admin/items/{{$item -> id}}/edit">編集</a>
    </li>
    <li class="{{ Request::is('admin/items/{{$item -> id}}/delete') ? 'active' : '' }}">
        <a href="/admin/items/{{$item -> id}}/delete">削除</a>
    </li>
    @endif
</ul>
```

上のコードは動作しない。原因はこれ。

```
{{ Request::is('admin/items/{{$item -> id}}') ? 'active' : '' }} // これが動かない


{{ Request::is('admin/items/{!!$item -> id!!}') ? 'active' : '' }} // これも動かない

{{ Request::is('admin/items/$item -> id') ? 'active' : '' }} // これも動かない

<?php $id = $item -> id ?>
{{ Request::is('admin/items/$id') ? 'active' : '' }} // 変数に代入しても動かない

// これは動くが、これだとワイルドカードなので期待動作にはならない。編集画面なのに詳細と編集の両方にactiveクラスがつくみたいなのが起きる。
{{ Request::is('admin/items/*') ? 'active' : '' }}

// これは /admin/items/create にアクセスした時に動く。念のため。
{{ Request::is('admin/items/create') ? 'active' : '' }}

```

何とかして変数を使いたい。。変数というか、数値が可変する部分を表現できたらいいなって

### 実装

次のようにする。

View 「subnavi.blade.php」

```
<?php
if( ! function_exists('is_route'))
{
	/**
	 * Alias for Request::is(route(...))
	 *
	 * @return mixed
	 */
	function is_route()
	{
		$args = func_get_args();
		foreach($args as &$arg)
		{
			if(is_array($arg))
			{
				$route = array_shift($arg);
				$arg = ltrim(route($route, $arg, false), '/');
				continue;
			}
			$arg = ltrim(route($arg, [], false), '/');
		}
		return call_user_func_array(array(app('request'), 'is'), $args);
	}
}
?>

<ul>
	<li class="{{ is_route(['admin.items.index']) ? 'active' : '' }}">
		<a href="/admin/items">一覧</a>
	</li>
	<li class="{{ is_route(['admin.items.create']) ? 'active' : '' }}">
		<a href="/admin/items/create">新規登録</a>
	</li>
	@if(!empty($item -> id))
	<li class="{{ is_route(['admin.items.show', $item -> id]) ? 'active' : '' }}">
		<a href="/admin/items/{{ $item -> id }}">詳細</a>
	</li>
	<li class="{{ is_route(['admin.items.edit', $item -> id]) ? 'active' : '' }}">
		<a href="/admin/items/{{ $item -> id }}/edit">編集</a>
	</li>
	<li class="{{ is_route(['admin.items.delete', $item -> id]) ? 'active' : '' }}">
		<a href="/admin/items/{{ $item -> id }}/delete">削除</a>
	</li>
	@endif
</ul>
```

### UIKitへの対応について

私の環境はBootstrapじゃなくてUIKitなのでそちらでの記述方法も説明。おとなしくBootstrap使ってくれればいいものを。。

View 「subnavi.blade.php」

```
<?php
if( ! function_exists('is_route'))
{
	/**
	 * Alias for Request::is(route(...))
	 *
	 * @return mixed
	 */
	function is_route()
	{
		$args = func_get_args();
		foreach($args as &$arg)
		{
			if(is_array($arg))
			{
				$route = array_shift($arg);
				$arg = ltrim(route($route, $arg, false), '/');
				continue;
			}
			$arg = ltrim(route($arg, [], false), '/');
		}
		return call_user_func_array(array(app('request'), 'is'), $args);
	}
}
?>

<div class="uk-margin uk-grid">
	<div class="uk-width-medium-1-1">
		<div>
			<ul class="uk-tab">
				<li class="{{ is_route(['admin.items.index']) ? 'uk-active' : '' }}">
					<a href="/admin/items">一覧</a>
				</li>
				<li class="{{ is_route(['admin.items.create']) ? 'uk-active' : '' }}">
					<a href="/admin/items/create">新規登録</a>
				</li>
				@if(!empty($item -> id))
				<li class="{{ is_route(['admin.items.show', $item -> id]) ? 'uk-active' : '' }}">
					<a href="/admin/items/{{ $item -> id }}">詳細</a>
				</li>
				<li class="{{ is_route(['admin.items.edit', $item -> id]) ? 'uk-active' : '' }}">
					<a href="/admin/items/{{ $item -> id }}/edit">編集</a>
				</li>
				<li class="{{ is_route(['admin.items.delete', $item -> id]) ? 'uk-active' : '' }}">
					<a href="/admin/items/{{ $item -> id }}/delete">削除</a>
				</li>
				@endif
			</ul>
		</div>
	</div>
</div>
```

### エラーが起きるんですけど

Route [admin.items.delete] not defined. とか出る場合。

ルーティング時にNameをつけ忘れていることが原因。
以下のコードで調べる

```
php artisan route:list
```

```
+--------+-----------+--------------------------+---------------------+----------------------------------------------------+------------+
| Domain | Method    | URI                      | Name                | Action                                             | Middleware |
+--------+-----------+--------------------------+---------------------+----------------------------------------------------+------------+
|        | POST      | admin/items              | admin.items.store   | App\Http\Controllers\Admin\ItemsController@store   | web        |
|        | GET|HEAD  | admin/items              | admin.items.index   | App\Http\Controllers\Admin\ItemsController@index   | web        |
|        | GET|HEAD  | admin/items/create       | admin.items.create  | App\Http\Controllers\Admin\ItemsController@create  | web        |
|        | GET|HEAD  | admin/items/{id}/delete  |                     | App\Http\Controllers\Admin\ItemsController@delete  | web        |
|        | DELETE    | admin/items/{id}/delete  |                     | App\Http\Controllers\Admin\ItemsController@destroy | web        |
|        | DELETE    | admin/items/{items}      | admin.items.destroy | App\Http\Controllers\Admin\ItemsController@destroy | web        |
|        | GET|HEAD  | admin/items/{items}      | admin.items.show    | App\Http\Controllers\Admin\ItemsController@show    | web        |
|        | PUT|PATCH | admin/items/{items}      | admin.items.update  | App\Http\Controllers\Admin\ItemsController@update  | web        |
|        | GET|HEAD  | admin/items/{items}/edit | admin.items.edit    | App\Http\Controllers\Admin\ItemsController@edit    | web        |
+--------+-----------+--------------------------+---------------------+----------------------------------------------------+------------+
```

deleteのネームルーティングができてなかった

app/routes.php

```
<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/

Route::get('/admin/items', function () {
    return view('.admin.items.index');
});

Route::resource('/admin/items', 'Admin\\ItemsController');

Route::get('/admin/items/{id}/delete','Admin\\ItemsController@delete');
Route::delete('/admin/items/{id}/delete','Admin\\ItemsController@destroy');
```

次のように修正

```
<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/

Route::get('/admin/items', function () {
    return view('.admin.items.index');
});

Route::resource('/admin/items', 'Admin\\ItemsController');

Route::get('/admin/items/{id}/delete','Admin\\ItemsController@delete')->name('admin.items.delete');
Route::delete('/admin/items/{id}/delete','Admin\\ItemsController@destroy')->name('admin.items.destroy');
```

これで動くはず。動かなかったら知らない。ごめん。


### 改善

nunulk 様から頂いた非常にナイスな書き方を受けて改善。
そうだね、「 . 」で追加すりゃよかったね…危うく読解不能な謎コードを錬成するところでした。危ない危ない。

Bootstrapの場合
<?php ~ ?> の記述は全て削除してください
View 「subnavi.blade.php」

```
<ul>
	<li class="{{ Request::is('admin/items') ? 'active' : '' }}">
		<a href="/admin/items">一覧</a>
	</li>
	<li class="{{ Request::is('admin/items/create') ? 'active' : '' }}">
		<a href="/admin/items/create">新規登録</a>
	</li>
	@if(!empty($item -> id))
	<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id) ? 'active' : '' }}">
		<a href="/admin/items/{{ $item -> id }}">詳細</a>
	</li>
	<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id . '/edit') ? 'active' : '' }}">
		<a href="/admin/items/{{ $item -> id }}/edit">編集</a>
	</li>
	<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id . '/delete') ? 'active' : '' }}">
		<a href="/admin/items/{{ $item -> id }}/delete">削除</a>
	</li>
	@endif
</ul>
```

UIKitの場合
<?php ~ ?> の記述は全て削除してください
View 「subnavi.blade.php」

```

<div class="uk-margin uk-grid">
	<div class="uk-width-medium-1-1">
		<div>
			<ul class="uk-tab">
				<li class="{{ Request::is('admin/items') ? 'uk-active' : '' }}">
					<a href="/admin/items">一覧</a>
				</li>
				<li class="{{ Request::is('admin/items/create') ? 'uk-active' : '' }}">
					<a href="/admin/items/create">新規登録</a>
				</li>
				@if(!empty($item -> id))
				<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id) ? 'uk-active' : '' }}">
					<a href="/admin/items/{{ $item -> id }}">詳細</a>
				</li>
				<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id . '/edit') ? 'uk-active' : '' }}">
					<a href="/admin/items/{{ $item -> id }}/edit">編集</a>
				</li>
				<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id . '/delete') ? 'uk-active' : '' }}">
					<a href="/admin/items/{{ $item -> id }}/delete">削除</a>
				</li>
				@endif
			</ul>
		</div>
	</div>
</div>
```