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