quarta-feira, 22 de abril de 2009

Módulos no Zend Framework

E ai pessoal,
Há um tempo atrás eu passei um sufoco ao tentar criar a separação dos meus controllers e diretórios por módulos. Nas minhas pesquisas para resolver meu problema, verifiquei que há muitas pessoas encontrando esta dificuldade e sem soluções.
Vamos imaginar que você possui um site que terá a área default(front com os usuários) e a parte de administração - admin(front dos administradores do site). É dessa forma que veremos como criar esses módulos.
Eu fiz o teste do exemplo utilizando o XamppLite 1.7.0 e o Appserv 2.5.10.
Obs.: Caso esteja tendo problemas com o .htaccess, leia mais no final do post (Dicas).

Eu cheguei a fazer testes com o Application server, mas deu um problema com relação a segurança e redirecionamentos do .htaccess. Estou entrando em contato pelo site do application server para poder solucionar o problema, mas pelo xampplite deu tudo certo.

ESTRUTURA DE DIRETÓRIOS

Deve existir várias formas de separar os módulos. Postarei a forma que obtive sucesso após bater a cabeça.
A estrutura do nosso diretório ficará como a figura abaixo:



Note que dentro de application eu criei um diretório chamado admin e outro chamado default(marquei de vermelho), que serão nossos módulos e conterão seus próprios controllers, models e scripts.

Para cada área da administração eu criei um controller, onde vc pode inserir as Actions de add, edit, etc...Assim como os arquivos phtml.
Os nomes dos arquivos phtml precisam ser iguais ao de suas Actions. Por exemplo, dentro do Controller NoticiasController, terei as seguintes actions:
public function addAction(){...}
public function editAction(){...}
e o nome de seus templates: add.phtml e edit.phtml

É dessa forma que o Zend trabalha. Caso tenha alguma outra forma que você saiba e tenha se sentido incomodado com minha observação, pode postar um comentário que ficarei feliz de saber outra forma. :)

CONTROLLERS

Como nós separamos nosso exemplo em módulos, devemos dizer ao index.php onde ficarão esses módulos.

No seu index.php, adicione a seguinte linha:
//Cria a instrancia do front_controller
$controller = Zend_Controller_Front::getInstance();

//Indica o topo do nosso diretório. por exemplo, caso o seu endereço fique: http://localhost/sistemas/Exemplo, o seu setBaseUrl deverá ficar com o valor '/sistemas/Exemplo'. No meu caso, estarei acessando http://localhost/ex_modulo
$controller->setBaseUrl('/Ex_modulo');

// mostra os erros em modo de execução
$controller->throwExceptions(true);

//Diz onde está os controllers do nosso módulo default
$controller->setControllerDirectory('./application/default/controllers');

//Aqui nós dizemos ao ZF que existe um módulo chamado admin e que seus controllers estão no diretório passado por parâmetro.
$controller->addControllerDirectory('./application/admin/controllers', 'admin');



Note que nos diretórios de controllers eu já criei os controllers para cada área de nossa administração: IndexControllers.php, NoticiasController.php e BlogsController.php .
Quando criamos nosso projeto sem módulos, o nome da classe dos módulos no nosso caso ficaria +/- assim:

public class NoticiasController extends Zend_Controller_Action(){...}
Se você tentar executar seu projeto o Zend reclamará que ele não conseguiu achar os controllers requisitados.
Como separamos nosso projeto em módulos, as nossas classes deverão conter o nome do nosso Módulo (com a primeira letra em maiúsculo) + underline"_" + NomedomoduoloController
Ficou confuso? bom, o resultado final ficaria assim:
public class Admin_IndexController extends Zend_Controller_Action(){...}
public class Admin_NoticiasController extends Zend_Controller_Action(){...}
public class Admin_BlogsController extends Zend_Controller_Action(){...}


DICAS

1 - No seu index.php indique seus include paths do seguinte modo:
setlocale(LC_ALL, 'BRA');
date_default_timezone_set('America/Sao_Paulo');
set_include_path('.' . PATH_SEPARATOR . '..' . PATH_SEPARATOR . './library'
. PATH_SEPARATOR .'./application/default/models/'
. PATH_SEPARATOR .'./application/admin/models/'
. PATH_SEPARATOR
. get_include_path());

