ルートモデルバインディングを備えたよりクリーンなLaravelコントローラー
序章
ウェブサイトを構築するためのフレームワークまたはAPIを構築するためのコンテナー( lumen )としてのLaravelは、開発者が選択するフレームワークとして進化してきました。 Laravelには、多くの機能が追加されています。たとえば、Laravelのイベントを取り上げます。 Laravelのイベントは、以前は単純なpub-subライブラリでしたが、Laravelイベントをクライアントにブロードキャストできるようになり、リアルタイムアプリを作成できるようになりました。
しかし、それは重要なことではありませんが、今日の有名人はLaravelのルートモデルバインディングです。
ルートモデルバインディングとは
Laravelのルートモデルバインディングは、モデルインスタンスをルートに注入するメカニズムを提供します。 まだ意味がはっきりしていませんが、ここに例を示します。 データベースから投稿を取得したい場合は、次のようにすることができます。
... // the route parameter is the id of the post // for example http://example.com/posts/53 Route::get('posts/{id}', function ($id) { // we have to find the post using the $id $post = Post::find($id); // if there is no post, 404 if (!$post) return abort(404); // return the view and the post return view('post.show', compact('post')); }); ...
この方法をさらに単純化して、
... // the route parameter is the id of the post // for example http://awesome.dev/posts/53 Route::get('posts/{id}', function ($id) { // find the post or 404 if not found $post = Post::findOrFail($id); // return the view and the post return view('post.show', compact('post')); }); ...
ただし、ルートモデルバインディングは、上記の両方のインスタンスを単純化することにより、余分なキーストロークを取り除くのに役立ちます。
... // by using $post, we can inject the Post object Route::get('posts/{post}', function ($post) { // we now have access to the $post object! no code necessary // return the view and the post return view('post.show', compact('post')); }); ...
これは、LaravelにPost
モデルを{post}
パラメーターが付加されているルートコントローラーに注入するように指示することで可能になります。
Laravelは現在、2種類のルートモデルバインディングをサポートしています。 我々は持っています:
- 暗黙的なモデルバインディング
- 明示的なモデルバインディング
注:上記のルートモデルバインディングの例は明示的です。
暗黙的なモデルバインディング
明示的なモデルバインディングを見てきましたが、暗黙的なモデルバインディングの例を次に示します。
Route::get('posts/{post}', function (App\Post $post) { // be awesome. enjoy having the $post object });
Laravelは、Post
モデルがコントローラークロージャーに注入されているため、ルートからid
パラメーターを取得し、ユーザーの詳細を取得する必要があることを知っているほど賢いです。
投稿へのアクセスは、引き続きhttp://awesome.example.com/posts/24
を使用して行われます。
モデルのルートキーの変更
モデルを取得するときに暗黙のモデルバインディングでid
以外のデータベース列を使用する場合は、EloquentモデルのgetRouteKeyName
メソッドをオーバーライドできます。
たとえば、id
の代わりにslug
を使用する場合は、次のように実行できます。
class Post extends Model { public function getRouteKeyName() { return 'slug'; } }
次に、http://awesome.example.com/posts/24
の代わりにhttp://awesome.example.com/posts/my-post-slug
を使用してルートにアクセスできます。
明示的なモデルバインディング
名前が示すように、url
パラメーターを特定のモデルにバインドするようにLaravelに明示的に指示する必要があります。 これを行うには2つの方法があります。提供されているRoute
ファサードを使用してパラメーターをモデルにバインドするか、app/Providers/RouteServiceProvider.php
でこのバインドを実行します(この方法が好きです)。
Route
ファサードの使用
Route
ファサードを使用してパラメーターをモデルにバインドすると、次のようになります。
Route::bind('post', 'App\Post');
また、バインディングにもっと意味を持たせることもできます。たとえば、ドラフトの場合にのみ投稿が必要な場合はどうでしょうか。 そのために、Route::bind
の2番目のパラメーターを、ルートパラメーターを値として取るクロージャーに変更できます。
Route::bind('post', function ($value) { return App\Post::find($value)->where('status', '=', 'published')->first(); });
RouteServiceProvider
を使用する
Route
ファサードとRouteServiceProvider
クラスの使用の唯一の違いは、バインディングの登録がRouteServiceProvider
クラスのboot
メソッドで行われることです(場所はapp/Providers
ディレクトリ)およびbind
メソッドは、メソッドに挿入された$router
オブジェクトで呼び出されます。 簡単な例
public function boot(Router $router) { parent::boot($router); $router->bind('post', function ($value) { return App\Post::find($value)->where('status', '=', 'published')->first(); }); }
ルートモデルバインディングのカスタム例外
私は多くのAPIを構築しているので、ルートモデルバインディングのカスタム例外は、実際には私のような人々にとってより便利です。 Laravelは私たちがこれを行うための簡単な方法を提供します。 RouteServiceProvider
クラスのboot
メソッドで、$router
オブジェクトのmodel
メソッドを呼び出します。
model
メソッドは3つの引数を取ります。引数は、bind
メソッドの引数と似ていますが、新しい例外をスローするクロージャである3番目の引数が新たに追加されています。
$router->model($routeParameter, $modelToBind, function () { throw new NotFoundHTTPException; });
結論
ルートモデルバインディングの詳細については、ドキュメントを参照してください。
うまくいけば、この小さいながらもきちんとした機能により、プロジェクトのコードを数行節約し、コントローラーをよりクリーンにすることができます。