LoginSignup
6
2

More than 3 years have passed since last update.

Laravel のモデル結合ルートパラメータに文字列を渡すと SQL エラーになるのを直す

Posted at

背景

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/strGET /hoges/2147483648 は、一致するレコードやルートがないときと同様に 404 Not Found を返します。

おしまい

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2