Encontro de desenvolvedores CAKE Sao Paulo

Bom dia pessoal,

Estive presente no Encontro de desenvolvedores CAKE em Sao Paulo, e posso dizer que foi um bom encontro, palestras de nivel muito bom, aonde foi abordado desde a criação de um helper ate a criação, plugins, ambiente de testes, brincadeiras e criação com o bake.

Algumas palestras em destaques para TDD – Test-Driven Development e Testes Automatizados com CakePHP, aonde foram abordados assuntos que vem ja a algum tempo sendo levado em conta que e desde a engenharia de software ate a cobertura de testes dos codigos. Abordados tipos de testes: Unitarios, Aceitação, entre outros. Palestras de Rodrigo Moyle e José Pedrini.

Apos isso uma outra palestra de nivel incrivel sobre criação e consumo de webservices com CAKEPHP que foi criado e desenvolvido um webservive utilizando REST. Parabéns ao Carlos Pires da 2KM que veio de Minas para nos prestegiar com sua palestra e sua participação no evento.

Um grade destaque também a palestra do Rafael Santos, que nos mostrou como construir uma plataforma RAD para Flex com CakePHP e Fake, apresentando inovações como o FAKE e integrações bem legais entre Flex e CAKEPHP, aonde se utiliza todos os recursos, desde validations, ate os models e controllers, nao deixando a desejar nem um pouco.

Parabéns aos Organizadores, ao Renan Gonçalves que se esforçou e fez acontecer e valer a pena o evento. Troca de conhecimentose fortalecimento da comunidade CAKEPHP e PHP no Brasil e em São Paulo.

Minha Palestra:

OOP no PHP: Overloading, utilizando os métodos mágicos do PHP

E aeeeeew blz? Bom gente voltando do período de preguiça bagarai, vício em jogos online e outras vagabundagens ociosidade vamos dar continuidade a série de artigos sobre OOP no PHP. O assunto de hoje é bem interessante, no post de hoje vamos ver como usar um dos métodos mágicos do php.

Neste artigo vou falar do método mágico __call(),  que funciona da seguinte maneira:

Quando uma classe tem o método __call() o php roda esse método sempre que qualquer método da classe for chamado, mesmo se o método que foi chamado não existir um método inexistente ou inacessível for chamado (obrigado Edgar pelo puxão de orelha), isso abre espaço para algumas coisas interessantes.

Vamos a um exemplo do funcionamento de __call():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class ExemploCall {  
  function __call($m, $a)
  {
    print "Método chamado: $m\n";
    print "Parametros: \n";
    var_dump($a);
    return $this->x;
  }
}
$call = new ExemploCall();
$call->test(1,2,'teste');
 
//Mostra na tela
/*
Método chamado: test 
Parametros: 
array(3) { 
  [0]=>  int(1) 
  [1]=>  int(2) 
  [2]=>  string(5) "teste" 
} 
*/
?>

O exemplo acima simplesmente exibe na tela o método chamado e os parametros enviados, mas vendo isso a pergunta que surge na cabeça é, pra que ou onde eu vou usar o método __call()?

A resposta pra essa pergunta vai da sua criatividade mas eu vou postar aqui uma forma de uso que o cakephp usava há algum tempo atrás.

Funcionava da seguinte forma, havia um método padrão chamado find que era chamado e fazia consultas ao banco de acordo com os parametros passados, porém, (aqui que vem a mágica) ele também podia ser chamado como findByNomeDoCampo o que em alguns momentos facilitava bastante a vida do programador, vamos fazer algo parecido com isso.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?php
 
/**
  Só vou postar o código relevante aos métodos mágicos, mas supõe-se que
  deste ponto em diante você já tem incluido no arquivo toda a rotina de 
  conexão com o banco de dados, etc, etc, etc...  
**/
 
class Model {
 
  public function __construct() 
  { //O conteúdo deste método vai variar de acordo com sua classe
  }
 
  public function __call($method, $params)
  {
    // Verifica se o método chamado existe nessa classe
    if ( method_exists($this,$method) )
    {
      //Caso exista chama o método
      return call_user_method($method, $this, $params);
    } 
    else 
    {
      //Caso não exista, chama um método especial que fará a nossa mágica
      $this->parseMethods($method,$params);
    }
  }
 