E para facilitar nossa vida, você pode utilizar a o autoload do Zend:

include "Zend/Loader.php";
Zend_Loader::registerAutoload();

2 - Inclua o arquivo .htaccess no diretorio raiz do seu projeto que no nosso caso é o Ex_modulo:
Arquivo .htaccess:
# Rewrite Engine config
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(gif|jpg|png|css|js|controller.php|tpl|trans.php|service.php)$ index.php

# Coloca UTF-8 como charset padrao
AddDefaultCharset iso8859-1

# Desabilita a auto insercao de escapes (\)
php_flag magic_quotes_gpc off

# Desabilita as Variaveis globais
php_flag register_globals off

No appserv e wampp, é necessário descomentar a seguinte linha no httpd.conf do apache:
LoadModule rewrite_module modules/mod_rewrite.so
se não vc vai obter o erro: Internal Server error .
O Xampplite já vem com a linha descomentada por padrão (pelo menos nessa versão).

Veja que eu inseri o Charset Iso8859-1 no arquivo htacces.
Caso você não lembre que estamos setando essa configuração no .htaccess e você quer q seu projeto rode com o charset utf8 e não lembrar de mudar no seu .htaccess, você vai ter sérias dores de cabeça procurando onde esta seu problema de CharSet.

Bom pessoal, em caso de dúvidas ou caso queiram que eu envie os arquivos do Exemplo, comentem ou me enviem e-mail que enviarei os arquivos de exemplo.

Abraços e até +

quinta-feira, 9 de abril de 2009

Upload de arquivos com Zend Framework

E ai pessoal,
Depois de um longo tempo sem escrever devido à mudança de emprego que tive, escreverei hoje sobre um framework que tenho estudado, o Zend Framework.

Lembra de quando você fazia o código para upload de arquivos do seu site e tinha uma "dor de cabeça" para obter tamanho de arquivo, verificar extensão, tamanho e etc?

O Zend já faz essa brincadeira para nós. É aquela velha história de não termos que reinventar a roda ou perder tempo criando nossas proprias classes e, além de criar, fazer testes exaustivos.
Então, pq não usar um framework de confiança e já testado?

Para este tutorial, você precisa ter uma base de como funciona o Zend Framework, como carregar(include) seus arquivos com o Zend_Loader por exemplo e saber como o Zend visualiza a estrutura de arquivos do seu projeto.
Para isso, eu indico um bom tutorial para iniciantes:

http://akrabat.com/wp-content/uploads/iniciando-com-zend-framework_130.pdf

AS CLASSES

O Zend possui uma classe Zend_File_Transfer que além de nos permitir trabalhar com uploads, também nos dá uma mão para a segurança em download de arquivos do nosso site.

Para conseguirmos indicar para onde irá nossos arquivos e checar algumas configurações, utilizaremos a classe Zend_File_Transfer _Adapter_Http

EXEMPLOS


Vamos criar um formulário que conterá um input file 'uploadedfile', que será responsável por carregar nosso arquivo (lembrando que precisamos ter o enctype preenchido sempre que formos mexer com arquivos em nossos formulários).


Arquivo:




Além de fazer o formulário de envio via HTML, podemos usar também a classe
Zend_Form_Element_File (O que eu acho melhor, veja o pq).
Exemplo:


$element = new Zend_Form_Element_File('uploadedfile');
$element->setLabel('Enviar arquivo:')
->setDestination('c:\Temp');

// Quero que o usuário envia apenas 1 arquivo
$element->addValidator('Count', false, 1);
// com o tamanho limite de 100K
$element->addValidator('Size', false, 102400);
// apenasJPEG, PNG, e GIFs
$element->addValidator('Extension', false, 'jpg,png,gif');
$form->addElement($element, 'foo');


//Setando o destino de nossos arquivos de upload (Caso use o exemplo de formulário em html)
$adapter = new Zend_File_Transfer_Adapter_Http();

$adapter->setDestination('C:\temp');

if (!$adapter->receive()) {
$messages = $adapter->getMessages();
echo implode("\n", $messages);
}


//Carregando os arquivos para o servidor
$upload = new Zend_File_Transfer();

