背景
Laravel でモデル結合ルートパラメータに整数を期待すると、文字列を渡したときにエラーになる。
例として hoges テーブルの1レコードを表示する画面を考えてみます。
Schema::create('hoges', function ($table) {
$table->increments('id'); // 主キーが連番の整数
...
});
Route::resource('hoges', 'HogeController');
public function show(Hoge $hoge) // モデル結合している
{
...
}
GET /hoges/str
にアクセスすると次の SQL エラーになる。
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: "str" (SQL: select * from "hoges" where "id" = str limit 1)
さらに GET /hoges/2147483648
にアクセスすると次の SQL エラーになる。
SQLSTATE[22003]: Numeric value out of range: 7 ERROR: value "2147483648" is out of range for type integer (SQL: select * from "hoges" where "id" = 2147483648 limit 1)
解決策
公式な対応
これについて公式のリポジトリに Issue があります。
PR も1件ありますが、"this changes a contract" とのことでマージぜすクローズされています。
PR のクローズを最後に半年以上動きがない状態が続いています。
暫定的な対応
モデル結合ルートはロジックをカスタマイズできるので、ロジックにバリデーションを追加しました。
トレイトとして実装して、必要なモデルで使えるようにしています。
app/Traits/PrimaryKeyRangeRouteBinding.php
<?php
namespace App\Traits;
trait PrimaryKeyRangeRouteBinding
{
public function resolveRouteBinding($value)
{
if (validator(['value' => $value], ['value' => 'integer|between:1,2147483647']])->fails()) {
return null;
}
return parent::resolveRouteBinding($value);
}
}
使い方
モデルに use
して使えます。
<?php
namespace App;
use App\Traits\PrimaryKeyRangeRouteBinding;
use Illuminate\Database\Eloquent\Model;
class Hoge extends Model
{
use PrimaryKeyRangeRouteBinding; // これ
...
}
これにより GET /hoges/str
や GET /hoges/2147483648
は、一致するレコードやルートがないときと同様に 404 Not Found
を返します。
おしまい