ユーザーがアクセスするURLを理解して、必要な関数にマップするのがroutes.phpの基本的な仕事です。
それらのURLには、以下のようにいろいろな形があります。
http://localhost/admin/login http://localhost/admin/product/156 http://localhost/admin/product/156/edit
さて、上の例の156の数字は、DBテーブルのproductの主キーの値なのですが、Laravelはこの値をどのようにコントローラに取り込むのでしょう?
まず、前回のroutes.phpの設定を見てみましょう。
Route::resource('product', 'ProductController');
は、
php artisan route:list
の出力では以下のようなマップになります。
+--------+-----------+------------------------------------+------------------------+-----------------------------------------------------------------------+-----------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+------------------------------------+------------------------+-----------------------------------------------------------------------+-----------------+
| | POST | admin/product | admin.product.store | App\Http\Controllers\Admin\ProductController@store | web |
| | GET|HEAD | admin/product | admin.product.index | App\Http\Controllers\Admin\ProductController@index | web |
| | GET|HEAD | admin/product/create | admin.product.create | App\Http\Controllers\Admin\ProductController@create | web |
| | GET|HEAD | admin/product/{product} | admin.product.show | App\Http\Controllers\Admin\ProductController@show | web |
| | DELETE | admin/product/{product} | admin.product.destroy | App\Http\Controllers\Admin\ProductController@destroy | web |
| | PUT|PATCH | admin/product/{product} | admin.product.update | App\Http\Controllers\Admin\ProductController@update | web |
| | GET|HEAD | admin/product/{product}/edit | admin.product.edit | App\Http\Controllers\Admin\ProductController@edit | web |
+--------+-----------+------------------------------------+------------------------+-----------------------------------------------------------------------+-----------------+
URIの部分を見てください。
例えば、7行目の
admin/product/{product}
は、
ProductController@show
にマップされています。
そして156のIDは、この{product}の部分に対応します。
admin/product/{product}/edit
も同じことです。
対応するコントローラのメソッドを見ると、
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Models\Product;
class ProductController extends Controller
{
/**
* 表示画面
*
* @param \App\Models\Product $product
* @return \Illuminate\Http\Response
*/
public function show(Product $product)
{
return $product->name; //画面に商品名を表示
}
...
showのパラメータが、数字でなくモデルのProductのタイプになっていますね。
これは、Laravelが自動的に、IDの数字をもとに、
$product = Product::find(156);
のようなモデルバインディング(紐づけ)操作を行って、Eloquentのオブジェクトを生成して、メソッドの中で使用できるようにしてくれているのです。便利ですね。
さて、product_id = 156に対応するDBレコードがない場合はどうなるのでしょう?
Sorry, the page you are looking for could not be found. 2/2 NotFoundHttpException in Handler.php line 102: No query results for model [App\Product]. 1/2 ModelNotFoundException in Builder.php line 290: No query results for model [App\Product].
「検索結果が空」の404エラーとなります。
今度は、上のshowの関数のパラメータ名を以下のように変えたとしたら、どうなるのでしょう?
public function show(Product $a_product)
{
return $a_product_name;//画面は空
}
この場合、$a_project_nameにはDBレコードが入らず、単にProjectの新規オブジェクトとなり、画面には何も表示されません。
つまり、パラメータ名は、{product}とまったく同じ名前である必要があるということです。ミススペルに気をつけましょう。
さて、今度は、product_idではなく、例えば、skuという商品番号の項目の値でレコードを引っ張ってきたいときはどうするのでしょう?
つまり、
http://localhost/admin/product/ABCDE
でアクセスしたい。そこでは、ABCDがskuの値とします。
その場合は、Productのモデルの定義で、
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $table = 'product';
protected $primaryKey = 'product_id';
public function getRouteKeyName()
{
return 'sku';
}
...
}
のように、getRouteKeyNameの関数を作成して、skuをリターンすれば、product_idの代わりに以下のようにオブジェクトを作成してくれます。
$product = Product::where('sku', 'ABCD')->first();
もちろん、skuは、productのDBテーブルで、主キーと同様に1つのレコードを特定するためにユニークなキーを持つ必要あります。
最後に、
http://localhost/admin/product/156?print=Y
の場合、printの値はどう取ってくるのでしょう?
これはshowメソッドを以下のように変更して、
...
/**
* 表示画面
*
* @param \App\Models\Product $product
* @param \Illuminate\Http\Request
* @return \Illuminate\Http\Response
*/
public function show(Product $product, Request $request)
{
$print = $request->input('print');
return $print;
}
...
printの値の取得が可能です。ここ、関数のパラメータの順番はURLでの順番とは関係ありません。逆でも同じ結果となります。先に説明したように、{product}の名前と一致する変数名でLaravelは判断するからです。
メルマガ購読の申し込みはこちらから。