Dev (Back & Front)ARTIGO

Problema com IDs alfanuméricos no form->input (select) do CakePHP

Para quem já está mexendo com CakePHP há 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.

Há 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 a ver 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, 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)<br />|| ($selectedIsArray && in_array($name, $selected))) {

Note o type casting sendo feito nas variáveis $selected e $name.

Se alguém conseguir uma solução mais bacana ou encontrou outro bug bizarro do CakePHP, compartilhe! 

Simbora!

Observação: Eu tinha reportado esse erro há algum tempo no track de bugs do CakePHP. Depois de um tempo, vi que isso havia sido corrigido. Então, quando sair a versão stable do cake 1.3, não precisa mais se preocupar com isso. 

IT Manager de um time de pessoas inoxidáveis na Wine.com.br e de inovação no WineLabs. Co-fundou a Giran E-commerce Solutions e liderou o desenvolvimento da plataforma de e-commerce Adena. Depois de 20+ anos construindo aplicações web para empresas de todo porte, liderando times com grande diversidade e tamanhos e inventando moda utilizando Scrum/XP/Lean, agora tenta ajudar as pessoas a serem as melhores que podem a cada dia utilizando uma penca de mindsets ágeis, inspirações, aspirações e (paix|tes)ão pelo que faz. Specialties: Internet, E-commerce platforms and Web Application Building, Agile Methodologies, Technical Team Lead/Coaching, Innovation, Creativity Current Interests: Visual Thinking, Recommendation Systems, Machine Learning, Lean, Isaac Asimov and Pentatonic Scales.

Ver perfil