// Retorna as informações referente ao arquivo
$files = $upload->getFileInfo();

foreach ($files as $file => $info) {
//O usuário escolheu um arquivo ou o campo esta vazio?
if (!$upload->isUploaded($file)) {
print "Pq vc nao escolheu o seu arquivo e deixou o campo vazio?";
continue;
}

// Tudo ok?
if (!$upload->isValid($file)) {
print "Desculpe, mas o arquivo $file não é o que queremos.";
continue;
}
}

//Envia para o servidor
$upload->receive();

// Obtem o nome do arquivo
$names = $upload->getFileName('
uploadedfile');

// Retorna o tamanho do arquivo
$size = $upload->getFileSize(
'uploadedfile');

// Retorna o mimetype do arquivo (Se é jpeg, gif, pdf, etc)
$type = $upload->getMimeType('
uploadedfile');


Que ajuda o Zend nos fornece né?
Bom, é isso ai!
Para dúvidas, consultem o manual da Zend:

http://framework.zend.com/manual/en/zend.file.html

quarta-feira, 4 de março de 2009

Trabalhando com arquivos XML no PHP

E aew pessoal.
Esses dias eu criei uma aplicação simples em PHP para ser utilizada em Pocket PC, ou seja, páginas WAP só que envolvendo o PHP como linguagem para acessar os dados de uma base MySQL.
Mas como eu iria dizer ao aplicativo PHP que eu teria que acessar a base do servidor x, y ou z?
Foi ai que eu criei um arquivo XML não só contendo informação da base de dados, mas também outros dados que seriam interessantes quando não houvesse conexão com a rede wireless.

ARQUIVOS XML

O XML trabalha muito parecido com o html em relação a criação, abertura e fechamento de Tags. A diferença é que todo XML é case sensitive. Outra característica parecida com o HTML, é que você pode definir o character code, segundo o padrão W3C.

Um exemplo de um arquivo XML:



Este é um exemplo simples de um arquivo XML, contendo como nódulo pai e seus filhos chamados nome.


CARREGANDO ARQUIVOS XML

Para interpretar um documento XML, utilizamos a função simplexml_load_file(). Esta função realiza a leitura de um documento XML, criando um objeto do tipo SimpleXmlElement. Caso o documento esteja mal formatado, com algum erro de case sensitive ou até mesmo não seja um documento XML, essa função retornará FALSE.

Vamos criar um documento PHP que lerá o arquivo XML do exemplo acima. Vamos chamar o arquivo XML de estados.XML.

< ?
//interpreta o documento XML
$xml = simplexml_load_file('estados.XML');

var_dum($xml);

?>

Obs.: A função var_dump() analisa o objeto resultante.

O resultado será o seguinte:

Object(SimpleXMLElement)#1 (4) {
["nome"]=> string(9) "SAO PAULO"
["nome"]=> string(14) "RIO DE JANEIRO"
["nome"]=> string(17) "RIO GRANDE DO SUL"
["nome"]=> string(4) "ACRE"
}


Você pode pegar os dados de um arquivo xml pelos índices de seus nodes. Exemplo:

< ? //interpreta o documento XML
$xml = simplexml_load_file('estados.XML');

echo "Estado: ' . $xml->estados->nome[0] . "\n";
echo "Estado: ' . $xml->estados->nome[1]. "\n";
echo "Estado: ' . $xml->estados->nome[2]. "\n";
echo "Estado: ' . $xml->estados->nome[3];
?>


Você também pode mudar o valor de um node, como no exemplo a seguir:

< ? //interpreta o documento XML
$xml = simplexml_load_file('estados.XML');

//Modificando o valor do primeiro estado e mostrando a seguir
$xml->estados-nome[0] = "MATO GROSSO DO SUL";
echo "Estado: ' . $xml->estados-nome[0];

?>


Você pode utilizar a função foreach para mostrar todos os subelementos nome do documento:

< ? //interpreta o documento XML
$xml = simplexml_load_file('estados.XML');

foreach($xml->estados->nome as $estado){
echo $estado . "\n";
}
?>


FUNÇÕES NATIVAS DO PHP5 PARA MANUSEIO DE ARQUIVOS XML

Existem algumas funções que auxiliam no uso do XML, como incluir novo node, Listar atributos, visualizacão de nodes filhos, gravar dados em um novo arquivo XML, e muitos outros.

Para visualizar e aprender essas funções, nada melhor que o bom e velho PHP.net (www.php.net) que na minha opinião, é o melhor manual/tutorial para linguagem de programação feito até hoje.
Segue abaixo algumas funções que sempre costumo usar:

asXML() - Retorna uma string XML formatada representando o objeto, bem como seus subelementos.
addChild() - Adiciona um novo elemento ao node especificado.
file_put_contents - Sobrepõe um arquivo XML com novos dados.

Qualquer dúvida, é só potar um comentário...
Abraços.

sexta-feira, 20 de fevereiro de 2009

Análise de Requisitos

E aew pessoal,
Eu resolvi escrever esse artigo devido a uma visita em um suposto novo cliente, depois de ele ter solicitado a criação de um sistema.

Grande parte das vezes que visitamos um cliente que necessita de um software de gestão para a empresa, a primeira coisa que escutamos é: "Eu quero pouca coisa", "É coisa rápida e fácil".
Escutamos isso porquê o cliente tem pouca noção para análisar um problema, então é aí que entra o analista de sistemas para levantar os requisitos de sistema.


INTRODUÇÃO

A análise de requisitos é uma das sub-áreas da engenharia de software, que a função é detectar e documentar problemas do cenário atual para que eles sejam implementados com qualidade e com o mínimo de manutenção possível.

Creio que cerca de 80% dos erros nos projetos são causados por defeitos inseridos durante a análise e requisitos, causando um custo maior de manutencão e de testes do sistema e, o pior são os erros descobertos pelos usuários. Atire a primeira pedra o programador que nunca escutou: "Está dando problema!", "Esta com bug!", "Não funciona!". Além disso, a pior coisa para uma empresa é a perda de oportunidades e de confiança com os clientes.

Para terminar a introdução, segundo a wikipedia, Análise de requisitos é: " O estudo das características que o sistema deverá ter para atender às necessidades e expectativas do cliente.
Cada funcionalidade demandada pelo cliente deve ser analisada para verificar os possíveis impactos no desenvolvimento das demais funcionalidades do sistema, e verificado em conjunto com a equipe de desenvolvimento se as necessidades tecnológicas para a sua implementação estão disponíveis."


ESTUDO DE VIABILIDADE

Você esta prestes a criar a documentação necessária e a implementar o novo sistema. Mas será que é realmente viável a criação do mesmo?

Uma forma de avaliar a viabilidade de um projeto é obter, através de interação com as partes interessadas a resposta às seguintes questões:
  • Será que o sistema contribui para os objetivos da organização? (POR PARTE DO CLIENTE)
  • Dadas as restrições tecnológicas, organizacionais (econômicas, políticas, ambientais, recursos disponíveis) e temporais associadas ao projeto, será que o sistema pode ser implementado? (POR PARTE DOS ANALISTA/DESENVOLVEDOR)
  • Caso haja necessidade de integração entre diferentes sistemas, será que esta é possível? (POR PARTE DOS ANALISTA/DESENVOLVEDOR)
Creio que a primeira questão é a que mais "pega" em um estudo de viabilidade. Caso a resposta seja negativa, com certeza você terá dores de cabeça caso resolva tocar o projeto, pois o cliente nuncá ficará satisfeito mesmo se tudo estiver funcionando.


PROCESSOS DA ENGENHARIA DE REQUISITOS

Você deve estar se perguntando: "E quais são os passos para o levantamento de requisitos?"
  1. Identificação do problema (Questionar os problemas e as necessidades que o cliente esta enfrentando).
  2. Análise e negociação (Saber como funciona cada processo e a regra de negócio é fundamental!).
  3. Especificação e documentação (Documentar por meios legíveis todos os processos que cada tarefa terá. É nesta fase que se dá a produção do documento de especificação de requisitos).
  4. Validação (Rever os 3 passos anteriores e demonstrar que o documento de requisitos produzido corresponde ao sistema que o cliente pretende receber).

Esses passos podem ser feitos de vários meios: Entrevistas, Questionários, Workshops ou qualquer outro meio de obter o máximo de informações dos usuários.

Não podemos começar a implementar um sistema pelo que achamos que deve ser feito, por isso o usuário "trabalha", passando todas as informações necessárias.

Como criar a documentação jogando todos os requisitos funcionais e todos os processos que cada requisito terá, explicarei em outro Post...caso eu ainda esteja vivo com esse carnaval.

Abraços e até +.

quinta-feira, 12 de fevereiro de 2009

InputQuery / Inputbox com campo estilo senha

Hoje eu precisei pedir uma senha para o usuário do sistema, só que eu não queria criar um form só para solicitar a senha, dai eu resolvi usar InputQuery.
Só que havia um problema, o usuário não pode visualizar a senha enquanto digita. Então como fazer com que o InputQuery fique com o passwordChar igual a #?

O delphi não possui um componente/função que faça isso. Então eu fui ao bendito google e achei a função/procedimento que queria no Blog do Adriano Santos http://delphitodelphi.blogspot.com que além de escrever para o blog pessoal, cria alguns artigos para a revista ClubeDelphi da devMedia www.devmedia.com.br.

Para a função, você precisa adicionar na Uses, as seguintes unidades: Types, Controls e Windows.

Segue abaixo a função:
function InputQuerySenha(const ACaption, APrompt: string; var Value: string):
Boolean;
var
Form: TForm;
Prompt: TLabel;
Edit: TEdit;
DialogUnits: TPoint;
ButtonTop, ButtonWidth, ButtonHeight: Integer;
function GetAveCharSize(Canvas: TCanvas): TPoint;
var
I: Integer;
Buffer: array[0..51] of Char;
begin
for I := 0 to 25 do
Buffer[I] := Chr(I + Ord('A'));
for I := 0 to 25 do
Buffer[I + 26] := Chr(I + Ord('a'));
GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result));
Result.X := Result.X div 52;
end;
procedure Saida(Sender: TObject);
begin
if TEdit(Sender).Text = '' then
begin
ShowMessage('Vazio');
TEdit(Sender).SetFocus;
end;
end;
begin
Result := False;
Form := TForm.Create(Application);
with Form do
try
Canvas.Font := Font;
DialogUnits := GetAveCharSize(Canvas);
BorderStyle := bsDialog;
Caption := ACaption;
ClientWidth := MulDiv(180, DialogUnits.X, 4);
Position := poScreenCenter;
Prompt := TLabel.Create(Form);
with Prompt do
begin
Parent := Form;
Caption := APrompt;
Left := MulDiv(8, DialogUnits.X, 4);
Top := MulDiv(8, DialogUnits.Y, 8);
Constraints.MaxWidth := MulDiv(164, DialogUnits.X, 4);
WordWrap := True;
end;
Edit := TEdit.Create(Form);
with Edit do
begin
{Usando a fonte Wingdings e a letra "ele" em minúsculo, simula-se as "bolinhas" no lugar
de asterísco da senha}
Font.Name := 'Wingdings';
PasswordChar := 'l';
Parent := Form;
Left := Prompt.Left;
Top := Prompt.Top + Prompt.Height + 5;
Width := MulDiv(164, DialogUnits.X, 4);
MaxLength := 255;
Text := Value;
SelectAll;
end;
ButtonTop := Edit.Top + Edit.Height + 15;
ButtonWidth := MulDiv(50, DialogUnits.X, 4);
ButtonHeight := MulDiv(14, DialogUnits.Y, 8);
with TButton.Create(Form) do
begin
Parent := Form;
Caption := 'Confirmar';
ModalResult := mrOk;
Default := True;
SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth,
ButtonHeight);
end;
with TButton.Create(Form) do
begin
Parent := Form;
Caption := 'Cancelar';
ModalResult := mrCancel;
Cancel := True;
SetBounds(MulDiv(92, DialogUnits.X, 4), Edit.Top + Edit.Height + 15,
ButtonWidth, ButtonHeight);
Form.ClientHeight := Top + Height + 13;
end;
if ShowModal = mrOk then
begin
Value := Edit.Text;
Result := True;
end;
finally
Form.Free;
end;
end;

