私が開発・管理しているプロジェクトのひとつは、もともとは過去に人気があった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 !!}メルマガ購読の申し込みはこちらから。