You are here
Home > routesを使いこなす(連載)

Laravel 5.3 resourceでの名前付きrouteの変更

以前に、Route::resourceの便利さを紹介しました。

routesを使いこなす(1)resourceを使う

routesを使いこなす(2)resourceを使いこなす

また、名前付きrouteがもたらす便宜さも紹介しました。

routesを使いこなす(4)routeを名付ける

しかし、Laravel 5.3のバージョンアップで「ちょっと、それはないよ」みたいな問題が出てきました。

Route::resourceでは、名前付きrouteが自動で作成されます。

例えば、Laravel 5.2では、routes.phpにこう設定すると、

Route::group(['prefix' => 'admin', 'middleware' => 'web', 'namespace' => 'Admin'], function () {

    Route::resource('product', 'ProductController');

});

以下のように名前付きroutesがprefixをもとに設定されます。「Name」の列です。

+--------+-----------+------------------------------+-----------------------+---------------------------------------------------------------+------------+
| Domain | Method    | URI                          | Name                  | Action                                                        | Middleware |
+--------+-----------+------------------------------+-----------------------+---------------------------------------------------------------+------------+
|        | POST      | admin/product                | admin.product.store   | App\Http\Controllers\Admin\ProductController@store            | web,web    |
|        | GET|HEAD  | admin/product                | admin.product.index   | App\Http\Controllers\Admin\ProductController@index            | web,web    |
|        | GET|HEAD  | admin/product/create         | admin.product.create  | App\Http\Controllers\Admin\ProductController@create           | web,web    |
|        | DELETE    | admin/product/{product}      | admin.product.destroy | App\Http\Controllers\Admin\ProductController@destroy          | web,web    |
|        | PUT|PATCH | admin/product/{product}      | admin.product.update  | App\Http\Controllers\Admin\ProductController@update           | web,web    |
|        | GET|HEAD  | admin/product/{product}      | admin.product.show    | App\Http\Controllers\Admin\ProductController@show             | web,web    |
|        | GET|HEAD  | admin/product/{product}/edit | admin.product.edit    | App\Http\Controllers\Admin\ProductController@edit             | web,web    |
+--------+-----------+------------------------------+-----------------------+---------------------------------------------------------------+------------+

しかし、おなじ、routes.phpをLaravel 5.3に持っていくと(もちろん、web.phpと改名して、app/Httpからroutes/のディレクトリに移して)、

+--------+-----------+------------------------------+-----------------+---------------------------------------------------------------+------------+
| Domain | Method    | URI                          | Name            | Action                                                        | Middleware |
+--------+-----------+------------------------------+-----------------+---------------------------------------------------------------+------------+
|        | POST      | admin/product                | product.store   | App\Http\Controllers\Admin\ProductController@store            | web,web    |
|        | GET|HEAD  | admin/product                | product.index   | App\Http\Controllers\Admin\ProductController@index            | web,web    |
|        | GET|HEAD  | admin/product/create         | product.create  | App\Http\Controllers\Admin\ProductController@create           | web,web    |
|        | DELETE    | admin/product/{product}      | product.destroy | App\Http\Controllers\Admin\ProductController@destroy          | web,web    |
|        | PUT|PATCH | admin/product/{product}      | product.update  | App\Http\Controllers\Admin\ProductController@update           | web,web    |
|        | GET|HEAD  | admin/product/{product}      | product.show    | App\Http\Controllers\Admin\ProductController@show             | web,web    |
|        | GET|HEAD  | admin/product/{product}/edit | product.edit    | App\Http\Controllers\Admin\ProductController@edit             | web,web    |
+--------+-----------+------------------------------+-----------------+---------------------------------------------------------------+------------+

なんと!
admin.product.store ⇒ product.store とadmin.が皆消えてしまいました。

ドキュメントを読むと、どうもこのprefixの設定は、resourceの名前付きrouteに反映される意図はなかったとのことで、5.3で修正という訳です。

以前と同様な、名前付きのrouteとするためには、asを使用して、以下のように設定します。

Route::group(['prefix' => 'admin', 'as' => 'admin.', 'middleware' => 'web', 'namespace' => 'Admin'], function () {

    Route::resource('product', 'ProductController');

});

注意:adminでなく、admin.です。最後にドットが必要。

あるいは、ひとつひとつを命名するというオプションもあります。しかし、これはちょっと。。

Route::group(['prefix' => 'admin', 'middleware' => 'web', 'namespace' => 'Admin'], function () {

    Route::resource('product', 'ProductController', ['names' => ['index' => 'admin.product.index']]);

});

routesを使いこなす(5)モデルとのバインディング

