[CakePHP] Dica Rápida – Usando shell de múltiplas versões

Tirando a poeira disso aqui…

Desde que comecei com CakePHP me sentia frustrado por não conseguir utilizar o shell de diferentes versões sem precisar alterar meu ambiente de trabalho. Na época meu problema era ter projetos rodando a versão 1.2 e outros rodando 1.3.

Ontem me deparei novamente com o problema e cheguei até a sugerir um alias embutido no CakePHP, porém a ideia foi sabiamente rejeitada.

A solução para isso é mais simples do que parece (se você usa Linux e Bash, pelo menos): basta criar uma alias de comando para cada uma das versões do CakePHP.

Como fazer

  1. Abra o arquivo ~/.bashrc (se não existir, crie-o);
  2. Para cada versão do CakePHP você vai criar um alias seguindo este “template”:
alias cake13="~/pastas_ate_chegar_ao_cake/cakephp/cake/console/cake"

Meu arquivo ficou assim:

alias cake13="~/develop/php/cake13/cake/console/cake"
alias cake2="~/develop/php/cake2/lib/Cake/Console/cake"

Agora é só fechar e abrir novamente o terminal e usar os comandos “cake2”, “cake13” ou outro que você tenha criado. Works like a charm ;]

Dica Rápida – Evitando problemas com uso de jQuery e imagens

Algumas vezes precisamos recuperar, em tempo de execução, o tamanho de uma determinada imagem para aplica-la corretamente ao layout da página, porém essa verificação pode acontecer antes da hora, o que geraria erros inesperados.

Todo mundo que trabalha com a biblioteca jQuery conhece a chamada:

$(document).ready({
//seu código javascript
});

Ela diz ao browser para executar o bloco interno somente quando o DOM do seu documento tiver sido totalmente carregado, isso permite que ele faça o parser de seu documento utilizando os seletores sem esquecer de nenhum item. Porém quando carregamos estruturas externas ao DOM, como uma imagem, não temos garantia de que o código dentro do bloco anterior será executado quando a imagem já tiver sido carregada.
Dessa maneira, caso você precise de informações sobre a imagem, seu script falhará.

Para contornar isso, podemos utilizar uma outra chamada, que é disparada somente quando TODO o documento tiver sido carregado:

$(window).load({
//seu código javascript
});

As duas diferenças, além do comportamento são:

  1. Saí o ‘seletor’ document para a entrada do window;
  2. Saí o evento ready para a entrada do load;

A primeira alteração ocorre por conta da segunda, já que o evento load não pode ser associado a um document.

Com essa pequena alteração você garante que seu script rodará apenas quando todo o documento tiver sido carregado – o que é essencial em algumas situações, como a citada anteriormente, porém dispensável na maioria das vezes.

Fonte: http://api.jquery.com/load-event/

Dica Rápida – CakePHP 1.3, link com prefixo

Quando estávamos criando o Comitiva, decidimos utilizar o novo recurso do CakePHP que permite definir diferentes prefixos.

Em nosso caso, cada prefixo representa um tipo de usuário.

A ideia ia bem, até termos que criar um link explicitando uma rota.

Por padrão, a classe Router reconhece o prefixo em uso no momento e adiciona ele na url que você está construindo, desta forma se eu estiver acessando um endereço http://comitiva/participant/events  e quiser criar um link para a url http://comitiva/admin/users  eu terei um problema (não documentado): a segunda url ficaria http://comitiva/partipant/users , por causa da página que está ativa no momento.

A solução foi me apresentada no IRC, canal #cakephp-pt pelo padeiro Danielpk: adicione um índice com o nome do prefixo associado ao valor TRUE no array de endereço.  Fica algo assim:

$this->Html->link('Administre os usuários', array('controller' => 'users', 'action' => 'index', 'admin' => true));
// ou, caso queira forçar o prefixo participant
$this->Html->link('Veja os usuários', array('controller' => 'users', 'action' => 'index', 'participant' => true));

Dica Rápida – Otimizando código

Há um bom tempo atrás rolou uma discussão na lista do PHPMS sobre um comparativo de performance entre PHP x Python x Ruby x Perl.

Bom, a conclusão que tirei do comparativo foi de que a velocidade de execução é importante, mas mais do que isso, o programador é essencial. No exemplo da thread supracitada, o PHP perdia feio para as outras linguagens, mas olhando para o código escrito em PHP, dava para notar  vários erros de uso da linguagem e suas funções (ponto para o Begnini que viu o código antes de todos).

Então a dica de hoje é: estude bem a linguagem. Procure a saber o funcionamento das funções e construções da linguagem, isso é essencial para se tornar um bom programador.

Exemplos de código

//uso comum
for($i = 0; count($var) < 0; $i++)
  ...
 
//forma mais adequada
for($i = 0, $c = count($var); $c < 0; ++$i)
 ...
 
