PHPMS Conf’14

banner de divulgaçãoÉ isso mesmo galerinha, seguindo bravamente a frente da organização, meu brother Marcelo Siqueira assumiu a responsa e juntamente com a SUCESU-MS está organizando a edição 2014 do nosso evento favorito: PHPMS Conf’14.

A grande novidade deste ano é que não vamos ficar preso a capital do estado, desta vez o evento ocorre em Dourados. Mas se você está em Campo Grande, tem ônibus grátis para os primeiros inscritos, que coisa linda não? O evento ocorre então dias 11 e 12 de Setembro de 2014, e a grade completa você confere na página dele.

Terei a honra de palestrar no sábado sobre a linguagem e tópicos relacionados (posto link para ela depois). Varias feras irão palestrar no evento como o Bruno PorKaria, Ricardo Coelho, Saulo Arruda, Alê Borba e o próprio Marcelo Siqueira. Imperdível.

Se quiser bater um papo, eu e quase toda a equipe da Radig estaremos lá nos dois dias.

Ainda da tempo de se inscrever, mas corra!

Até breve!

CakePHP: Plugin Locale

Vamos falar um pouco sobre outro plugin para CakePHP que surgiu no coração da Radig: o Locale.

Meu amigo José Agripino já apresentou o plugin no próprio blog da Radig, mas como reescrevi quase que totalmente o plugin nos últimos dias, acredito ser a hora de falar dele novamente.

Nada melhor para ver a utilidade de algo como imaginar uma situação de uso real, então vamos lá…

Cenário 1: você desenvolve um sistema para brasileiros, e quer permitir a entrada de informações em formato local, isto é, datas com dia/mês/ano e números com vírgula separando decimais. O problema é que estes dados são inválidos em um banco de dados convencional (como MySQL e PostgreSQL). Ao tentar salvar uma data formatada com dia/mês/ano você receberá um erro como resposta. Como resolver isso? Use o behavior Locale no seu modelo.

Basta adicionar o behavior Locale no modelo que ele fará a conversão de datas e números para o formato americano.

public $actsAs = array('Locale.Locale');

É possível converter automaticamente datas, datas acompanhadas de horas e decimais/floats.

Cenário 2: você já tem os dados do seu usuário armazenados no banco (formato padrão/americano) e quer apresenta-los em um formato local na sua View, o que fazer? Use o Helper Locale em sua view. Primeiro ative o helper no seu controller:

public $helpers = array('Locale.Locale');

Agora basta usa-lo na view:

echo $this->Locale->date($this->data['User']['birthday']);

É possível formatar data, data com hora, data literal (quarta-feira 18 de abril de 2012, por exemplo), decimais como 53,42 e valores monetários ( R$ 53,42 ).

Além do Behavior e do Helper, você pode carregar as libs Localize e Unlocalize em qualquer parte de seu sistema para converter entre os dois diferentes formatos. As libs são estáticas e suportam aninhamento de método, assim você pode fazer:

echo Localize::setLocale('pt_BR')->decimal(12.45); // 12,45

A unica configuração necessária é a definição do locale de sua aplicação, que pode ser feito no próprio bootstrap.php do Cake:

setlocale(LC_ALL, 'pt_BR');

Assim como outros plugins da Radig, você pode consultar os testes incluídos para ver melhor o funcionamento deste.

Se for utilizar, nos avise, será uma grande satisfação ver que o plugin é util para outros.

Há uma versão compatível com o CakePHP 1.3 e outra com o CakePHP 2.x, basta usar o branch correspondente.

[CakePHP] Acl: Problema com Acos “duplicados”

Quando falamos em Acl e CakePHP muitos tem a lembrança de horas lutando contra um monte de código para tentar fazer funcionar a autenticação e permissionamento. Bastam algumas dezenas de projetos e você fica craque em configura-lo.

Porém vez ou outra aparece uma dúvida que te faz perder várias horas debugando e as vezes termina isso sem uma solução razoável.

Trabalhamos muito com Plugins na Radig e um problema que enfrentávamos de vez em quando era o de ter um plugin com o mesmo nome de uma ação de controller. Nestes, quando você verifica a permissão para a ação usando uma sintaxe de caminho parcial, isto é, algo como:

$this->Acl->check('acao', 'Fulano');
$this->Acl->check('Controller/acao', 'Fulano');
$this->Acl->check('Plugin/Controller/acao', 'Fulano');

Um erro é retornado, dizendo que o Aco não pode ser verificado (lembrando que para o exemplo, Plugin teria o mesmo nome de acao).

Isso foi até assunto de um bug reportado para o CakePHP, afirmando que a falha estava no fato das comparações no banco de dados serem, na maioria das vezes, case-insensitive. De fato, como respondeu o Mark Story, uma forma de resolver este “problema” é utilizar no banco de dados um COLLATION que seja de fato case-sensitive. O problema nisso é que a maioria dos conjuntos de caracteres, ao menos no MySQL, são case-insensitive, então você teria de mudar todos os seus banco de dados para corrigir isso.

Porém o usuário nlcO postou uma dica interessante: basta usar o caminho completo do Aco que não haverá conflito, mesmo quando controllers, plugins ou actions tiverem os mesmos nomes. Mas como usar o caminho completo? Basta ver qual é seu Aco raiz (que possuí o parent_id = NULL) e ir incluindo após ele todos os subsequêntes – plugins, controllers e actions, até formar o caminho completo.

No meu exemplo ficaria:

$this->Acl->check('aplicacao/Plugin/Controller/acao', 'Fulano');

HTML5: Problemas com Input type=”number”

Opa, esse é mais um aviso.

Recentemente estava trabalhando em um sistema com CakePHP 2.1 e ao tentar editar um registro onde um dos campos era do tipo float, o valor que estava no banco não era apresentado no formulário, embora a tag input estivesse com o atributo value preenchido corretamente. Isso aconteceu comigo no Chrome 17, no Firefox 10 não houve problema porque ele utiliza input text normal.

Um detalhe importante é que eu utilizo o Helper Locale para formatar os números decimais para meus usuários, assim o que vem do banco como “12.58” vira “12,58” formato que usamos no Brasil. Talvez se usasse ponto como separador de decimais não teria problema – o que não é possível pra mim.

Ao pesquisar um pouco descobri um bug no Chromium relacionado a isso reportado no link http://code.google.com/p/chromium/issues/detail?id=44116 . Não consegui entender o motivo mas foi marcado como Wontfix.

A saída foi sobrescrever o FormHelper para utilizar input do tipo text quando o número vindo é um ponto flutuante/decimal. Se você não trabalha com CakePHP, mas trabalha com números decimais separados por vírgula, a dica continua valendo: utilize input com o tipo text ao invés de number.

Aqui tem um commit onde implementamos a “correção” em um FormHelper que estende o do CakePHP.

[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 ;]

[Comitiva] Como utilizar controle de permissão no sistema – quase tudo mudou

No último post falei um pouco sobre o sistema de permissões que implantamos no Comitiva.

Acontece que após a adição de uma nova funcionalidade (submissão de trabalhos) aquele sistema de permissão começou a ficar ineficiente, e apesar de eu ter dito nos comentários que o ideal era implementar o Acl para este controle no sistema, acabei por implementar a solução sugerida pelo grande Humberto – que, tomando como ponto inicial o que tínhamos, era o jeito mais simples de solucionar os problemas.

Então o que mudou?

  • Os usuários não possuem mais um “tipo”, agora eles pertencem a “grupos” (um ou mais);
  • A verificação de permissão é feita na classe AppController, de forma genérica, o que elimina a necessidade de reescrever a função de autorização a cada controlador;
  • Os grupos que um usuário pertence ficam definidos em um campo “groups”, do tipo varchar e são guardados codificados no formato json
  • Defini um método protegido no AppController para verificar se o usuário logado pertence a um grupo qualquer, facilitando essa operação quando necessário. (o método chama-se AppController::__checkGroup($string) )

O que não mudou?

  • As ações continuam tendo como prefixo o grupo que pode acessa-la, sendo assim, a ação ProposalsController::participant_add() está disponível a todos os usuários que pertençam ao grupo “participant”
  • Todos os usuários registrados pertencem inicialmente ao grupo ‘participant’, porém podem vir a pertencer a outros grupos posteriormente (em adição ao grupo ‘participant’)
  • Continua sendo muito fácil saber se o  usuário logado pode ou não efetuar uma ação, basta usar o método supracitado __checkGroup.

