Para quem já está mexendo com CakePHP a algum tempo, algumas limitações de funcionalidades podem tirar um pouco o sono de quem está muito mal acostumado com a produtividade da framework. Em geral, toda framework tem seus pontos fracos.
A algum tempo, tive um problema curioso: a chave primária de uma tabela teria valores alfanuméricos. Ou seja: valores como “205-A”, “JB02″ e outros bizarros seriam possíveis. Regra de negócio definida, modificação do modelo para o nome de chave fora da convenção e tudo corria bem até que populei um select.
Qual não foi minha surpresa em ver que o CakePHP, além de não marcar o valor correto, em certos casos ainda selecionava mais de um valor no select. #fail total.
Pesquisa na internet, perguntas na lista de discussão oficial do CakePHP e as respostas eram:
- Coisas que não tinha nada haver com o problema
- Sugestões pra mudar a estratégia para resolver o problema
- Gente falando que o CakePHP só trampa com valores numérico (o que de fato acontece
)
O problema
Então, mexendo no código pra cima e pra baixo (sem conotações sexuais por favor) consegui achar o problema.
No arquivo cake/libs/views/helpers/form.php (cakephp 1.2.5), na linha 1710:
if ((!$selectedIsEmpty && $selected == $name) || ($selectedIsArray && in_array($name, $selected))) {
Depois de fuçar e testar um pouco, vi que o problema principal na verdade é um problema com o próprio operador == do PHP: ele trata as operações entre strings e numéricos (http://php.net/manual/en/language.operators.comparison.php) de uma forma que gera os seguintes resultados:
- um valor como 206-1 por exemplo, o helper casava tanto o valor 206-1 (o correto) quanto 206 (string == integer).
- um valor como JB01 por exemplo, o helper casava tanto o valor JB01 (o correto) quanto 0 (string == integer).
Devido à característica do PHP de resolver qual o tipo da variável em tempo real, ele tenta fazer o casting da variável sempre e acaba gerando resultados não esperados pra gente.
Solução
A solução então foi forçar (type casting) as variáveis para serem tratadas como strings. Assim, evitamos que o PHP transforme nossas variáveis em tipos distintos (no nosso caso string e integer) e consequentemente faça a comparação de valores do jeito que precisamos.
A linha 1710 (no cakephp 1.2.5 ou 1748 no cakephp 1.3-dev) ficou assim:
if ((!$selectedIsEmpty && (string)$selected == (string)$name) || ($selectedIsArray && in_array($name, $selected))) {
Note o type casting sendo feito nas variáveis $selected e $name.
Se alguem conseguir uma solução mais bacana ou encontrou outro bug bizarro do CakePHP, compartilhe!
Simbora!
Update: Eu tinha reportado esse erro a algum tempo no track de bugs do CakePHP e hoje vi que já corrigiram isso. Então, quando sair a versão stable do cake 1.3, não precisa mais se preocupar com isso.
Óia que bacana: eu tinha reportado o bug/correção dessa falha anteriormente para o pessoal do Cake (http://code.cakephp.org/tickets/view/167) mas com outra abordagem pro erro. Alterei a estratégia, enviei de novo e não é ele já tinham corrigido? HAHEHEHAUEe Iradasso.
Então, quando sair a versão stable do cake 1.3, não precisa mais se preocupar com isso.