  private function parseMethods($method,$params)
  {
    //Verifica se o método segue o padrão adotado
    if ( eregi('findBy',$method) === false ) 
    {      
      //Caso não siga dispara um erro dizendo que o método é inválido/não encontrado
      trigger_error('Método inválido ou inexistente',E_USER_ERROR); 
      die;
    }
    else
    {
      //Caso seja um método padronizado (findByAlgo) recupera o nome do campo e converte tudo para minúsculo
      $fieldName = strtolower(str_ireplace('findBy','',$method));      
 
      //Formata os parametros para serem passados ao método find padrão
      $options = $params['1'];
      $options['conditions'] = array($fieldName=>$params['0']);
 
      //Chama o método find original
      $this->find($options);            
    }
  }
 
 
  public function find($options) 
  {    
    var_dump($options);
    //Aqui você faria a consulta usando as informações recebidas
  }
 
}
 
//Instancia a classe
$model = new Model();
 
//Define parametros a serem passados
$options = array (
   'fields' => array ('*')
  ,'order'  => array ('nome ASC')
);
 
//Chama o método mágico
// Onde o primeiro parametro é o valor que o campo passado no nome do método deve ter.
$model->findByBlog('Technócio',$options);
 
/**
O que chega no método options é:
array(3) { 
    ["fields"] =>  array(1) { 
        [0]=>  string(1) "*" 
    } 
    ["order"] =>  array(1) { 
        [0]=>  string(8) "nome ASC" 
    } 
    ["conditions"] =>  array(1) { 
        ["blog"]=>  string(9) "Technócio" 
    } 
} 
**/
?>

O código ta bem comentado e bem simples também, embora não tenha me aprofundado muito no assunto acho que deu pra ter uma noção dessa possibilidade e do que pode ser feito com isso.

Como sempre, para dúvidas, sugestões e puxões de orelha, utilizem os comentários. Até a próxima (que dessa vez não vai ser tão demorada assim).

Trabalhando com Datas em PHP & MySQL

Bom dia,

Datas, hora, minutos, meses, anos, informações que nos deslocam às nossas tarefas diárias, ou que nos deixam desesperados porque o tempo é pouco para tal coisa ou compromisso, pois é, data esta dentro do tempo, que nem sempre esta à nosso favor. Deixa-mos a filosofia de lado, blá nunca fui bom filosófo, quer dizer, jamais fui um, então comecemos logo à entender um pouco datas.

Formatos de datas no Mundão!

O php, a linguagem de inicio que vou usar nesse post, tem a função strftime(), ela faz a formatação de uma hora/data com as configurações locais dos paises, é importante frisar que em servidores windows, é preciso usar a função setlocale() para definir a linguagem da localidade que você vai usar, e ler no MSDN as suportadas, porque claro, o Windows complica mais do que ajuda!

Exemplo de datas com fuso horario de outros paises

Alemanha

<?php
//Seta o local, de_DE = alemanhã (German)
setlocale(LC_TIME, "deu");
echo strftime(" estamos na  German (Alemão) %A.\n");
?>

Portugues Brasil

<?php
//Seta o local, "portuguese-brazil" ou "ptb" = Português Brasil
setlocale(LC_TIME, "portuguese-brazil");
echo strftime(" estamos no Brasil  (Português) %A.\n");
?>

Formas de String:

%a – dia da semana abreviado de acordo com a localidade
%A – nome da semana completo de acordo com a localidade

Mais sobre as formas de string em PHP.Net ( Manual).

Bom, agora que a parte de deixar configurado à data de acordo com sua localidade ou com a necessidade mesmo do desenvolvedor, por exemplo se você estiver trabalhando em um sistema que poderá ser usado em outros paìses (nossa, elevei o pessoal a programadores mundiais!), isso pode poupar-lhe de muita dor de cabeça, gritos, socos, murros, monitores, gabinetes, e HD’s!

Datas em formato Timestamp

An extension of the DATE datatype that can store date and time data (including fractional seconds). The timestamp type takes 11 bytes of storage.

Inglês péssimo né? é? então eu vou lhe dar uma linguada básicanisso e verbalizar essa budêga:

Uma extensão do datatype (tipo de data) da DATA que pode armazenar dados da data e da hora ( com segundos fracionários incluídos).  O tipo do timestamp faz exame de 11 bytes de  armazenamento..

Nossa, meu inglês é uma bosta também, mas o português tambem é fraco, mas é isso. é uma extenção de data para armazenamento de data hora e informações facionarias como segundos, blá e blá, se você quiser uma data exata mesmo, no real sentido, isso é sua solução!

Timestamp em MySQL e outros tipos