Exemplo de como verificar se o usuário é administrador

if($this->__checkGroup('admin'))
    echo 'O usuário logado é administrador';
else
    echo 'O usuário logado não é administrador';

[Comitiva] Como utilizar controle de permissão no sistema

Como escrevi anteriormente, o PHPMS mantém um sistema para gerenciar eventos – desde a divulgação de informações, cadastro de eventos, inscrições, pagamentos, envio de mensagens para inscritos e check-in.

Mas o objetivo deste post não é dizer o que já foi dito, quero iniciar uma série de posts onde vou explicar o funcionamento de alguns recursos dentro do Comitiva, convidando todos os desenvolvedores a opinar sobre implementação e contribuir com o projeto.

O assunto de hoje é controle de acesso, então vamos ao que interessa.

Como funciona o controle de acesso no Comitiva?

Utilizamos o componente Auth do CakePHP para cuidar da autenticação (efetuar login, verificar se o usuário está logado e efetuar logout).
Mas precisávamos ir um pouco além da configuração básica, definindo diferentes opções para diferentes tipos de usuários. Para isso, consideramos duas opções iniciais: usar também o Acl Behavior ou ficar apenas com o AuthComponent e criar diferentes actions para diferentes tipos de usuários.

Como possuímos apenas dois tipos de usuários (admin e participant) decidimos pela que seria mais simples inicialmente – mesmo sabendo que a manutenção no futuro poderia ser mais complicada – que foi criar diferentes actions para os tipos de usuários.

Para criar essa funcionalidade, definimos inicialmente um prefixo para cada tipo de usuário (prefixos ‘admin‘ e ‘participant‘). Em seguida configuramos o AuthComponent desta maneira (código extraído do AppController):

//Configure AuthComponent
$this->Auth->authorize = 'controller';
 
if( !isset($this->params['prefix']) || !( in_array($this->params['prefix'], Configure::read('Routing.prefixes')) ) )
{
	// all non-prefixed actions are allowed
	$this->Auth->allow('*');
}

Ou seja, toda ação que não tiver prefixo ou o prefixo não estiver definido nas configurações de rota serão públicas (assim é possível, por exemplo, deixar uma página com instruções acessível à qualquer usuário).

Mas como fica essa verificação de tipos no controlador? Como definimos o método de autorização do Auth como ‘controller’, precisamos definir em todos os controladores o método isAuthorized que deve retornar true quando o acesso é aprovado e false caso contrário.
Seguindo a ideia de que cada tipo de usuário possui um prefixo próprio nas ações, nosso método isAuthorized fica desta forma:

if($this->userLogged == TRUE && $this->params['prefix'] == User::get('type'))
{
	return true;
}
 
return false;

Onde o atributo $this->userLogged pertence a classe AppController e sua função é reduzir chamada ao método $Auth->login() e na segunda parte da condição temos uma comparação entre o prefixo da url acessada e o tipo do usuário – se ambos forem iguais, então o acesso está liberado.

Por fim, devemos criar nossas ações para cada tipo de usuário, onde o prefixo será usado para validar o acesso à aquela ação, veja o exemplo da ação “listar pagamentos”:

// ação exclusiva para admin - tem acesso aos pagamentos de todos os outros usuários
public function admin_index($event_id = null)
{
	$this->Subscription->recursive = 0;
 
	if(is_numeric($event_id))
	{
		$this->paginate = array(
			'conditions' => array(
				'event_id' => $event_id
			)
		);
	}
 
	$this->set(compact('event_id'));
	$this->set('subscriptions', $this->paginate());
}
 
// ação exclusiva para participant - tem acesso somente aos próprios pagamentos
public function participant_index()
{
	$this->Subscription->recursive = 0;
	$this->set('subscriptions', $this->paginate(array('user_id' => User::get('id'))));
}

Como podem ver, isso permite a criação de diferentes regras de negócio para os diferentes tipos de usuários e embora aumente a quantidade de código “redundante” por repetir alguns procedimentos para todos os tipos de usuários, a leitura e entendimento do código é facilitada – basta ver o prefixo do método (ação) para saber quem terá acesso a ele.

Obrigado pelos peixes SVN