Exemplo de uso:

procedure TForm1.Button1Click(Sender: TObject);
var
Texto : string;
begin
InputQuerySenha('Caption', 'Caption', Texto);
Edit1.Text := Texto;
end;

Abraços pessoal. T+

quinta-feira, 22 de janeiro de 2009

Threads - Conceito e exemplo em Delphi

Nesse post falarei a respeito de Threads no Delphi.
Threads são processos e segundo o dicionário, o verbo processar no termo computacional significa "tratar dados em computador a fim de obter informação sistematizada" ou "interpretar e executar instruções".
Toda vez que executamos um projeto no Delphi, o projeto aberto é uma thread na qual é o processo principal do seu sistema. Você pode estar pensando: "Mas para que eu preciso aprender sobre Threads?". Você já notou que toda vez que um trecho de código é executado no delphi, você só consegue mexer no seu sistema depois que tudo é executado. Não notou? Então faça o seguinte exemplo:

Crie um projeto VCL forms e arraste um button no seu formulário.
No Onclick de um botao, coloque o código abaixo, rode o programa e depois clique nele.
var
I: Integer;
begin
for I:=1 to 10000 do
begin

end;
end;

Notou que após que você clica no botao e enquanto o laço de repetição não foi finalizado, não é possível nem mover o seu formulário ou executar qualquer outra tarefa em seu aplicativo?
Isso acontece devido ao processo que esta rodando mas ainda não foi finalizado.
Mas e agora? Se eu quiser executar outra tarefa no meu aplicativo enquanto o laço de repetição ainda esta em loop?. É aqui que entra Threads de sistema!
Outro exemplo de Thread é o componente Timer do Delphi que enquanto você esta rodando seu aplicativo, você consegue fazer com que o timer atualize a hora em um label a cada segundo sem interferir nas outras execuções.