O Nosso Manual MySQL nos diz, que DATETIMES e TIMESTAMP são relacionadas, calma, elas não tem relações sexuais, vão ter datazinhas gritando, chorando e chamando você de titio não! nossa, mente poluída a minha não?! Elas são apenas parecidas, ou tem a mesma função, até hoje nunca descobri, ou tenho certeza disso! hahahaha!

Os formatos de DATE do MySQL se reservam apenas à Ano, dia e Mês: YYYY-DD-MM, não temos a opção de segundos fracionários, então neca de comparação exata usando segundos com esse tipo de campo.

Agora em Timestamp como diz a descrição da extenção, temos opção fracionária, que ficará no formato de: YYYY-DD-MM HH:MM:SS, po, mas ta feio pacas isso não? Os Brasileiros não leem datas nesse formato americano, então o MySQL permite usar o padrão de data Brasileiro ? que é DD-MM-YYYY, cara, sei não, se tiver desconheço, e não recomendo! já vou explicar os motivos.

Imagine essa  situação:

Você tem 2 datas, que precisam ser comparadas se uma é maior que outra , as datas são essas: 23/06/1989 e 23/08/1800, e em comparações de datas você não pode usar barras, traços, essas viadagens todas pra ficar bonitinha! Seria assim seu pensamento:

23061989 > 23081800  vai retornar false, hahah se lasco cara!

Bom, olhando você ja sabe que a data mais antiga é maior que a mais nova, no nosso formato Brasileiro, mas isso esta errado, sendo que a primeira data é a maior, sendo à mais perto de nosso ano atual, não é? mas os numeros não mentem, porque nosso formato é incorreto para comparações de data, mas no formato americano é mais fácil de se comparar:

18002308 > 19892308 vai retornar true.

Mas você ficou tristinho, pois a data no formato americano fica estranho pros brasileiros, calma, tudo tem uma solução, você pode formatar a data em timestamp com uma função, ela fica em um formato agradavel de ler exemplo: 23 de outubro de 2004 as 13:01:21 . mas caso os dados venham do banco de dados, é necessário usar UNIX_TIMESTAMP antes no seu select, por exemplo:

# Seleciona o campo data, usando a função UNIX_TIMESTAMP, dando renome a ela, de NovaData, campo esse da tabela TabelaLinda
SELECT UNIX_TIMESTAMP(DATA) AS NovaData FROM TabelaLinda;

Se você chamar a função UNIX_TIMESTAMP sem nenhum argumento, exemplo:

# Obtem a data de hoje usando os segundos, desde de 1969!
SELECT UNIX_TIMESTAMP();

Isso iria retorna um tipo timestamp do Unix, são segundos desde ‘1969-01-01 00:00:00′ GMT, mais ou menos assim: 882226357

Bom, ai você tem um monte de numeros de segundos, o que você vai fazer com eles? colocar no prato e comer? Jogar na lata do lixo porque não serve pra nada? Pegar uma metralhadora e atirar no monitor? Ou usa a função para formatar?, ahhh garoto esperto, usa a função!

<?php
function montaData($data) {
 $v_mes = array(1=>"Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro");
 $v_data = explode(" ",date("Y m d H i s", $data));
 return "{$v_data[2]} de {$v_mes[(int)$v_data[1]]} de {$v_data[0]} as {$v_data[3]}:{$v_data[4]}:{$v_data[5]}";
}
?>

Pronto! Basta aplicar:

<?php
echo montaData($consulta['NovaData']);
// 23 de outubro de 2005, as 13:13:13
?>

Agora quando você define no seu campo tipo Timestamp? como deve inserir o formato das datas no banco? Você usa o padrão americano, temos outra função pra isso, pra em vez de se matar escrevendo date() e suas propriedades, só chama a função PadraoData().

<?php
function padraoData() {
$exibe = date('Y m d H i s');
return $exibe;
}
?>

Se você mandar imprimir date(‘Y m d H i s’); vai ver que vai sair: YYYY MM DD H I S, não as letras, mas a data mesmo! que é o padrão americano, em timestamp! Em comparações isso fica mais perfeito ainda, não foge nem os segundinhos!

20041512030520  >  20031810122030 retorna  true

20031810122030 > 20041512030520   retorna  false

Índices para Pesquisa

 

Abraços ;-)

Bloqueio de rota administrativa do CakePHP

Olá Pessoal,

Quem utiliza o Fremwork CakePHP sabe que é uma mão na roda o route admin. Nos poupa um bocado de trabalho criar as funções da administração do site. Isso graças ao “Bake” Porém a rota não pode ficar totalmente acessivel a qualquer um, certo?

