Laravel - Eloquent converte parâmetro de consulta em inteiro antes da comparação
Pergunta
Estou tentando retornar uma única linha de uma tabela com base na chave primária.
$product = Product::where('id', '=', $idOrSKU)
->orWhere('sku', '=', $idOrSKU)
->take(1)->get();
Por algum motivo $idorSKU
está sendo convertido para e (int)
antes que a comparação aconteça.Por exemplo, quando $isOrSKU = "9dfghfd"
, a linha com ID=9 será retornada.Por que é isso?Não deve retornar nada!Alguém pode explicar isso?
Aqui está o esquema de tabela relevante
| id | int(10) unsigned | NO | PRI | NULL
| name | varchar(255) | NO | | NULL
| sku | varchar(255) | NO | | NULL
Solução
Isso está relacionado ao banco de dados, não ao Laravel, ao digitar sua string.Porque você está fazendo uma consulta em um int(10)
coluna, o MySQL está alterando forçosamente sua string de pesquisa para um int
, fazendo com que sua consulta se torne 9
.
Posso confirmar o seguinte:
$test1 = Test::find('1');
echo $test1->id; // gives 1
$test2 = Test::find('1example');
echo $test2->id; // gives 1
Portanto sua variável de 9dfghfd
porque typecast para int (9)
.Mas se sua variável fosse "df9ghfd" - não seria typecast e não corresponderia.
Editar:O problema afeta outras coisas, como a vinculação do modelo de rota:
domain.com/product/1
domain.com/product/1thisalsoworks // takes you to the page of ID 1
Abri um ticket no Github para discutir mais sobre isso - então verifique aqui para mais informações/discussões.
Mas no geral o problema não é culpa direta do Laravel.
Editar:parece que o problema afeta o GitHub em si:
Isso funciona: https://github.com/laravel/framework/issues/5254
E o mesmo acontece com isso: https://github.com/laravel/framework/issues/5254typecast
Outras dicas
Acontece que aqui, usando PostgreSQL, funciona de forma diferente do seu banco de dados, quando eu faço:
Route::any('test', function()
{
$code = '181rerum';
return Ad::where('id', $code)->orWhere('company_code', $code)->first();
});
Eu recebo este erro:
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)
Então o Laravel, sabendo que é uma coluna inteira, está passando ela diretamente para o banco de dados sem aspas, o que gera uma exceção no banco de dados, já que o PostgreSQL nem tentará converter aquela string para inteiro.
Então, mesmo que você receba ajuda dos principais desenvolvedores do Laravel, acho que você deve sempre fazer algo assim para ajudá-lo a fazer essas pesquisas mistas:
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();
});