CRIANDO UMA CLASSE E TENDO COMO HERANÇA A CLASSE TTHREAD

Criaremos uma classe chamada TMinhaThread que extenderá a classe TThread que esta na unit Classes:

type
TMinhaThread = class(TThread)
private
procedure Execute; override;
end;

Na nossa classe criada, criamos uma procedure chamada Execute que deverá ser modificada(override/virtual) toda vez que herdamos a classe Tthread. Somos forçados a fazer isso pois a classe TThread possui o método Execute que é abstrato e segundo o conceito de Orienteção a objetos, toda classe que herda uma classe que possui métodos abstratos, deve implementar todos os métodos abstratos da mesma. Eu sei que você deve estar pensando: "E toda classe que possui métodos abstratos, deve ser abstrata.", mas orientação a objetos não é o foco do Post.

Pressione CTRL+SHIFT+C para o delphi criar a estrutura no método Execute.

procedure TMinhaThread.Execute;
var
I: Integer;
begin

try
for I:=0 to 10000 do
begin
Sleep(20);
end;
Except

end;
end;

Com a procedure já implementada, arraste outro button para o formulário e adicione o seguinte trecho de código:

var
//Cria a variavel minhaThread do tipo TMinhaThread
minhaThread: TMinhaThread;
begin
//Criação do objeto
minhaThread := TMinhaThread.Create(False);
minhaThread.FreeOnTerminate := true;
end;

