見出し画像

[laravel8] ルート・モデル・バインディング

ルート・モデル・バインディングとは?

いきなり例から見てみます。

routes/web.php

// /posts/(記事ID) 記事IDが$idになる
Route::get('/posts/{post}', function ($id) {

   // 記事IDが$idの記事を取得
   $post = Post::findOrFail($id);

   // $post(記事)
   return view('post', [
       'post' => $post
   ]);
});

このルーティングは

の記事で説明したように、URLから記事IDを取得してからその記事IDを使い記事(Post)モデルをfindOrFailメソッドを使って探しています。

ルート・モデル・バインディングとは、記事IDをURLから取得するのでなく、直接記事(Post)モデルをURLから取得する機能のことです。

具体例

ではどのように使うのか見てみましょう。

routes/web.php

// /posts/(記事ID) 記事モデルが$postになる
Route::get('/posts/{post}', function (Post $post) {

   // $post(記事)
   return view('post', [
       'post' => $post
   ]);
});

routeのコールバック関数のパラメータに$idではなく、直接

Post $post

と、Postモデルのインスタンスが入ってきています。

http://localhost:8000/posts/2

のアクセスが来たら、laravelは記事IDが2の記事(Post)モデルのインスタンスを$postとして扱うことができます。

注意点

routeのワイルドカードの名前変数の名前と一致しなければなりません。

Route::get('/posts/{post}', function (Post $post) {...}

もし$post変数の名前を$fooに変えたりすると動きません。

Route::get('/posts/{post}', function (Post $foo) {...} // 動きません

具体的には

Route::get('/posts/{post}', function (Post $post) {...}

このようにPostタイプヒントされた場合、Laravelは変数の名前($post)とワイルドカードの名前({post})が一致するか調べます。もし一致する場合はLaravelは『URLにあるIDのPostモデルを探しているのかな』と仮定し、そのIDのPostモデルインスタンスを自動的に返してくれます。

id以外のカラムを使う場合

上記の説明ではテーブルのidカラムを使用していましたが(デフォルト)、もちろんidカラム以外を使うこともできます。制限はカラムがuniqueである必要があるだけです。

の記事で使ったcreate_posts_tableのファイルを編集してslugカラムを追加します。

database/migrations/2021_05_07_111050_create_posts_table.php

    public function up()
   {
       Schema::create('posts', function (Blueprint $table) {
           $table->id();
           $table->string('slug')->unique(); // uniqueにする必要があります。
           $table->string('title');
           $table->text('excerpt');
           $table->text('body');
           $table->timestamps();
           $table->timestamp('published_at')->nullable();
       });
   }
$php artisan migrate:fresh

migrate freshコマンドでslugを追加します。テーブルのデータは全て消えるので。コピーしてslugも追加します。

スクリーンショット 2021-05-18 21.46.25

スクリーンショット 2021-05-18 21.48.58

方法1

routes/web.php

Route::get('/posts/{post:slug}', function (Post $post) {

   // $post(記事)
   return view('post', [
       'post' => $post
   ]);
});

ワイルドカードを設定するところで

{post:slug}

とslugカラムを使用すると指定しています。

ここで内部的にはどのようになってるかと言うと

Post::where('slug', $post)->firstOrFail();

が実行されてPostモデルを探しています。

方法2

Postモデルを変更し、slugを使うことを明示します。

app/Models/Post.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
   use HasFactory;

   protected $guarded = [];

   public function getRouteKeyName()
   {
       return 'slug';
   }

}

getRouteKeyNameメソッドを追加し、 slugをリターンして明示してます。

この場合はrouteのワイルドカードでslugを明示する必要はありませんので以下のようになります。

routes/web.php

// /posts/(記事ID) 
Route::get('/posts/{post}', function (Post $post) {

   // $post(記事)
   return view('post', [
       'post' => $post
   ]);
});

最後に

この段階でのソースコードはこちら


この記事が気に入ったらサポートをしてみませんか?