Há alguns anos descobri o fantástico mundo do controle de versão, naquele momento me perguntei “como vivi sem isso até hoje?”. Dali em diante podia alterar arquivos sem medo, qualquer erro era só voltar uma versão e tudo certo. Trabalhar em equipe finalmente se tornava algo fácil, graças ao Subversion – SVN.

Porém os anos passaram e algumas coisas começaram a fazer falta: como faço quando estou desenvolvendo algo grande, fico sem commitar até ter algo estável/usável? crio um branch para isso? mas e depois para unir os branches, e os conflitos? além disso, se só eu estou trabalhando em cima disso, porque commitar para todo mundo algo não pronto?

Foi aí que descobri o GIT, um sistema de controle de versão distribuído, open source e gratuito. Ok, ele é gratuito e open source, mas isso não é motivo suficiente. Como disse, ele é um sistema de controle de versão distribuído, isso quer dizer que cada um que tem uma cópia do repositório tem de fato uma cópia dele, e pode servir outras pessoas, ver histórico, tudo localmente.

Então de quebra, ele resolve o problema de ter de criar um branch para desenvolver uma funcionalidade que só eu vou mexer, posso controlar cada alteração minha localmente, e quando quiser – se quiser – posso sincronizar meu repositório local com um outro central (que eu considero central, já que essa figura não existe no GIT). E mais, ele é MUITO RÁPIDO. Acho que para ajudar na argumentação de que é rápido basta dizer que ele foi feito por alguns desenvolvedores do Kernel Linux, e gerencia todo o código trabalhado por eles – e não é pouca coisa.

Ainda estou caminhando com o GIT, tenho aproveitado minha ânsia de aprende-lo junto com a de contribuir com softwares open source para criar e disponibilizar projetos no GitHub.

A grande maioria dos projetos é voltado ao CakePHP, mas há outras coisas também. Alguns projetos que podem interessar são:

  • Comitiva – Sistema construído em CakePHP 1.3 para gerenciamento de eventos;
  • Plugin Mailer – Um plugin que ajuda na utilização da biblioteca PHP SwiftMailer dentro do CakePHP;
  • Behavior Locale – Um behavior para transformar dados vindo do usuário de seu padrão local para um padrão internacional (de banco de dados)
  • Libs – uma coleção de pequenos scripts PHP que fui fazendo ao longo da vida. Há coisas boas, coisas úteis, coisas não tão úteis, mas tudo pode ser usado ao menos como ponto inicial para uma implementação mais elaborada.

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));

3º Workshop do PHPMS

Tenho dado uma pausa nos posts aqui do blog por 3 motivos: estou na reta final da faculdade, a Radig esta indo muito bem obrigado e o PHPMS esta organizando seu 3º Workshop. E este último é motivo para este post.

Para quem me acompanha há algum tempo, sabe que participo do grupo e sempre ajudo de alguma forma no evento, dessa vez não seria diferente.
O evento terá 4 excelentes palestras, sendo duas de nossa celebridade convidada, Guilherme Blanco.

Tenho ajudado bastante no desenvolvimento de uma ferramenta para a gestão de eventos do grupo, que terá seu código liberado tão breve quanto fique pronto (ou seja, sem data, mas não deve demorar muito, hehehe). O nome dele é Comitiva.

Confira abaixo o release oficial:

O 3° Workshop do PHPMS será realizado no dia 27 de março no SENAC/MS, das 08:30 até 17:50. O evento vai contar com a presença de Guilherme Blanco que hoje trabalha na empresa sul-africana MIH/SWAT, desenvolvedor do core do projeto Doctrine, bem como nas frameworks Zend e Symfony. Ele vai apresentar duas palestras, “Overview do Doctrine 2.0″ e “Usando o Doctrine 2.0 com Zend Framework 1.10″.

Vamos ter também duas palestras sobre WordPress, a ferramenta de blog mais usada no mundo, Flávio Ricardo irá apresentar o tema “Gerenciando blogs e websites de forma flexível com WordPress MU” e em seguida Gabriel Novaes aborda o tema “WordPress SEO: Práticas e plugins para robos de busca”.

Sem falar na tradicional mesa-redonda para debater assuntos de interesse da comunidade de desenvolvedores PHP do estado, que vem nesse workshop com o tema “Perfil do programador PHP no estado de MS”.

Informações para inscrição no evento, grade completa, você encontra no hotsite do evento http://www.phpms.org/workshop/