PHP
Automação de scripts com PHP
by Michael Mafort on ago.12, 2010, under Linux, PHP
Programadores em ambiente linux já estão acostumados a fazerem diversos scripts para automatizarem tarefas utilizando o sh ou bash.
No entanto, não menosprezando o poder de tal linguagem, para quem está mais familiarizado com o PHP uma boa alternativa para gerar estes scripts é utilizando o próprio PHP.
Para isto precisamos de ter o php-client instalado, no ubuntu basta um “apt-get install php5-cli” para tê-lo instalado. Depois de instalado basta criar o seu arquivo php normalmente, como se estivesse usando-o dentro do apache.
Agora mudando para funcionar no prompt.
Na primeira linha do programa insira o seguinte:
#!/usr/bin/php
Seu script vai ficar mais ou menos assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/usr/bin/php <?php //Codigo de exemplo class Automatizar{ public function __construct(){ echo "Instanciado a classe."; } public function acao( $parametro1, $parametro2 ){ echo "Estou passando o $parametro1 e $parametro2 para o php."; } } $auto = new Automatizar; $auto->acao( $argv[1], $argv[2] ); ?> |
Para executar o script basta dar permissão de execução no arquivo:
1 | chmod 0777 script.php |
E executá-lo apenas chamando ele no console
1 | ./script.php MeuPrimeiroParametro "Meu segundo parametro" |
A saída será
Instanciado a classe.
Estou passando o MeuPrimeiroParametro e Meu segundo parametro para o php.
No código php a variável $argv recebe os valores passados como parametro no script, conforme exemplo acima, o primeiro elemento $argv[0] é o próprio nome do arquivo executado “script.php” e os demais vão seguindo a ordem que foi passada.
Para saber quantos argumentos foram passados tem a variavel global $argc que retorna a contagem dos argumentos.
Agora é correr e fazer os scripts em php para automações em shell.
Performance – menos requets e mais cache
by Michael Mafort on jan.29, 2010, under Desenvolvimento, PHP
Oba eu também quero! Mas o que é isso?
Uma das melhores praticas para se ter uma boa performance em sua página web é reduzir o número de requisições ao servidor, pois cada requisição abre um canal de comunicação que é composto por uma mensagem de ida que aguarda a mensagem de volta, que será a resposta, numa página pode ser html, imagem, css, js etc. Por isso é importante reduzir este número de requisições, pois o que vai tornar a exibição da página mais rapido não será necessariamente o seu tamanho total em Kb mas sim a quantidade de requisições que ela tem.
Agora sim!
Para economizarmos ( economia trabalha o melhor uso de recursos escassos, no nosso caso o tempo ) e ganharmos performance, uma das técnicas é da utilização de renderização de imagens usando inline images rfc 2397, ou seja você não vai ficar fazendo 1 requisição para cada imagem, elas irão ser carregadas juntamente com o seu html, isto agiliza o processo de renderização, diminui os seus requests e possibilita um controle de cache maior, pois todas as imagens estarão no mesmo arquivo html.
Vamos a prática
1 2 | No seu html vai ficar assim: <img src="<?php echo renderImagem( " alt="" />"> |
Com isso você irá reduzir consideravelmente os requests de imagens no seu servidor, diminuindo o tempo para renderização da página, no entando isto aumenta um pouco o tamanho da imagem que era compactada e passou a ser descompactada e enviada via base64, mas para isto há uma solução muito rápida e prática com o uso do mod_deflate do apache, mas isto já é assundo para um novo post.
Até logo e obrigado pelos peixes!
Facilidades para sua vida – Parte 9 – Vantagens do uso do SSH (locaweb, dreamhost)
by Michael Mafort on ago.23, 2009, under Acessibilidade, Facilidades para sua vida, Linux, Mysql, PHP
O uso do SSH por usuários linux é muito recorrente, pois traz muitas facilidades de acesso remoto a máquina onde se deseja executar alguma tarefa.
Hospedagens mais profissionais como na locaweb, dreamhost, goodady entre outros lhe oferecem esta ferramenta de acesso e gerenciamento do seu site.
Algumas coisas práticas que podemos fazer com o uso do ssh:
- Criar shell scripts para executar tarefas de backup, como já escrito no meu blog sobre backup do mysql, você pode criar um shell script para fazer o backup e gravar num diretório que não é acessivel pelo público.
- Vai subir um site que tem muitos arquivos (Normalmente quando você utiliza algum editor wysiwyg, tipo tyneMCE, fckEditor, entre outros) ? Que tal zipar a pasta e enviar via ftp para o site e depois via ssh você descompacta esta pasta no servidor? Muito fácil e útil. O contrário também é valido, zipar o site pra depois baixar.
- Usa o svn para controlar as versões dos seus arquivos que estão em desenvolvimento? Então você poderá simplesmente exportar a ultima versão, que será a publicada em produção diretamente no servidor.
- Sabe aquele site que vai dar manutenção, e tem 30 mil imagens, que no novo layout vão ter ela em tres tamanhos diferentes? E agora o que fazer, mandar para o design recortar uma por uma, jogar no html e forçar o tamanho, fazendo o usuário baixar mais do que precisava? Nada disso, você pode simplesmente criar um shell script para junto com o imagemagick redimencionar estas imagens, e como vai estar rodando diretamente no servidor atravez do shell, isso vai ser bem rápido.
Já que falei um pouco dos beneficios, que você descobrirá muito mais quando estiver utilizando, então vai umas dicas de como usar:
Para conectar em ambiente linux você pode abrir o console e digitar o seguinte:
ssh nome_usuario@seusite.com.br [enter]
senha: [digite sua senha, ela não irá aparecer, mas está sendo digitada] [enter]
Se você usa windows você pode utilizar o putty, disponível para download em http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
Aqui http://ajuda.locaweb.com.br/pt-br/Configurando_o_Putty você tem um tutorial de como se conectar usando o putty.
Alguns cuidados são extremamente importantes, como o uso de alguns comandos que poderão te atrapalhar um pouco, o uso de rm (REMOVE) irá excluir os arquivos que você passar como parametro, deve ser usado com cautela.
Shell Scripts devem ser testados antes de inseridos no site, para evitar algum tipo de travamento, ou loop infinito.
Alguns comandos básicos que poderá usar:
Zipar arquivos:
zip -r nomedozip.zip diretorio_a_ser_zipado
zip nomedozip.zip arquivo.ext
Descompactar zip:
unzip nomedozip.zip
ImageMagick, redimensionar imagem:
convert -resize [tamanho] arquivo.jpg arquivo_thum.jpg
ex.: convert -resize 200 arquivo.jpg arquivo_thum.jpg
Alguns exemplos podem ser vistos no site do ImageMagick [http://www.imagemagick.org/Usage/]
O uso do svn, tem outro post no meu blog a respeito.
Outras referencias:
Wiki Locaweb: http://ajuda.locaweb.com.br/pt-br/SSH (Como conectar na locaweb usando ssh)
Wiki Dreamhost: http://wiki.dreamhost.com/Ssh (Conectando via ssh na dreamhost)
Facilidades para sua vida – Parte 8 – Cronjobs com cakephp
by Michael Mafort on fev.26, 2009, under CakePHP, Facilidades para sua vida, Linux, PHP
Bom pessoal, de volta a ativa, vou neste post falar um pouco sobre como utilizar tarefas agendadas utilizando o crontab do linux.
Primeiro passo, copie o arquivo webroot/index.php para cron_dispatcher.php.
No cakephp versão final 1.2.1.8004, a linha a ser editada é após a 83, que está o seguinte código:
1 2 3 | if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } |
Você irá substituir para:
1 2 3 4 5 6 7 8 9 10 | if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } else { define(‘CRON_DISPATCHER’, true); if($argc == 2) { $Dispatcher = new Dispatcher(); $Dispatcher -> dispatch($argv[1]); } } |
Assim seu script dará acesso ao seu controller através do dispatcher, utilizando o phpclient. Para executar o script utilizando o crontab, deve-se fazer o seguinte:
1 | * * * * * php -q /var/www/app/webroot/cron_dispatcher.php /products/cron/ |
Onde os asteriscos na ordem significam:
1 – Minuto (0-59)
2 – Hora (0-23)
3 – Dia (1-31)
4 – Mês (1-12)
5 – Semana (0-6)
Para que os valores repitam sempre utilize o mesmo asterisco, exemplo: para executar o script 1 vez por dia a 0h use:
1 | 0 0 * * * php -q /var/www/app/webroot/cron_dispatcher.php /products/cron/ |
“php -q” executa o arquivo passado a seguir como parametro. neste exemplo vai chamar o arquivo /var/www/app/webroot/cron_dispatcher.php (lembre de passar o caminho absoluto ao arquivo).
O parametro /products/cron/ diz que o seu dispatcher vai chamar o action cron do controller products.
Agora já esta pronto o seu crontab, é só rodar e testar.
Abraço!
Facilidades para sua vida – Parte 7 – CakePHP json encode
by Michael Mafort on fev.02, 2009, under CakePHP, Facilidades para sua vida, PHP
Bom nesta parte vamos tratar de um problema muito comum quando vamos trabalhar com ajax, utilizando json como padrão de dados. O principal problema que enfrentamos é referente ao uso de palavras acentuadas e configurações do servidor, então para livrar deste problema criei um component que transforma as informações de uma query em json.
jsonComponent.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | class jsonComponent extends Object { public function encode($data){ $tmp_arr = array(); if( is_array($data) ){ foreach( $data as $key => $value ){ if( is_array($value) ){ $tmp_arr[] = "'$key':{" . $this->encode($value) . "}"; } else{ $tmp_arr[] = "'$key':'$value'"; } } } else { return "'$data'"; } return join(", ", $tmp_arr); } } |
Para utilizá-lo basta inserir em seu controller a variável:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $components = array('json'); //para converter um array em json use: function minha_funcao(){ $produtos = array('Produto'=>array( array('id'=>1, 'descricao'=> 'Carne moída', 'valor'=>10.50), array('id'=>2, 'descricao'=>'Feijão preto', 'valor'=>2.90))); $json = "{" . $this->json->encode($produtos) . "}"; echo $json; //resultado será: //{'Produto':{'0':{'id':'1', 'descricao':'Carne moída', 'valor':'10.5'}, '1':{'id':'2', 'descricao':'Feijão preto', 'valor':'2.9'}}} |
Ou você poderá criar diretamente um novo método ao seu app_model da seguinte forma:
app_model.php
1 2 3 4 5 6 7 8 | public function json($type='all', $conditions=array()){ $result = $this->find($type, $conditions); App::import("Component", "json"); $json = new jsonComponent(); return "{". $json->encode($result) ."}"; } |
Com o método no app_model, você vai chamar o seu método da seguinte forma:
1 2 3 4 5 6 7 8 9 | //Utilize a mesma sintaxe do find $meu_json = $this->MeuModel->json('all', array('conditions'=>array('MeuModel.preco < 2'), 'fields'=>array('MeuModel.id','MeuModel.descricao'))); echo $meu_json;//{'Produto':{'0':{'id':'1', 'descricao':'Carne moída', 'valor':'10.5'}, '1':{'id':'2', 'descricao':'Feijão preto', 'valor':'2.9'}}} //Lembre-se sempre de definir o header antes da saída de dados "echo" quando estiver utilizando json. //Exemplo: header('Content-Type: text/javascript'); echo $meu_json; |
No javascript para acessar os valores pode-se usar:
1 2 3 | var json = {'Produto':{'0':{'id':'1', 'descricao':'Carne moída', 'valor':'10.5'}, '1':{'id':'2', 'descricao':'Feijão preto', 'valor':'2.9'}}}; produto_um = json.Produto[0].id; // use um loop para percorrer dinamicamente todo o objeto, recomendo utilizar "for in". |
Bom espero que possa ser mais uma facilidade para vocês também.
Abraço!
Facilidades para sua vida – Parte 6 – Acesso restrito para imagens
by Michael Mafort on jan.29, 2009, under Facilidades para sua vida, Linux, PHP
Bom, hoje no grupo de php surgiu uma dúvida de como fazer um bloqueio de acesso a imagens caso o usuário não tenha permissão (não esteja logado), então sugeri que fosse feito utilizando regras do htaccess, vejamos como ficou.
Vamos seguir o exemplo da seguinte estrutura:
htdocs
- scripts
- img
- etc…
Dentro do diretório img que temos as imagens restritas, vamos criar um arquivo .htaccess.
Lembrando que antes de usar os arquivos .htacess o seu apache deve estar configurado para leitura destes arquivos e o módulo rewrite habilitado.
Para isto basta verificar se seu httpd.conf está com estas configurações:
1 2 3 4 5 6 7 | LoadModule rewrite_module modules/mod_rewrite.so AddModule mod_rewrite.c <directory> Options Indexes FollowSymLinks AllowOverride All </directory> |
Se não tiver basta descomentar as linhas do LoadModule e AddModule, e adicionar dentro do seu directory root as duas linhas, Options e AllowOverride.
Agora vamos criar nosso arquivo .htaccess:
1 2 3 4 5 6 7 8 9 10 11 | <IfModule mod_rewrite.c> Options +FollowSymlinks RewriteEngine on #Verificamos se a imagem é .jpg ou .gif RewriteCond %{REQUEST_FILENAME} (.jpg|.gif)$ #Redirecionamos a requisição para o arquivo index.php #passando como parametro get o nome da imagem $1 RewriteRule ^(.*)$ index.php?image=$1 [NC,L] </IfModule> |
Criamos também o arquivo index.php dentro do diretório img, vamos ao exemplo:
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 | <?php //Inicia a sessão @session_start(); //Setamos a sessão para o teste com o valor 1 //Para testar se não o usuário não está logado, exclua a linha abaixo $_SESSION['uid'] = 1;//logado /* Verifica se existe a sessão, deve ser feito de acordo com sua necessidade Este é apenas um exemplo didático */ if( isset($_SESSION['uid']) ){ //Define o header para o mime type do arquivo requisitado image/jpg ou image/gif header("Content-Type: ".mime_content_type($_GET['image']) ); //Lê o arquivo e joga na saída readfile($_GET['image']); }else{ //Define o Contenty-type como image/gif header("Content-Type: image/gif" ); //Lê o arquivo e joga na saída readfile('deny.gif'); } ?> |
Crie um arquivo chamado deny.gif no seu diretório img para ser exibido caso o usuário não tenha permissão para visualizar as imagens.
Pronto, o acesso as suas imagens já estará bloqueado para usuários que não estejam logados.
Abraço!
Facilidades para sua vida – Parte 4 – Expressões Regulares
by Michael Mafort on jan.26, 2009, under Facilidades para sua vida, PHP
Em javascript, php, java, action script 3 entre outras linguagens de programação temos suporte às expressões regulares, que auxiliam no serviço de tratamento de strings de várias formas, dentre elas:
- Validação de datas, emails, ip, url;
- Procura por termos expecificos;
- Procura por textos no inicio ou fim da string;
- Substituição de termos.
“Bem resumido, uma expressão regular é um método formal de se especificar um padrão de texto.
Mais detalhadamente, é uma composição de símbolos, caracteres com funções especiais, que, agrupados entre si e com caracteres literais, formam uma seqüência, uma expressão. Essa expressão é interpretada como uma regra, que indicará sucesso se uma entrada de dados qualquer casar com essa regra, ou seja, obedecer exatamente a todas as suas condições.” [http://guia-er.sourceforge.net/apresentando.html#1_3]
Nesta parte vamos aprender um pouco sobre o funcionamento e ver alguns exemplos de uso em javascript e php.
Caracteres e seus significados:
. (ponto) – Significa que pode ter entrada de qualquer caracter. A expressão /./ tanto em php quanto em javascript significa que pode-se dar entrada de quantos caracteres quiser em qualquer combinação.
Ex.:
1 2 3 4 5 6 7 8 9 10 11 | //Verifica se a string não está vazia function javascriptER(){ //Declara a expressão regular var ER = /./; //Testa a string asd com a ER. Neste teste o retorno será true se passar "" vazio o retorno será false. return ER.test("asd"); } |
1 2 3 4 5 6 7 8 9 | function phpER(){ //Declara a expressão regular $ER = '/./'; //Testa a string asd com a ER. Neste teste o retorno será true se passar "" vazio o retorno será false. return preg_match($ER, "string"); } |
Criando listas: Listas são agrupamentos de informações em ER para dizer alguma determinada regra.
Ex.: [0-9] nesta lista se tiver algum numero de 0-9 (o hifen serve como escala de até de 0 até 9 de A até Z…) ele retornará true, para verificar se tem apenas número use /^[0-9]{1,}$/ onde ^ diz que inicia a ER e $ diz quando termina, {1,} significa que o valor será procurado de 1 até N vezes na string, assim a string com “00099878″ retornará true e a string com “03090338.0494″ retornará false. Para validar um número com duas casas decimais, separado por ponto usaria /^[0-9]{1,}[\.][0-9]{0,2}$/ o \. significa que o caracter “.” está sendo escapado, pois ele representa qualquer caracter, sendo escapado representará apenas ele mesmo.
Agora já vimos que ^ significa que deverá ser procurado no inicio, $ no final {2,3} quantidade de vezes que a regra da lista pode ser repetida, \ é o caracter de escape.
Agora vem outro significado para o caracter ^ (circunflexo), ele também representa o valor negativo, rejeitado, oposto, not. Ex.: [^0-9] ele irá procurar todos os caracteres que não sejam de 0 a 9. Se quiser criar uma regra com o circunflexo pode-se utilizá-lo no final da instrução, assim: [0-9^] retorna verdadeiro para caracteres de 0 a 9 e ^ 00099^09 é um valor válido para esta ER.
Bom como tem gente na internet que já explicou muito melhor do que eu poderia explicar o que são ERs, vou mandar para vocês o link de um pequeno tutorial de como usar Expressões Regulares.
http://guia-er.sourceforge.net/
Outra dica é o Add-on do Firefox para testar as suas Expressões regulares:
Firebug (utilizando o console para executar scripts javascript em modo interativo)
Abraço,
Facilidades para sua vida – Parte 3 – Utilizando frameworks
by Michael Mafort on jan.25, 2009, under CakePHP, Facilidades para sua vida, PHP
Framework segundo a wikipédia, é “um conjunto de classes que colaboram para realizar uma responsabilidade para um domínio de um subsistema da aplicação.”
Resumindo os frameworks vieram para facilitar nossas vidas, agilizando (e muito) o processo de desenvolvimento e criando padrões que tornam a programação unificada e de fácil manutenção por qualquer um, desde que o padrão adotado pelo framework seja entendido e aplicado pelo desenvolvedor.
Alguns exemplos de frameworks:
Javascript (Biblioteca de funções javascript, como efeitos, animações, controle DOM, ajax…):
Jquery – Na minha opinião a mais produtiva e fácil aprendizado, compatibilidade com a maioria dos browsers em uso e vários plugins que podem ser acrescidos para facilitar ainda mais.
Prototype – Fácil uso de ajax e controle DOM.
ExtJS – Com uma biblioteca gráfica para customização muito boa.
Dojo, – Rápida e com vários addons.
PHP:
CakePHP - Agilidade no desenvolvimento, padrões de Design Pattern, MVC, ORM (Mapeamento Objeto Relacional), Scaffold (Desenvolvimento de Criação, Edição, Visualização e Exclusão de dados em uma linha de código), acesso a components entre outras milhares de funcionalidades que facilitam nossas vidas. Baseado no Rails do Ruby on Rails, é um framework php completo.
CodeIgniter - MVC, curva de aprendizagem baixa, fácil intendimento, processamento veloz das informações documentação completa.
ZendFramework - O mais robusto e com certeza o que será em breve o melhor framework, pois é desenvolvido pela mesma empresa que mantem hoje o php.
Bom acredito que com estes frameworks já possa ter um desempenho melhor e uma programação mais limpa daqui pra frente.
Abraço.
Série facilidades para sua vida – Parte 1: Criando views
by Michael Mafort on jan.21, 2009, under Facilidades para sua vida, Linux, Mysql, PHP
Este é o primeiro post de uma série que poderá lhe ajudar na hora de fazer algo de uma forma mais prática, rápida e elegante. Neste primeiro post vamos tratar das queries gigantes que as vezes encontramos em alguns códigos por ai.Vejamos um exemplo:
Temos as tabelas: usuarios, produtos, vendas, venda_produtos e venda_status.
Onde os campos das tabelas sejam:
usuarios -> id, nome, telefone, endereco
produtos -> id, descricao, valor
vendas -> id, usuario_id, data, venda_status_id
venda_produtos -> id, venda_id, produto_id
venda_status -> id, descricao
Criando as tabelas:
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 | CREATE DATABASE teste_view; USE teste_view; CREATE TABLE usuarios( id int(11) not null auto_increment primary key, nome varchar(60) not null, telefone varchar(15), endereco varchar(200) ); CREATE TABLE produtos( id int(11) not null auto_increment primary key, descricao varchar(120) not null, valor decimal(4,2) ); CREATE TABLE vendas( id int(11) not null auto_increment primary key, usuario_id int(11) not null, data datetime, venda_status_id int(11), index usuario_id(usuario_id), index venda_status_id( venda_status_id ) ); CREATE TABLE venda_produtos( id int(11) not null auto_increment primary key, venda_id int(11) not null, produto_id int(11) not null, index venda_id( venda_id ), index produto_id( produto_id ) ); CREATE TABLE venda_status( id int(11) not null auto_increment primary key, descricao varchar(60) not null, index descricao( descricao ) ); |
Insira dados nas tabelas:
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 | #Adicionando usuarios INSERT INTO usuarios (nome, telefone, endereco) VALUES ( 'José pereira', '31 3333-3333', 'rua dos subidos, 123' ); INSERT INTO usuarios (nome, telefone, endereco) VALUES ( 'Maria pereira da silva', '31 4444-4444', 'rua das marias, 12' ); INSERT INTO usuarios (nome, telefone, endereco) VALUES ( 'Willy Nelson', '31 5555-5555', 'rua dos cantores, 120' );#Adicionando produtos INSERT INTO produtos ( descricao, valor ) VALUES ('CAMERA DIGITAL',199.50); INSERT INTO produtos ( descricao, valor ) VALUES ('FILMADORA',999.50); INSERT INTO produtos ( descricao, valor ) VALUES ('GELADEIRA',899.50); INSERT INTO produtos ( descricao, valor ) VALUES ('FOGÃO',399.50); INSERT INTO produtos ( descricao, valor ) VALUES ('CHURRASQUEIRA',99.50); INSERT INTO produtos ( descricao, valor ) VALUES ('NOTEBOOK',1999.50); INSERT INTO produtos ( descricao, valor ) VALUES ('MONITOR LCD 15',399.50); #Adicionando status de vendas INSERT INTO venda_status (descricao) VALUES ('Em processamento'); INSERT INTO venda_status (descricao) VALUES ('Aguardando pagamento'); INSERT INTO venda_status (descricao) VALUES ('Aprovada'); INSERT INTO venda_status (descricao) VALUES ('Cancelada'); #Adicionando vendas INSERT INTO vendas (usuario_id, data, venda_status_id) VALUES (1, '2009-01-20 10:20:00', 1); INSERT INTO vendas (usuario_id, data, venda_status_id) VALUES (2, '2009-01-22 10:22:00', 2); INSERT INTO vendas (usuario_id, data, venda_status_id) VALUES (1, '2009-01-22 10:44:00', 4); #Adicionando produtos as vendas #Nessa compra joão comprou uma camera digital e uma filmadora INSERT INTO venda_produtos (venda_id, produto_id) VALUES (1,1); INSERT INTO venda_produtos (venda_id, produto_id) VALUES (1,2); #Nessa foram comprados por maria um fogão e uma geladeira INSERT INTO venda_produtos (venda_id, produto_id) VALUES (2,4); INSERT INTO venda_produtos (venda_id, produto_id) VALUES (2,3); #Nessa o joão comprou um notebook INSERT INTO venda_produtos (venda_id, produto_id) VALUES (3,6); |
Agora suponhamos que vc queira agrupar estas informações num único select, então teremos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | SELECT produtos.descricao AS produto_descricao, produtos.valor AS produto_valor, usuarios.nome AS usuario_nome, usuarios.telefone AS usuario_telefone, usuarios.endereco AS usuario_endereco, venda_status.descricao AS venda_status, vendas.id AS venda_id, vendas.data AS venda_data FROM vendas INNER JOIN venda_produtos ON ( vendas.id = venda_produtos.venda_id ) INNER JOIN produtos ON ( produtos.id = venda_produtos.produto_id ) INNER JOIN usuarios ON ( usuarios.id = vendas.usuario_id ) INNER JOIN venda_status ON ( venda_status.id = vendas.venda_status_id ) |
Agora suponhamos que vc use este select em 3 lugares diferentes, então vc vai ter que passar esta query em 3 locais distintos, podendo gerar uma confusão na hora da manutenção, então para isto existem as views. Elas simulam uma tabela, agem como uma tabela, mas só estão disponíveis para exibir os dados, não podendo sofrer exclusão ou alteração de registros, muito útil ela nestes casos que acabamos ficando com uma query gigante para simplificar nossas vidas.
então para criar a view basta vc adicionar antes da query CREATE VIEW nome_da_view AS ( aqui entra a query ).
Ex.:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | CREATE VIEW view_vendas AS ( SELECT produtos.descricao AS produto_descricao, produtos.valor AS produto_valor, usuarios.nome AS usuario_nome, usuarios.telefone AS usuario_telefone, usuarios.endereco AS usuario_endereco, venda_status.descricao AS venda_status, vendas.id AS venda_id, vendas.data AS venda_data FROM vendas INNER JOIN venda_produtos ON ( vendas.id = venda_produtos.venda_id ) INNER JOIN produtos ON ( produtos.id = venda_produtos.produto_id ) INNER JOIN usuarios ON ( usuarios.id = vendas.usuario_id ) INNER JOIN venda_status ON ( venda_status.id = vendas.venda_status_id ) ); |
Bom agora vc já tem a sua view, para buscar os dados a partir dela faça um select normal. Ex.:
1 2 3 4 5 6 7 | SELECT sum(produto_valor) FROM view_vendas; #ou com um where agora SELECT sum(produto_valor) FROM view_vendas WHERE venda_id = 1;#para visualizar todas as suas views basta dar um SHOW TABLES, que ela estará la como uma tabela. #para certificar que é uma view e não uma tabela mesmo vc pode confirmar usando SHOW CREATE TABLE nome_da_view; |
Bom por hoje é só.
Espero que isto possa facilitar um pouco a sua vida.
Abraços,
Teste Unitário – Cakephp
by Michael Mafort on set.04, 2008, under PHP
Com o concentimento do autor, estou publicando este artigo que é simplesmente uma aula de testes.
class Aula{
Vou falar um “pouco” sobre o que eu sei, mas eu recomendo que todos procurem na internet e estudem, pois o assunto é interessante.
A primeira vantagem de se escrever teste é trivial. Ao invés de ficar fazendo testes manualmente, você escreve programas que testam automaticamente. Testes automatizados criam uma malha protetora, garantindo que seu código faça aquilo que você pensa que ele tem que fazer. Automatizar testes ajudam você testar aquela aplicação de 5000 linhas em pequeno tempo de execução.
Bem, como esta técnica notoriamente é vantajosa, os desenvolvedores começaram a usa-la e uns malucos acharam TÃO boa que começaram a testar antes mesmo de escrever código. Dai nasce o TDD[1]. Você não pode testar manualmente alguma coisa que ainda não criou, mas pode programar algo que teste.
Como os programadores buscam sempre o DRY (dont repeat yourself), foram criados vários frameworks e ferramentas para melhorar a forma com que testamos, posso citar os xUnits, a cobertura de testes, gerenciadores de macros, fixtures, etc. São inúmeras ferramentas e, normalmente, cada linguagem possui um grande conjunto delas, portanto não vou me aprofundar nisto.
No CakePHP, o framework de teste utilizado é o SimpleTest[2]. A função de um framework de teste é prover o cenário ideal para se realizar testes. Quem mexe com experimentos sabe a importância de se ter um ambiente apropriado. Um exemplo desta preparação de ambientes são os fixtures. Para fazermos testes é importante sabermos o estado inicial de sua aplicação. Imagine testar a inserção de um comentário em um tópico, no momento de desenvolvimento do teste, você tinha certeza que o tópico existia, mas se no momento de execução do teste ele não existir? Seu teste irá falhar, mas não por que seu programa está corrompido, mas sim por que o estado inicial do teste não estava controlado.
Os principais métodos que usamos no framework são os métodos de Assert, no SimpleTest encontramos diversos[3], eles nos auxiliam a testar vários tipos de situações. É fazendo asserções que vocês irão testar seus códigos. Um exemplo de asserção é: Se eu passar o valor 5 para uma função de fatorial o resultado tem que ser 120. As asserções são feitas na tentativa de explorar seus códigos. Não é interessante fazer 10 asserções testando todos os valores entrado entre 5 e 15. Mas se eu testar alguns valores chaves, que realmente tragam significado, estarei realmente protegendo minha aplicação. No exemplo, alguns testes interessantes são valores negativos, 0 e 1.
Os testes são divididos em 3 grandes áreas (me desculpem se estou falando alguma merda): Unitário, Funcional e de Aceitação. Os de aceitação são aqueles que envolve testes que o seu cliente faria, testes que envolvem a interface, algo que pegue a aplicação inteira. Mesmo existindo ferramentas para estes testes, normalmente não se roda toda hora, eles podem ser custosos. Testes funcionais são aqueles que testam integrações entre objetos e métodos, é quando dois ou mais objetos devem trabalhar juntos. Já os testes unitários testam a lógica local de um objeto, de um método. Não tem muita diferença entre unitário e funcional, somente o conceito.
Bem, é este o conceito por trás dos testes, não sei mais o que eu posso falar. Para dar algo prático, vou tentar falar um pouco de como testar no CakePHP, mas não prometo muita coisa, não tem como falar de tudo.
A primeira coisa que vocês terão que fazer é colocar o SimpleTest na pasta Vendors (seja ela da aplicação ou do cake), assim vocês poderão rodar os testes. A título de experiência, visitem o link http://endereco_aplicacao/
Agora que sabem como executar os testes, vamos fazer alguns testes. Primeiramente, como tudo no CakePHP, existe uma convenção de nomes de arquivos O padrão do Cake é XXXX.test.php. O XXXX pode ser qualquer coisa, mas é recomendável que seja o nome do arquivo que você quer testar (quando forem fazer cobertura de teste vocês entenderão). Utilizem as pastas predefinidas do CakePHP.
Eu vou utilizar um exemplo aqui sobre um Model de Tópicos, vocês utilizem o que for necessário para sua aplicação. Primeira coisa, vou criar um arquivo chamado topico.test.php na pasta /app/tests/cases/models. E, utilizarei a seguinte estrutura:
App::import(’Model’,'Topico’);
class TopicoTestCase extends CakeTestCase {
var $fixtures = array (’topico’);
}
Antes de mais nada, eu não utilizo o método que tinha no CookBook do Cake. Eu faço diferente e parece que outras pessoas[4] também não gostaram e já incluiram uma correção no Cake. Como não sei se esta correção está no RC2 ou só no SVN, vou explicar o que é necessário para fazer do meu modo. Peço desculpas, mas não vou explicar o por que disto, pois só iria complicar, mais explicações no [4].
Adicionem no app_model.php de sua aplicação a seguinte lógica:
function __construct(){
if(isset($_GET['app'])){
$this->useDbConfig = ‘test’; // Ou nome do seu DataSource de teste (aquele que fica no arquivo database.php)
}
parent::__construct();}
Agora voltando, o código inicial é simples, primeiro estamos incluindo a classe Topico para podermos instancia-la e testa-la. Criamos uma sub-classe de Case do CakeTestCase, assim teremos todo o ambiente necessário para podermos testar. E colocamos uma variável chamada fixtures. PARA! O que é fixtures?
Bem, lembram quando falei de ambiente de testes? de que tínhamos de ter controle do estado inicial de nossos testes? Quem garante isto são os Fixtures. O fixture vai, A CADA teste LIMPAR todo o banco e REPOPULAR com as ENTRADAS especificadas no arquivo de fixtures. Assim, você terá a certeza de que todo inicio de teste você tem um banco limpinho e bunitinho. No meu exemplo, o arquivo teria o nome topico_fixture.php e ficaria no /app/tests/fixtures/ :
class TopicoFixture extends CakeTestFixture {
var $name = ‘Topico’;
var $fields = array(
‘id’ => array(
‘type’ => ‘integer’,
‘key’ => ‘primary’
),
‘titulo’ => array(
‘type’ => ’string’,
‘length’ => 200,
),
‘publicado’=> array(
‘type’ => ‘boolean’
)
);
var $records = array(
array(
‘id’=>1,
‘titulo’=>’Como escrever um e-mail gigantesco’,
‘publicado’=>true
),
array(
‘id’=>2,
‘titulo’=>’Como ler um texto antes de escrever?’,
‘publicado’=>false
)
);
}
Só para explicar, a variável $fields é a estrutura do banco (vocês podem utiliza o shell schema para gerar isto para vocês[5]) e o $records são os dados que ele irá incluir. (olhem o CookBook, tem mais coisa [6])
Agora é só fazermos os testes. Para fazermos nossos testes, vamos usar a convenção de nome de função do CakePHP. Iniciamos todas as funções que queremos que sejam executadas no Case com o seguinte formato testXXXXXX, cada função será um teste. Dentro desta função você usa os Asserts. No exemplo, vou testar uma funcionalidade do meu model que retorna o número de Topicos publicados.
function testNumeroPublicados(){
$modelo =& new Topico();
$esperado = 1;
$encontrado = $modelo->numeroPublicado();
$this->assertEqual($esperado,$
}
Simples não? A lógica do método numeroPublicado() não importa, ele pode até mesmo não exitir, o que estamos fazendo aqui é o teste. Uma coisa importante de se lembrar é que temos liberdade de “estragar” o banco, pois os fixtures vão recompo-lo novamente no próximo teste, exemplo:
function testNumeroPublicados(){
$modelo =& new Topico();
$esperado = 1;
$encontrado = $modelo->numeroPublicado();
$this->assertEqual($esperado,$
$modelo->publicarId(2);
$esperado = 2;
$encontrado = $modelo->numeroPublicado();
$this->assertEqual($esperado,$
}
Entenderam? Agora é só melhorando os testes, forçando algumas situações, algo que possa dar problemas. Bem, escrever teste é como escrever código, vocês vão ter que melhorar, refatorar, pensar em novas lógicas, etc.
Bem pessoal, espero ter ajudado. Com mais calma eu vou melhorar o que escrevi aqui. Mas agora eu quero que vocês tentem em casa, no trabalho, façam perguntas e o mais importante: testem suas aplicações completamente.
Abraços.
[1]http://www.improveit.com.
[2]http://simpletest.org/
[3]http://simpletest.org/api/
[4]http://debuggable.com/
[5]Comando: php cake.php -app aplicacao schema generate // isto criará um arquivo schema.php no na pasta /aplicacao/config/sql/
[6]http://book.cakephp.org/
}
Autor: João José Carvalho Pedrini