O método create recebe um valor booleano que significa:
True - A Thread é iniciada porém ela é pausada ou seja, não executa o método Execute (imagine o componente Timer com a opção Enabled = false).
False - O método Execute é executado assim que a Thread é iniciada.

O método FreeOnTerminate, verifica se a Thread precisa ser liberada da memória assim que ela for finalizada. Com isso não precisamos dar um FreeAndNil.
Valor True para liberar da memória e False para permanecer armazenada.


Execute o botão e note que apesar do seu aplicativo estar em loop, você consegue movê-lo e até mesmo executar outras tarefas.

Outro exemplo onde podemos utilizar Threads é no download ou upload de múltiplos arquivos, pois com thread conseguimos fazer a transferência de vários arquivos ao mesmo tempo sem ser preciso esperarmos o término de cada um.


Todas as explicações que eu posto aqui no blog são de tarefas que pratico no dia-a-dia, mas caso algum leitor ache interessante eu postar algo de um determinado assunto, basta comentar em algum post ou me enviar um e-mail.

Blz pessoal?
See ya guys....

quarta-feira, 21 de janeiro de 2009

Votação de produtos com porcentagem e barra de progresso

E ai pessoal, tudo tranquilo?
Depois de mais ou menos 1 mes de ferias do blog, voltei aqui para postar mais uma implementação q fiz em um dos meus trabalhos.