ユーザーがアクセスする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は判断するからです。

routesを使いこなす(4)routeを名付ける

Laravelでは、routeに名前を付けることができます。いったいそれがどうした?と思いますが、これができることで便利なことが増えます。

まず、routeの名前の付け方から、


Route::get('admin/ranking/download', 'RankingController@download');

routes.phpに指定して、

php artisan route:list

を実行すると、

+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
| Domain | Method    | URI                     | Name                   | Action                                                |
+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
|        | GET|HEAD  | admin/ranking/download  |                        | App\Http\Controllers\Admin\RankingController@download |

を出力します。3列名のNameの列に注目してください。

今は空ですね。

しかし、


Route::get('admin/ranking/download', 'RankingController@download')->name('admin.ranking.download');

とすると、

+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
| Domain | Method    | URI                     | Name                   | Action                                                |
+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
|        | GET|HEAD  | admin/ranking/download  | admin.ranking.download | App\Http\Controllers\Admin\RankingController@download |

admin.ranking.downloadと名前が付きます。

現在は、URIのスラッシュ(/)をピリオド(.)に置き換えたフォーマットですが、admin:ranking_downloadでも、admin::rankingdownloadでもOKです。

さて、routeにresourceを使用するときはどうなるのでしょう?

例えば、

Route::resource('product', 'ProductController');

は、

+--------+-----------+------------------------------------+------------------------+-----------------------------------------------------------------------+-----------------+
| 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             |
+--------+-----------+------------------------------------+------------------------+-----------------------------------------------------------------------+-----------------+

と自動で名前を付けてくれます。

routeに名前が付いたところで、どう使用するか見てみましょう。

echo route('admin.ranking.download');

は、

http://localhost/admin/ranking/download

となります。もちろん、localhostはライブ環境では実際のドメイン名となります。

ということは、

echo url('admin/ranking/download');

と同じになります。

引数があるときは、

echo route('admin.product.edit', 12);
echo url('admin/product', [12, 'edit']);

の出力は、両方とも、

http://localhost/admin/product/12/edit

となりますが、名前付きの方がわかりやすいですね。

このroute()は、

return redirect()->route('admin.product.show', 12);

のようにリダイレクトや、


{!! Form::open(['route' => ['admin.product.store'], 'method' => 'post']) !!}

のようにテンプレートでも使用可能です。

もちろん、名前付きのrouteをプログラムで使用するなら、そのrouteのURIを変えても何もプログラムで変更は要らないことになります。便利ですね。

さらに、URIに比べて比較的扱いやすい文字列なので、名前付きのrouteに対してユーザーの権限をDBで定義すれば、例えば、ログインしたユーザーの役割により、特定のrouteを実行するかどうかの権限の判断にも使用可能です。将来、この連載で扱う予定のトピックです。

routesを使いこなす(3)prefixでgroupを分割

開発しているプログラムの機能が増えてくると、必然的に定義するrouteの数が増えてきます。特に、マルチ認証ともなると、関わるプレイヤーの分だけで倍増する可能性があります。

例えば、ECのプロジェクトで、会員と管理者がプレイヤーとすると、ログインだけでも2通りのURIが必要となり、routeの設定は以下のように4つ必要となります。

Route::group(['middleware' => 'web'], function () {
	Route::get('user/login', 'User\Auth\AuthController@showLoginForm');
	Route::post('user/login', 'User\Auth\AuthController@login');
	Route::get('admin/login', 'Admin\Auth\AuthController@showLoginForm');
	Route::post('admin/login', 'Admin\Auth\AuthController@login');
});

実際作成されるrouteは、

php artisan route:list

の実行によると、

+--------+----------+-------------+------+--------------------------------------------------------------+-----------------+
| Domain | Method   | URI         | Name | Action                                                       | Middleware      |
+--------+----------+-------------+------+--------------------------------------------------------------+-----------------+
|        | POST     | admin/login |      | App\Http\Controllers\Admin\Auth\AuthController@login         | web,guest:admin |
|        | GET|HEAD | admin/login |      | App\Http\Controllers\Admin\Auth\AuthController@showLoginForm | web,guest:admin |
|        | POST     | user/login  |      | App\Http\Controllers\User\Auth\AuthController@login          | web,guest       |
|        | GET|HEAD | user/login  |      | App\Http\Controllers\User\Auth\AuthController@showLoginForm  | web,guest       |
+--------+----------+-------------+------+--------------------------------------------------------------+-----------------+

これに他のいくつもの機能を加えていくと、管理が大変になってきます。現在私が管理しているプロジェクトでは、管理画面だけで300近いrouteが存在します。そうなると、タイプミスも増えるでしょうし、一目見て理解もしにくいです。