O Jonathan Snook escreveu um artigo em relação a isso, porém em alguns testes por aqui nenhum realmente funcionou utilizando .htaccess para proteção dessa rota com password.

Password Protecting Admin Functions in CakePHP.

O Conceito da proteção no artigo do Jonathan Snook é simples, E pode ser gerado com qualquer um que possua acesso ao SSH do site. Não é necessário acesso root para esses tipos de ações no servidor.
Seu servidor não te da acesso ao SSH? Está na hora de mudar para a IW²

O primeiro passo dessa proteção se dá ao inserir seguinte conteúdo no seu .htaccess :

1
2
3
4
AuthUserFile /diretorio/passwd/protecao
AuthName "Administracao CAKE"
AuthType Basic
Require valid-user

Com acesso ao ssh utilize o seguinte comando dentro da pasta “www”.

htpasswd -c /diretorio/passwd/protecao username

.
Isso gera um arquivo com a senha criptografada! Caso queira barar o arquivo gerado para verificar fiquem à vontade!

Bons testes, aqui nunca funcionou!

Meu jeitinho

A maneira no qual eu utilizo é a verificação simples de variavel, ou seja, apenas um usuário dentro do código no qual após o POST, verifica os dados, e grava uma sessão, se os mesmos forem iguais.

Primeiro passo é abrir o seu /app/config/routes.php, e crie uma rota chamada admin, usando o controller de páginas estáticas. Veja:

1
Router::connect('/admin/', array('controller' => 'pages', 'action' => 'display', 'admin'));

Agora crie um arquivo chamado admin.ctp dentro da pasta /app/views/pages/ com um formulário básico para login e senha:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php  
//Define o layout padrão para a página
$this->layout = 'admin'; 
?>
<h1><?php __('Administração');?></h1>
<?php   
// Caso ocorra algum erro, é exibido em sua div correta!
if(isset($error)) {   
    echo "<div class='error'>" . $error . "</div>";   
}   
?>   
<?php 
/*
criamos um formulário com o vetor User, indicando a rota /admin/login, onde teremos nossa verificação de usuário e senha para registro da sessão da administração, e acesso ao restante dos actions _admin_
*/
echo $form->create('User', array('url'=>'/admin/login/'));
?>   
<fieldset>
    <legend>Digite os dados</legend>   
        <?php  echo $form->input('username', array('label'=>'Login')); ?>
        <?php echo $form->input('password', array('label'=>'Senha', 'id'=>'Senha')); ?>   
  <?php echo $form->end('Logar!'); ?>   
   </fieldset>
</form>

O próximo passo é criar uma nova rota no /app/config/routes.php, rota no qual foi definida na URL do nosso formulário, onde será submetida os dados para verificação.

1
Router::connect('/admin/login/', array('controller' => 'users', 'action' => 'admLogin'));

Claro, obviamente eu já possuo um controller chamado users, caso não tenha, pode cria-lo, utilizando o código abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
class UsersController extends AppController {
 
	var $name = 'Users';
	var $helpers = array('Html', 'Form');
 
/*
Claro, que aqui irão outras actions suas ;)
*/
 
	function admLogin() {   
	    //verifica se o post possui alguma informação para registrar o nosso array com informações
	    if($this->data) {   
                $dbuser	=       array('username'=='Administrador', 'password'=>'Sua_senha_aqui');
	           if(($this->data['User']['username'] == $dbuser['username']) && 
                         ($this->data['User']['password'] == $dbuser['password']))  {   
                                 $this->Session->Write('admin', $dbuser);   
                                 // registra a sessão "admin" para futuras verificações
                                 $this->Session->setFlash('Logado com sucesso');   
                                 //Notifica o sucesso ao logar!
                                 $this->redirect('/admin/users/index');   
                                 // redireciona para a action index do controller users.
	        } else {   
	              $this->Session->setFlash('Erro! Dados inválidos');
                          // notifica o erro    
	        }   
	    }   
	}
 
 
}
?>

Note que por enquanto o nosso controller users possui apenas um action. Fica a seu critério a criação do resto do conteúdo ;)

Agora iremos criar a função para verificação da sessão:

1
2
3
4
5
6
7
8
9
<?php
	function checkAdminSession() {   
               if (!$this->Session->check('admin')) {   
               $this->Session->setFlash('Você não tem acesso a essa área');   
               $this->redirect('/admin/login/');   
    }   
}   
 
?>

A minha recomendação é que coloque essa função dentro do arquivo /app/app_controller.php no qual o cake carrega automáticamente. Esse arquivo serve para colocar as funções que vai utilizar em todos os controllers, sem a necessidade de ficar repetindo os mesmos.

