LoginSignup
1
3

More than 3 years have passed since last update.

[Laravel]Implicit BindingとgetRouteKeyName() メソッドについて

Last updated at Posted at 2021-05-10

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の末尾の部分を任意の文字列に指定できる機能のことらしい。

Article.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    public function getRouteKeyName() {
      return 'slug'; //Article::where('slug', $article)->first() という意味。
    }
}

以上です!

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3