管理性を高める1つの方法は、prefixを使用してroutesのgroupを分割します。

先の例では、useradminprefixを用いて、それぞれのプレイヤーに1つのgroupを作成します。

Route::group(['prefix' => 'user', 'namespace' => 'User', 'middleware' => 'web'], function () {
	Route::get('login', 'Auth\AuthController@showLoginForm');
	Route::post('login', 'Auth\AuthController@login');
});

Route::group(['prefix' => 'admin', 'namespace' => 'Admin', 'middleware' => 'web'], function () {
	Route::get('login', 'Auth\AuthController@showLoginForm');
	Route::post('login', 'Auth\AuthController@login');
});

行数が少し増えたかもしれませんが、重複部分がなくなってすっきりしただけでなく、グループ分けで理解しやすいコードとなりましたね。さらに、namespaceを使用することで、コントローラのnamespaceも重複も省いています。

さて、実際生成されるrouteはどうなのでしょう?この変更で変わってしまっては問題です。

php artisan route:list

を実行すると、

+--------+----------+-------------+------+--------------------------------------------------------------+-----------------+
| Domain | Method   | URI         | Name | Action                                                       | Middleware      |
+--------+----------+-------------+------+--------------------------------------------------------------+-----------------+
|        | POST     | admin/login |      | App\Http\Controllers\Admin\Auth\AuthController@login         | web,guest:admin |
|        | GET|HEAD | admin/login |      | App\Http\Controllers\Admin\Auth\AuthController@showLoginForm | web,guest:admin |
|        | POST     | user/login  |      | App\Http\Controllers\User\Auth\AuthController@login          | web,guest       |
|        | GET|HEAD | user/login  |      | App\Http\Controllers\User\Auth\AuthController@showLoginForm  | web,guest       |
+--------+----------+-------------+------+--------------------------------------------------------------+-----------------+

まったく先と同じです。

routesを使いこなす(2)resourceを使いこなす

resourceを使い始めて、まず思うのは、いつもいつも index, store, create, edit, update, destroyの一式が必要というわけではないことです。

例えば、以下のようなレポートタイプのコントローラなら、

report

indexだけで十分なので、以下のようにonlyを使い他のrouteを無効にします。


Route::resource('ranking', 'RankingController.php', ['only' => ['index']]);

また、追加と編集だけで、削除が要らないコントローラなら、exceptを使い、index, store, create, edit, updateだけの使用を可能にします。


Route::resource('no_destroy', 'NoDestroyController.php', ['except' => ['destroy']]);

便利ですね。

さらに、 index, store, create, edit, update, destroyだけでないrouteが必要なときもあります。

例えば、先の「売上ランキング」のレポートに、結果をCSVでダウンロードしたいとします。

今のところ、indexしか使用していないので、storeでも使う?

しかし、名前がいまひとつ。理想は、ranking/downloadとしたいです。

このような場合は、


Route::get('admin/ranking/download', 'RankingController@download');
Route::resource('admin/ranking', 'RankingController', ['only' => ['index']]);

と、独自のrouteをRoute::resourceの前に追加します。

php artisan route:list

の出力は、

+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
| Domain | Method    | URI                     | Name                   | Action                                                |
+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
|        | GET|HEAD  | admin/ranking           | admin.ranking.index    | App\Http\Controllers\Admin\RankingController@index    |
|        | GET|HEAD  | admin/ranking/download  |                        | App\Http\Controllers\Admin\RankingController@download |

routesを使いこなす(1)resourceを使う

私が開発・管理しているプロジェクトのひとつは、もともとは過去に人気があったCodeIgniterで書かれたもの。過去2年の間に、それをLaravelのバージョン4で書き直し、さらに更新して現在はLaravelのバージョン5.2となっています。

それゆえに、最初のLaravelを使っての書き換えは、Laravelを勉強しながらの書き換えで、知らないことが多く、Route::controllerを多用していました。

コントローラは以下のように作成して、

class ProductController extends Controller
{
...
	public function getAdd() {...}
	public function postAdd() {...}
	public function getEdit(Product $product) {..}
	public function postEdit(Product $product) {..}
...
}

メソッドには、getやpostのプリフィックスが必要です。
次は、routeを設定します。

...
	Route::controller('product', 'ProductController.php');
...

これを

php artisan route::list

で実行して見るとこんな感じに出力されます。

