親記事
Laravel 5.7で基本的なCRUDを作る - Qiita
要望
ビューの中で、現在のコントローラ名がposts
かどうかを確認したい場合があります。
例えば、グローバルナビで現在の項目を強調したい場合などです。
問題点
Request::is()
リクエストを判別する方法で真っ先に思いつくのはis
メソッドです。
readouble.com: リクエストURIの取得
@if (Request::is('posts/*'))
// postsの場合の処理
@endif
しかし、上のコードでは下記の2番と3番しかTRUEになりません。
1番も含めるためにスラッシュを省いてRequest::is('posts*')
としてもいいのですが、postsenders
のような似通った名前のコントローラがある場合は正しく判別できません。
http://foo.com/posts
http://foo.com/posts/23
http://foo.com/posts/6/edit
アスタリスク*
が使えるので、もしや正規表現で指定できるのではと調べてみました。
しかし、内部でpreg_quote()が使われており、アスタリスク以外の正規表現の特殊文字は無効化されてしまうと判明しました。
ソースコード: Request::is() - 内部でStr::is()が使われている
ソースコード: Str::is() - preg_quote()で特殊文字を無効化
Route::currentRouteName()
currentRouteName
メソッドを使う方法もあります。
readouble.com: 現在のルートへのアクセス
$controllerName = Route::currentRouteName();
// 得られる結果は posts.index, posts.show など。
// トップページの場合はNULLとなる。
posts.index
のようにアクション名も付いてくるのでそれを除去しなければならず、ちょっと面倒です。
しかし、調べた限りではコントローラ名だけを一発で返してくれるメソッドは見当たりませんでした。
仕方ないので、このメソッドの結果に少し手を加えることにします。
解決策
currentRouteName
メソッドの結果を.
を区切りとしてexplodeし、その配列の0番目を取り出します。
これでposts
だけを正しく取得できるようになります。
$controllerName = explode('.', Route::currentRouteName())[0];
ヘルパー関数にする
どのビューでも使えるように、ヘルパー関数を作ります。
ヘルパー関数を自作する方法
自作の方法は下記の通り様々です。
Laravel 5へ自作のヘルパー関数を追加するベストプラクティス | ある蜜柑の上にアルミ缶
今回は、新たに作るヘルパー関数は3~4個と少ないので、上の記事の1番目の「Composerでオートロードする方法」を使います。
まず、空のファイルapp/helpers.php
を作ります。
次に、composer.json
に追記します。
Composer公式ドキュメント: autoload
Composer公式ドキュメント: files
"autoload": {
+ "files": [
+ "app/helpers.php"
+ ],
"classmap": [
"database/seeds",
"database/factories"
],
そして、下記を実行します。
これで、app/helpers.php
内で定義した関数をどこからでも呼び出せるようになります。
Composer公式ドキュメント: dump-autoload
> composer dump-autoload
ちなみに、Laravel本体のヘルパー関数もこれと同じ方法で登録されています。
Laravel本体では2つのファイルに分けて関数を定義しているようです。
{
"autoload": {
"files": [
"src/Illuminate/Foundation/helpers.php",
"src/Illuminate/Support/helpers.php"
],
関連記事: 公式ドキュメントでは言及されていないヘルパー関数
ヘルパー関数を記述する
では、本題の「現在のコントローラ名を取得する関数」を作ります。
正確には、現在のコントローラ名を返すのではなく、引数で渡した複数のコントローラ名が現在のコントローラ名と一致するかどうかを返すようにします。
そうすれば、「現在のコントローラ名がlogin
またはpassword
かどうか」のような複数の条件でも、ビューでの記述量が少なくて済みます。
なお、自作だと分かるように関数名の先頭にmy_
を付けています。
PHP5.6以降で有効な可変長引数を使っています。
<?php
if (! function_exists('my_is_current_controller')) {
/**
* 現在のコントローラ名が、複数の名前のどれかに一致するかどうかを判別する
*
* @param array $names コントローラ名 (可変長引数)
* @return bool
*/
function my_is_current_controller(...$names)
{
$current = explode('.', Route::currentRouteName())[0];
return in_array($current, $names, true);
}
}
自作のヘルパー関数を使用する
レイアウトを下記のように修正します。
現在のコントローラ名と一致する場合は、BootstrapのCSSクラス名active
を追加したり、HTML要素を表示させたりする処理を追加しています。
<div class="collapse navbar-collapse" id="navbarSupportedContent">
{{-- Navbarの左側 --}}
<ul class="navbar-nav mr-auto">
{{-- 「記事」と「ユーザー」へのリンク --}}
- <li class="nav-item">
- <a class="nav-link" href="{{ url('posts') }}">{{ __('Posts') }}</a>
+ <li class="nav-item @if (my_is_current_controller('posts')) active @endif">
+ <a class="nav-link" href="{{ url('posts') }}">
+ {{ __('Posts') }}
+ @if (my_is_current_controller('posts'))
+ <span class="sr-only">(current)</span>
+ @endif
+ </a>
</li>
- <li class="nav-item">
- <a class="nav-link" href="{{ url('users') }}">{{ __('Users') }}</a>
+ <li class="nav-item @if (my_is_current_controller('users')) active @endif">
+ <a class="nav-link" href="{{ url('users') }}">
+ {{ __('Users') }}
+ @if (my_is_current_controller('users'))
+ <span class="sr-only">(current)</span>
+ @endif
+ </a>
</li>
</ul>
(中略)
{{-- 認証関連のリンク --}}
@guest
{{-- 「ログイン」と「ユーザー登録」へのリンク --}}
- <li class="nav-item">
- <a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
+ <li class="nav-item @if (my_is_current_controller('login', 'password')) active @endif">
+ <a class="nav-link" href="{{ route('login') }}">
+ {{ __('Login') }}
+ @if (my_is_current_controller('login', 'password'))
+ <span class="sr-only">(current)</span>
+ @endif
+ </a>
</li>
- <li class="nav-item">
- <a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
+ <li class="nav-item @if (my_is_current_controller('register')) active @endif">
+ <a class="nav-link" href="{{ route('register') }}">
+ {{ __('Register') }}
+ @if (my_is_current_controller('register'))
+ <span class="sr-only">(current)</span>
+ @endif
+ </a>
</li>
@else