//outro caso, ao invés de forçar várias verificações
if( $a > 100 )
 ...
if( $a < 100 )
 ...
if( $a == 100 )
 
//use a estrutura adequada
if( $a > 100 )
 ...
else if( $a < 100 )
 ...
else //não precisa fazer o último teste
 ...
 
// esse último caso que me inspirou a fazer o post
 
// a pessoa só queria saber se o array $var tava vazio, e para isso contou todos os seus elementos
if ( count($var) > 0 )
 ...
 
// enquanto ela poderia ter usado uma verificação direta como
if ( !empty($var) )

Este último caso, que motivou o post foi visto no changelog da versão 1.2.6 do CakePHP. Neste caso o “erro” foi encontrado e corrigido pelo brasileiro Juan Basso neste commit.

O intuito do post não é meter o dedo na cara de ninguém, apenas alertar para situações onde culpamos uma determinada linguagem pelo desempenho de nossa aplicação quando o problema na verdade é o mal uso que estamos fazendo.

Dica Rápida – CakePHP – Personalizando as páginas de erros

A grosso modo, existem dois tipos de erros no CakePHP:

Erros de codificação e configuração:

Quando acessamos um endereço de nossa aplicação e está faltando alguma coisa, o CakePHP nos retorna uma mensagem avisando sobre o erro ocorrido e a causa dele (o que falta fazer).

Erros HTTP:
Quando tentamos acessar um endereço inexistente (erro 404) e quando há falha no servidor (erro 500).

O primeiro tipo deixa de ser exibido quando você configura o debug para o valor zero. A partir deste momento todos os erros relacionados ao primeiro tipo serão mostrados como um erro 404.
O segundo tipo é exibido não importando o valor do debug.

Como personalizar essas mensagens?

Caso queira usar o mesmo layou definido no arquivo app/views/layouts/default.ctp, você precisará apenas criar uma pasta chamada errors dentro da pasta views  (caso ela não exista) e depois criar um arquivo para cada erro, ficando mais ou menos assim:

app/views/errors/error404.ctp
app/views/errors/error500.ctp
app/views/errors/missing_action.ctp

Veja a lista completa de arquivos acessando o diretório cake/libs/views/errors/
Caso queira ir um pouco além, personalizando também o layout da mensagem, adicione um arquivo com o layout definido em app/views/layouts/. Vamos chamar esse arquivo de errors.ctp;
Em seguida, vamos adicionar o seguinte código em nosso AppController:

/**
 * Caso já esteja usando o beforeRender, apenas adicione a linha interna abaixo ao seu beforeRender
 */
function beforeRender () {
       $this->_setErrorLayout();
}
 
function _setErrorLayout() {
    if($this->name == 'CakeError') {
        $this->layout = 'error';
    }
}

Pronto, agora é só personalizar o arquivo errors.ctp da forma que achar melhor =]
Dica retirada do Teknoid

Dica rápida

Ontem estava aplicando algumas ideias encontrada no excelente Super Awesome Advanced CakePHP Tips e me deparei com um erro que ocorria na minha aplicação.

PROBLEMA:
Ao tentar usar a função file_exists do PHP dentro do arquivo config/bootstrap.php para incluir um outro arquivo do mesmo diretório sempre recebia como resposta o valor FALSE

SOLUÇÃO:
Descobri que ao usar o file_exists o PHP estava tomando como diretório corrente o webroot/ e não o diretório do bootstrap.php (arquivo atual), então tive de acrescentar o prefixo ‘../config/’ para encontrar o arquivo que procurava.
Após usar o file_exists, iria dar um include no arquivo, neste caso o comportamento é diferente: ele considera o diretório corrente como sendo o diretório do arquivo que está chamando a função ( no meu caso o config/), portanto não é preciso adicionar prefixo nenhum.

Ainda não consegui descobrir o motivo desses dois comportamentos no mesmo ambiente, porém imagino que o comportamento do file_exists está ligado ao arquivo .htaccess do CakePHP que seta para o Apache o diretório webroot/ como sendo a raiz do domínio.

Se souber a resposta deixe-a no comentário que eu atualizo o post.

Até a próxima.

———————————–
Atualizando conforme combinado – 27/01/2010
———————————–

O Társis deu uma boa dica para evitar esse tipo de problema: utilizar as constantes do CakePHP, no caso da dica do post, a constante utilizada seria CONFIGS, ela contém o caminho completo para o diretório /config.

A chamada da função ficaria assim:

if( file_exists(CONFIGS . 'arquivo.php') ) include( CONFIGS . 'arquivo.php');

Além da constante CONFIGS temos algumas outras, como a WWW_ROOT e IMAGES que seguem o mesmo princípio, mas para apontar o caminho completo do diretório /webroot e /webroot/img respectivamente.
Veja a lista completa de constantes em http://book.cakephp.org/view/122/Core-Definition-Constants