+--------+--------------------------------+------------------------------------------------------------+-----------------------+-----------------------------------------------------------------------+-----------------+
| Domain | Method                         | URI                                                        | Name                  | Action                                                                | Middleware      |
+--------+--------------------------------+------------------------------------------------------------+-----------------------+-----------------------------------------------------------------------+-----------------+
|        | GET|HEAD                       | admin/product/add/{one?}/{two?}/{three?}/{four?}/{five?}  |                       | App\Http\Controllers\Admin\ProductController@getAdd                  | web             |
|        | POST                           | admin/product/add/{one?}/{two?}/{three?}/{four?}/{five?}  |                       | App\Http\Controllers\Admin\ProductController@postAdd                 | web             |
|        | GET|HEAD                       | admin/product/edit/{one?}/{two?}/{three?}/{four?}/{five?} |                       | App\Http\Controllers\Admin\ProductController@getEdit                 | web             |
|        | POST                           | admin/product/edit/{one?}/{two?}/{three?}/{four?}/{five?} |                       | App\Http\Controllers\Admin\ProductController@postEdit                | web             |
|        | GET|HEAD|POST|PUT|PATCH|DELETE | admin/product/{_missing}                                  |                       | App\Http\Controllers\Admin\ProductController@missingMethod           | web             |

さて、ここでの問題は、デフォルトでは、URIが、

admin/product/edit/{one?}/{two?}/{three?}/{four?}/{five?}

となりgetEditの関数のパラメータがrouteに反映されないことです。

うえは、

admin/product/{product}/edit

とあるべきです。

これを正しくするには、

...
Route::model('product', 'App\Models\Product');  
...
Route::get('product/add', 'ProductController@getAdd');
Route::post('product/add', 'ProductController@getAdd');
Route::get('product/{product}/edit', 'ProductController@getEdit');
Route::post('product/{product}/edit', 'ProductController@getEdit');
...

と、やたらroutes.phpにおいての記述が多くなってしまいます。ウェブのアプリのほとんどは、DBでのレコードの閲覧、作成、編集、削除などの定型です。簡単にならないものでしょうか?

そこで、Route::resourceの登場です。

ちなみに、Route::controllerは、バージョン5.1まではLaravelのマニュアルに説明がありましたが、現バージョン5.2ではなくなりました(コードではまた対応はしているようです)。

もうRoute::controllerはリタイヤが近づいているということで、Route::resourceに切り替えるちょうど良い機会です。

まず、以下のコマンドを実行してひな形を作成します。

php artisan make:controller ProductController --resource

作成されたファイルを編集して、

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;

use App\Models\Product;

class ProductController extends Controller
{
    /**
     * 検索表示
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * 新規作成画面
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * DBレコード新規作成
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * 表示画面
     *
     * @param  \App\Models\Product $product
     * @return \Illuminate\Http\Response
     */
    public function show(Product $product)
    {
        //
    }

    /**
     * 編集画面
     *
     * @param  \App\Models\Product $product
     * @return \Illuminate\Http\Response
     */
    public function edit(Product $product)
    {
        //
    }

    /**
     * DBレコード編集
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \App\Models\Product $product
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, Product $product)
    {
        //
    }

    /**
     * DBレコード削除
     *
     * @param  \App\Models\Product $product
     * @return \Illuminate\Http\Response
     */
    public function destroy(Product $product)
    {
        //
    }
}

Route::Controllerと比較すると、resourceのメソッドは、

getAdd   → create
postAdd  → store
getEdit  → edit
postEdit → update

となります。

routesを設定すると、

...
	Route::resource('product', 'ProductController.php');
...

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             |
|        | PUT|PATCH | admin/product/{product}            | admin.product.update  | App\Http\Controllers\Admin\ProductController@update                   | web             |
|        | DELETE    | admin/product/{product}            | admin.product.destroy | App\Http\Controllers\Admin\ProductController@destroy                  | web             |
|        | GET|HEAD  | admin/product/{product}/edit       | admin.product.edit    | App\Http\Controllers\Admin\ProductController@edit                     | web             |
| 

URIも自動で設定され、さらに名前付きのroute (named route)も設定されていますね。

さて、admin.product.updateのPUTやPATCHはどうbladeのフォームで対応するのでしょう?HTMLの<form>のactionにはGETとPOST以外見たことありませんね。

もちろん、簡単です。

<form method="POST" action="admin/product/{{$product->product_id}}">
     {!! method_field('put') !!}
     . . .
</form>

method_field()は、Laravelのヘルパー関数で、以下と同じです。

<input type="hidden" name="_method" value="PUT">

そして、以前紹介した、Laravel Collectiveのフォームを使用するなら、

{!! Form::open(['route' => ['admin.product.update', $product->product_id], 'method' => 'put']) !!}
..
{!! Form::close !!}
Top