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

By khino