Laravel - Eloquent在比较前将查询参数转换为整数


Laravel - Eloquent converts query parameter to integer before comparison

我试图根据主键从表中返回单行。

    $product = Product::where('id', '=', $idOrSKU)
        ->orWhere('sku', '=', $idOrSKU)
        ->take(1)->get();

由于某种原因,$idorSKU在比较发生之前被转换为和(int)。例如:$isOrSKU = "9dfghfd",返回ID=9的行。为什么会这样?它应该什么也不返回!有人能解释一下吗?

下面是相关的表方案

| id                         | int(10) unsigned | NO   | PRI | NULL      
| name                       | varchar(255)     | NO   |     | NULL                
| sku                        | varchar(255)     | NO   |     | NULL 

这与数据库有关,而不是Laravel,对字符串进行类型转换。因为你在int(10)列上做查询,mySQL强制将你的搜索字符串更改为int,导致你的查询成为9

我可以确认如下:

$test1 = Test::find('1');
echo $test1->id; // gives 1
$test2 = Test::find('1example');
echo $test2->id; // gives 1

因此你的变量9dfghfd因为类型转换为int (9)。但是如果你的变量是"df9ghfd" -它不会被类型转换,它不会匹配。

编辑:这个问题影响其他事情,像路由模型绑定:

domain.com/product/1
domain.com/product/1thisalsoworks // takes you to the page of ID 1

我已经在Github上开了一个票来进一步讨论它-所以检查这里更多的信息/讨论。

但总的来说,这个问题不是Laravel的直接错误。

编辑:似乎问题影响GitHub 本身:

可以运行:https://github.com/laravel/framework/issues/5254

下面也是:https://github.com/laravel/framework/issues/5254typecast

事实证明,在这里,使用PostgreSQL,它的工作方式不同于你的数据库,当我这样做:

Route::any('test', function()
{
    $code = '181rerum';
    return Ad::where('id', $code)->orWhere('company_code', $code)->first();
});

我得到这个错误:

SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input 
syntax for integer: "181rerum" (SQL: select * from "ads" where 
"id" = 181rerum or "company_code" = 181rerum limit 1)

所以Laravel,知道它是一个整数列,直接传递给数据库,没有引号,这会产生一个数据库异常,因为PostgreSQL甚至不会尝试将该字符串转换为整数。

所以,即使你从Laravel核心开发人员那里得到了一些帮助,我认为你应该总是做这样的事情来帮助你做那些混合搜索:

Route::any('test/{id}', function($id)
{
    /// You can always filter by a string here
    $q = Ad::where('company_code', $id);
    /// You just try to filter by id if the search string is entirely numeric
    if (is_numeric($id))
    {
        $q->orWhere('id', $id);
    }
    return $q->first();
});