LaravelのImplicit BindingとgetRouteKeyName() メソッドについて、備忘録でまとめます!
#1. ☆彡Implicit Bindingとは☆彡
URLからid を受け取って、Controllerでそのidを元にデータを引っ張ってくるという流れはよく行われるので、特に記述しなくても、自動的にモデルをデータに結びつけられるImplicit Bindingという仕組みが用意されているのだそう。
例えば、ブログサイトとかで個別記事のURLを『 http://127.0.0.1:8000/articles/1 』のようにしたかった場合。(環境はローカル環境を想定。)
ルートファイル(web.phpね。)の記述は、以下のようになる。
Route::get('/articles/{article}', 'ArticlesController@show');
これにヒットする、ArticlesControllerのshow()メソッドを以下のように書いたとすると。。。
public function show(Article $article) {
return view('articles.show', ['article' => $article]);
}
show(Article $article)の、仮引数の箇所の 『(Article $article)』の記述がImplicit Bindingとなる。
これは、Articleの部分がArticleモデルってことで、$articleの部分が、Articleモデルのインスタンスってことになる。だから、このようなImplicit Bindingの書き方で書くと、『必ずそのモデルのインスタンスが渡ってくる』ってことになる。
で、ここで一つ知っておくべきことは、Implicit Bindingの場合、Laravelはデフォルトで、『該当するモデルのインスタンスのidに対応するデータを取ってくる』ということ。
だから、『 http://127.0.0.1:8000/articles/1 』とか、『 http://127.0.0.1:8000/articles/2 』のようなURLにしたい場合(idを普通の連番にした場合と想定。)は特に問題ないのだけれども、
『 http://127.0.0.1:8000/articles/my-profile 』とか、idではなくtitleとかの違うカラムのデータを引っ張ってきてURLにしたい場合はエラーになってしまう。
(※ ここで、idではないカラムのデータを引っ張ってきたい場合は、該当するモデルファイルにgetRouteKeyName() メソッドを追記することで解決できます。これに関しては後述しています。)
つまり、以下二つのコードは全く同じ結果を返すことになる。
public function show($id) {
$article = Article::findOrFail($id);
return view('articles.show', ['article' => $article]);
}
public function show(Article $article) {
return view('articles.show', ['article' => $article]);
}
1つ目はImplicit Bindingではない書き方で、2つ目はImplicit Bindingで書いたもの。
Implicit Bindingは、『(Article $article)』の部分で、既にArticleモデルのidを引っ張ってきているから、1つ目のコードように、わざわざ『Article::findOrFail($id);』とかを書かなくてもいいというわけ。
因みに、findOrFail()というメソッドですが、例えは『Article::find($id);』と書いたとすると、もしデータベースに登録のないidでアクセスされるとエラー表示されてしまうけれど、findOrFail()であればエラー表示ではなく、『404|Not Found』が表示されるようになるそうです。
!!!注意点!!!
ルートファイルで、ワイルドカード(URLの{}のところ)を変更したら、コントローラーの仮引数の部分も併せて変更しなくてはなりません!↓↓の例のように、赤い文字部分は全部合わせて!
『Route::get('/articles/{foobar}', 'ArticlesController@show');』
『public function show(Article $foobar) {
return view('articles.show', ['article' => $foobar]);
} 』
#2. ☆彡getRouteKeyName() メソッドについて☆彡
さて、前述した通り、Implicit Bindingはデフォルトだと、該当するモデルのインスタンスのidを引っ張ってきてしまうわけすが、これをidではないものにしたい場合は、該当するモデルファイルにgetRouteKeyName() メソッドを以下のように追記することで解決できます。
※ 『return 'slug';』のslugとは、URLの末尾の部分を任意の文字列に指定できる機能のことらしい。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
public function getRouteKeyName() {
return 'slug'; //Article::where('slug', $article)->first() という意味。
}
}
以上です!