laravelの認識で間違っていたこと その1~Route-Controller間のパラメーター~


laravelのRoute-Controller間のパラメーター間違い

言い訳

youtubeなんかの動画や初心者用のwebページなどをみてlaravelにおけるroute-controller間のパラメーターの受け渡しを学びました。(学んだつもりでした。)
まさか他の人が沼にハマるまいとは思いますが、救済する1本の蜘蛛の糸になれば幸いです。

科学の力ってスゲー

フレームワークを利用し始めた当初簡単にsqliteのようなデータベースと接続し、簡単にSELECTできる(値を引っ張ってこれる)ことに感心していました。
「(データがあるテーブル名がpostsの場合)え?Post::find(1)だけでid=1の(レコードの)データをもって来れるの!?科学の力ってスゲー。」

間違い

実際にハマっていた間違い↓

web.php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/post','PostsController@index');
Route::post('/post/{id}','PostsController@detail');
//ルートの設定postで一覧画面、その後ろに数字をつけることで、そのidの詳細画面に行けるようにする 
PostController.php
namespace App\Http\Controllers;

use App\Post;
use Illuminate\Http\Request;

class PostsController extends Controller
{
    public function index()
    {
        $posts = Post::all();
        //postsテーブルの全データ取得

        return view('ichiran',['posts' => $posts]); 
        //表示は「ichiran.blade.php」の方に引数postsを渡して任せる
    }

    public function detail(Post $post)
    {
        $title = $post->title; 
        $body = $post->body; 
        //例えば/postページから/post/1へと遷移した時は$id=1のデータが勝手に取得される

        return view('shousai',['title' => $title,'body' => $body]); 
        //表示は「shousai.blade.php」の方に引数title,bodyを渡して任せる
        //普段は$postをビューの方に渡してそっちで{{ $post->title }}としていますよ、念為。
    }
}

/postページから/post/1へと遷移した時は$id=1のデータが勝手に取得されるなんて程、人生は甘くはないんですねぇ。
何万回試そうが、$id=1のデータは取れず…

最初に見つけた解決策1

PostController.php
namespace App\Http\Controllers;

use App\Post;
use Illuminate\Http\Request;

class PostsController extends Controller
{
    //略

    public function detail(Post $post,$id)//<-new
    {
        $post = Post::find($id);
        //routeの方で{id}と指定したためcontrollerで使いたい時にはfunctionの引数に指定すれば使える
        //よって/post/1へと遷移したら$id=1のデータをfindすることができる

        $title = $post->title; 
        $body = $post->body; 

        return view('shousai',['title' => $title,'body' => $body]); 
    }
}

でもこれなんかスマート(ここで言うスマートとは「引数が多くなってるなぁ、function内の記述もちょっと多いし…なんかもっと削れないんかなぁ」程度のこと)でないなぁ…

試行錯誤し、行きついた解決策2

まずrouteをちょっと変更し、{id}ではなく{post}にします。
そうすると…

web.php
<?php

use Illuminate\Support\Facades\Route;

Route::get('/post','PostsController@index');
Route::post('/post/{post}','PostsController@detail');
PostController.php
namespace App\Http\Controllers;

use App\Post;
use Illuminate\Http\Request;

class PostsController extends Controller
{
    //略

    public function detail(Post $post)//<-new
    {
        $title = $post->title; 
        $body = $post->body; 

        return view('shousai',['title' => $title,'body' => $body]); 
    }
}

これだけで$titleには{post}に渡された数字のデータが入るんですね。ビックリです。

いつも{id}で指定していたので、「なんでリソースコントローラー作るとeditには勝手に任意のデータが読み込まれるのだろう…リソースコントローラー専用なのか、ずるいな」と思っていました。

からくり

detailファンクションの引数にPostモデルのインスタンスを指定してあげた(いわゆるDI)変数名とrouteで指定した変数名を合わせることで、URL内で指定した数値のデータをモデルから持ってくることができるんですね。

え?それの次が知りたい?
それはもっと偉い人に聞いてください。