No momento eu estou fazendo um site em PHP, onde há produtos e cada produto possui uma enquete com 5 opções:
1 - Péssimo produto
2 - Razoável
3 - Bom
4 - Muito bom
5 - Excelente

Eu não explicarei exatamente como fazer a enquete, ou seja, como incluir uma nova enquete ou como fazer com que a página receba os votos do usuário. Irei apenas enfatizar como pegar o total de votação e mostrar a porcentagem de cada opção e além disso, como mostrar o total da votação em uma barra de progresso horizontal.


TABELAS UTILIZADAS

Segue abaixo como estao as minhas tabelas na base de dados:

USUARIOS
-------------------
idusuario INT AUTOINCREMENT NOT NULL
nome VARCHAR(30) NOT NULL

PRODUTOS
-------------------
idproduto INT AUTOINCREMENT NOT NULL
nome VARCHAR(30) NOT NULL

VOTACOES_PRODUTOS
--------------------
idusuario INT
idproduto INT
data_votacao DATETIME
declaracao TINYINT (Campo que determina a opção do voto)

Bom, agora com nossas tabelas, irei mostrar a logica de como fazer a porcentagem de votos para cada opção.


PORCENTAGEM DE VOTOS POR OPÇÃO VOTADA


Para calcular a porcentagem de votos que uma opção teve, devemos fazer o seguinte calculo:
porcentagem é = quantidade total . (quantidade de votos/100)

Quantidade total = Número de registros da tabela votacoes_produtos.
Ex.: (SELECT COUNT(*) as qtde_total FROM votacoes_produtos)

Quantidade de votos = Número de votos que o produto obteve na determinada opção.
Ex.: (SELECT COUNT(*) as qtde_votos FROM votacoes_produtos WHERE idproduto = 3 and declaracao = 4)

ficaria assim em PHP:
$porcentagem = $qtde_total*($qtde_votos/100);
echo $porcentagem;

RECEBENDO A PORCENTAGEM DE TODAS AS OPÇÕES

Imagine a primeira opção (Péssimo produto) como 0% e a quinta opção (Excelente) como 100% da nossa barra de progresso.
Precisamos criar uma forma de preencher nossa barra de progresso pelas votações recebidas, tendo votos da primeira e última opção ou não.

Para fazer isso, faremos uma regra de três.
Vamos supor que 5 pessoas votaram, seus votos foram: 5, 3, 5, 1 e 2
A soma de todas as votações(opções), seria 16...correto?
O máximo de número de votos seria 5x5 = 25(100%)
Ai você faz aquela pergunta para obter a porcentagem: se para 25 pontos eu tenho 100%, quantos % eu obtive com 16 pontos?
Fácil!
25 = 100%
16 = x

x = (100*16)/25
x = 64%

Como diz o professor de inglês Arthur que aparece no youtube: IT'S EASY!!!


CRIANDO A BARRA DE PROGRESSO

Nossa barra de progresso será feita no esquema de Estrelas.
Faça download das seguintes imagens:




Para criar a barra de progresso, utilizaremos HTML puro.
Crie uma tabela com 100 pixels de largura, 0 de borda, cellpadding e cellspacing.
Dentro dessa nova tabela criada, insira outra tabela com 100% de largura, 0 de borda, cellpadding e cellspacing.

Na coluna(TD) da primeira tabela criada, insira o seguinte código CSS: style="background-image:url(estrela02.gif); background-repeat:no-repeat;"
Na coluna(TD) da segunda tabela criada, insira o seguinte código CSS:
style="background-image:url(estrela01.gif); background-repeat:no-repeat"

No width da segunda tabela criada, coloque o seguinte valor: width="< ? echo $x; ? >"
onde $x é o novo valor q obtemos com a regra de 3 que criamos acima.
Note que conforme a porcentagem, as estrelas coloridas sobrepõe as estrelas apagadas.

É isso galera..
Em caso de dúvidas, envie comentário q tentarei responder o mais rápido possível.
Até lá.