Agora vem a parte mais interessante, vamos inserir o beforeFilter(); também dentro do /app/app_controller.php, para verificação do parametro /admin/ na url, e execução da verificação da sessão. Veja:

1
2
3
4
5
6
7
8
<?php
 
function beforeFilter() {   
        if(isset($this->params['admin'])) {   
           $this->checkAdminSession();   
    }   
 }
?>

O que a função faz é: Se existe algum parametro na url “admin”, executa a função checkAdminSession e veja se existe a sessão “admin”. Se não existir a sessão, a checkAdminSession redireciona para login.

Pronto, e assim você tem uma certa segurança em relação a rota /admin/ não estar sendo visualizada por tudo e por todos!

Leitura de XML – Parte 2 SimpleXML

Olá Pessoal,

Primeiramente, post de dia 24 de Dezembro, desejos a todos um Feliz Natal, que estejam todos ai junto a amigos e familiares curtindo uma data especial.

Bom, demorei um pouco, mas chegou, a segunta parte de Leitura de XML usando SimpleXML, dessa vez vou usar alguns modelos, ao invez de trabalhar com o nosso Feed de RSS, vamos trabalhar com valores de cambio e pesquisa de CEP. Tudo simples e em poucas linhas.

Primeiramente precisamos de algum XML que seja atualizado, com os valores que temos que trabalhar. Para isso existe esse endereço: http://www.republicavirtual.com.br/cotacao/exemplos.php

Não posso garantir 100% de uptime do link, pois não sei se algo vai mudar ok? Mas iremos trabalhar em cima dos retornos desse xml, ok?

Simple XML

O objetivo é fornecer acesso aos documentos XML usando propriedades de objetos e iterators, não é uma extensão complicada (são poucos métodos) mas é bastante flexível.

Exemplo Básico

Importando o XML da URL:

1
$file = simplexml_load_file('http://cotacao.republicavirtual.com.br/web_cotacao.php?formato=xml');

Iniciando o trabalho

Aqui vamos pegar o valor do dolar comercial para compras:

1
2
3
4
// importando o arquivo
$file = simplexml_load_file('http://cotacao.republicavirtual.com.br/web_cotacao.php?formato=xml');
// pegando a tag dolar_commercial_compra
echo $file->dolar_comercial_compra;

As tags que podemos trabalhar podem ser encontrada nesse XML

1
2
3
4
5
6
7
8
9
10
<webservicecotacao>
	<dolar_comercial_compra>2,1260</dolar_comercial_compra>
	<dolar_comercial_venda>2,1280</dolar_comercial_venda>
	<dolar_paralelo_compra>2,2200</dolar_paralelo_compra>
	<dolar_paralelo_venda>2,3000</dolar_paralelo_venda>
	<euro_dolar_compra>1,2410</euro_dolar_compra>
	<euro_dolar_venda>1,2410</euro_dolar_venda>
	<euro_real_compra>2,6384</euro_real_compra>
	<euro_real_venda>2,6408</euro_real_venda>
</webservicecotacao>

Viram como é simples trabalhar com o SimpleXML? Agora vamos trabalhar para achar endereços de CEP ;) O XML que iremos trabalhar emcima é desse modelo:

Trabalhando com CEP

Código:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="iso-8859-1" ?>
<webservicecep>
<resultado>1</resultado>
<resultado_txt>sucesso - cep completo</resultado_txt>
<uf>SP</uf>
<cidade>São Paulo</cidade>
<bairro>Santana</bairro>
<tipo_logradouro>Rua</tipo_logradouro>
<logradouro>Duarte de Azevedo</logradouro>
</webservicecep>

A URL que iremos importar as consultas é: http://cep.republicavirtual.com.br/web_cep.php?cep=02036021&formato=xml

Vamos ao Código:

1
2
3
4
5
6
7
$file = simplexml_load_file('http://cep.republicavirtual.com.br/web_cep.php?cep=02036021&formato=xml');
 
echo "UF: " .$file->uf;
echo "<br />Cidade: " .$file->cidade;
echo "<br />Bairro: " .$file->bairro;
echo "<br />Tipo de Logradouro: " .$file->tipo_logradouro;
echo "<br />Endereço: " .$file->logradouro;

Não recomendo que essa aplicação rode atravez da url de pesquisa, a base de dados pode ser baixada nesse endereço: Download

É isso, viram como é simples integrar uma pesquisa de CEP pra completar formulários de cadastros e tudo mais? Agora é com vocês ;)