Arquivo da categoria: Linguagens de Programação

Tudo sobre linguagens de programação.

Montando Álbum de fotos em Php


Ola gente
sei que estou meio sumido mais estamos ai firme e forte e vou me organizar e assumir compromissos com os leitores
que sempre  dão  o bom ar da presença na coluna.
e toda semana dicas novas por aqui
Essa Máteria vai em especial ao “JAMAICA” sobre como montar um album de fotos em php

espero que a galera goste e claro com base nos comentarios podemos fazer a parte2 desse script

vamos a ação entao
espero que so os comentarios ajude vc a entende esse script


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt-BR" lang="pt-BR">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>album de fotos rapido em php </title>
<meta name="resource-type" content="document" />
<meta http-equiv="pragma" content="no-cache" />
<script type="text/javascript" src="highslide/highslide.js"></script>
<script type="text/javascript">
hs.graphicsDir = 'highslide/graphics/';
window.onload = function() {
hs.preloadImages(5);
}
</script>
<style type="text/css">
@import "teu.css";
</style>
</head>
<body>
<div class="controle2">
<?
$album="album";
/*nome da pasta do meu album de fotos :)*/
$tudo=count($total = glob("$album/{*.jpg}", GLOB_BRACE));
/*de uma olhada na minha materia lendo e excluindo pastas */
/*aqui eu conto o total de fotos dentro da pasta indicada e pegou as fotos jpg
*/
$a=0;
while($a < $tudo) {
/*traduzindo enquanto o total de img for menor que o total que esta na pasta  eu
dou um giro pegando
a outra imagem
como vc deve ter reparado quando imagem tem um titulo e alt vc poder criar
variavel
garantido assim uma acesibilidade para sua imagem
eu usei uma unica img no tamanho maior = 450 x 338
mais vc pode trabalhar com tamanho maiores
editar o seu css e usar os modelos que tem dentro da pasta
highslidegraphicsoutlines
*/
?>
<a href="<?=$total[$a]?>" class="highslide" onclick="return hs.expand(this,
{captionId: 'caption<?=$a?>'})">
<img src="<?=$total[$a]?>" alt="<?=$album?>"
title="<?=$album?>" height="75" width="100" /></a>
<div class='highslide-caption' id='caption<?=$a?>'>
<p>Um texto legal aqui para fotos ou deixar em branco mesmo </p>
<? $a++; ?>
</div>
<?
}
?>
<div id="mensagem">
<p>Ser vc tive tempo de uma olhada no arquivo highslide.js</p>
<p>vc podera mexer em quase tudo dentro do js</p>
<p> ate escolhe outros modelos para seu album editar a tradução e colocar
conforme seu desejo </p>
<p>Visite  o site do autor dessa biblioteca tem mais coisa  legal</p>
<p>http://vikjavev.no/highslide/</p>
<p>
</div>
</div>
</body>
</html>

Eu estou disponiblizado um exemplo que eu fiz num recente projeto , e claro que ninguem fique seduzindo pela  beleza do layuot mais avalie o efeito desse album
ver exemplo online

Agora a decisao e sua baixe o script e edite conforme seu desejo
um abraço a todos e comente sobre esse album
e nao esqueça sua sugestão de hoje pode ser sua materia de amanha

Um Abraço,
Henrique Guedes
Fonte: http://www.oficinadanet.com.br/artigo/462/montando_album_de_fotos_em_php___

Trocando itens de ListBoxes via JavaScript


Olá caro leitor! Neste tutorial você aprenderá de uma forma fácil e detalhada a trocar ítens entre ListBoxes através de um simples código JavaScript, uma das mais usadas ferramentas para programação Web/Client. Vamos então ver alguns conceitos básicos,para alguém que nunca utilizou essas ferramentas não ficar “boiando” no assunto 🙂 ….


I – Conceitos

1. ListBox
Um ListBox – ou caixa de listagem – nada mais é que a tag SELECT da linguagem HTML. Mas espera aí, a tag SELECT não é a que cria o ComboBox? Sim, em termos de código esses objetos são idênticos – não levando em conta o aspecto visual – com apenas um único diferencial: a propriedade size. Se essa propriedade tiver um valor maior que 1 então nossa tag SELECT será um ListBox, mas se ela tiver um valor igual a 1 ou for omitida teremos um ComboBox. A ListBox será o recipiente que nos permitirá manipular as informações que desejamos, as quais estarão contidas nas opções.

2. Opções
As opções serão as estruturas que armazenarão as informações que estaram contidas dentro do ListBox. Elas são criadas através da tag OPTION que será exemplificada mais a frente. Elas serão o alvo deste tutorial pois, nelas que estarão contidas as informações que serão aproveitadas.

3. JavaScript
A JavaScript é uma linguagem de scripts utilizada no cliente para alterar propriedades da página e de seus objetos e que cria até uma certa dinamicidade. Ela será a nossa ferramenta para manipular essas informações.
Bom, agora depois de todo esse blá blá blá vamos ao que realmente interessa:

II – Código
Para facilitar a compreensão, vou colocar como exemplo uma escola onde se deseja cadastrar os alunos em suas respectivas salas. Cada página desta, representará uma sala e teremos todos os alunos da escola em uma List e outra List vazia onde serão colocados os alunos que pertencerão a essa sala.
Vou colocar aqui o código completo para que você não tenha que ficar “caçando” linha a linha no tutorial caso queira utilizá-lo. As explicações vêm a seguir:

1. Este é o código HTML contendo as Lists e dois botões para podermos fazer as trocas:


<HTML>
<HEAD>
<TITLE>Exemplo de ListBox – Escola São João do JavaScript </TITLE>
</HEAD>
<BODY>
<FORM name=”form” action=”página_destino.htm” method=”post”>
<TABLE width=”80%” border=0>
<TR>
<TD width=35%><P align=”right”>Alunos<BR>
<SELECT name=”List1″ size=”5″ multiple style=”width: 100pt”>
<OPTION value=”Joãozinho”>Joãozinho</OPTION>
<OPTION value=”Pedrinho”>Pedrinho</OPTION>
<OPTION value=”Juquinha”>Juquinha</OPTION>
<OPTION value=”Mariazinha”>Mariazinha</OPTION>
</SELECT></P>
</TD>
<TD width=10%><P align=”center”>
<INPUT type=”button” name=”insere”value=”>>” OnClick=”TrocaList(document.form.List1,document.form.List2)”><BR>
<INPUT type=”button” name=”deleta” value=”<<” OnClick=”TrocaList(document.form.List2,document.form.List1)”><BR>
</TD></P>
<TD width=35%><P align=”left”>Classe<BR>
<SELECT name=”List2″ size =”5″ multiple style=”width: 100pt”></SELECT></P>
</TD>
</TR>
</TABLE><BR>

</FORM>

</BODY>
</HTML>

2. Esse é o código JavaScript que fará a transferência:

<SCRIPT language=JavaScript>
function TrocaList(ListOrigem,ListDestino)
{
var i;
for (i = 0; i < ListOrigem.options.length ; i++)
{
if (ListOrigem.options[i].selected == true)
{
var Op = document.createElement(“OPTION”);
Op.text = ListOrigem.options[i].text;
Op.value = ListOrigem.options[i].value;
ListDestino.options.add(Op);
ListOrigem.options.remove(i);
i–;
}
}
}
</SCRIPT>

Simples não é? Não? Então vamos ver passo a passo:

III – Passo a Passo
Nessa parte tentarei explicar do modo mais detalhado possível, sendo que é provável que muita coisa que estiver aqui você pode já estar careca de saber, mas pense em quem está começando a fazer páginas e tem apenas noções básicas de HTML.
Vamos começar pelo código HTML, que além de ser mais fácil de se entender é a base para compreendermos a utilidade do restante do código:

1. O imprescindível HTML

a) O Formulário
O formulário vai ser a tag onde estarão as ListBoxes e os botões que usaremos para trocar as opções entre os mesmos e também que direcionará a resposta do nosso HTML para outra página.

<FORM name=”form” action=”página_destino.htm” method=”post”>

Se você deseja passar as opções que selecionou para outra página, obrigatoriamente terá que usar um formulário para passar os parâmetros desejados para ela. Como a tabela foi usada apenas por um aspecto visual, não falaremos sobre ela.

b) A ListBox
Aí está a tão polêmica tag SELECT que neste caso está como uma ListBox e não como um ComboBox pois notem, a propriedade size possui valor 5, ou seja, este SELECT será uma ListBox com cinco linhas.

<SELECT name=”List1″ size=”5″ multiple style=”width: 100pt”></SELECT>

A propriedade multiple que está dentro da tag nos permite selecionar várias opções simultaneamente. Ela só será útil numa ListBox pois, como o size do ComboBox é 1, mesmo que colocássemos essa propriedade seria possível selecionar somente uma opção por vez.

c) As Opções
Como foi dito anteriormente, a OPTION armazena as informações que desejamos utilizar. Nela teremos dois tipos de informação: uma que será a que utilizaremos e outra que será a apresentada na página. Essa é uma das vantagens de uma ListBox – a informação apresentada não precisa ser necessariamente a que será utilizada.

<OPTION value=”Joãozinho”>Joãozinho</OPTION>

A informações que serão aproveitadas devem estar contidas na propriedade value. As aspas não são obrigatórias, a menos que a informação contenha espaços. As informações que serão apresentadas ao usuário devem estar entre as tag de abertura e a de fechamento. Estas não necessitam de aspas em qualquer hipótese, pois tudo que você escrever ali será visto na página, então se você digitar as aspas elas irão aparecer também.

Note que, nesse caso as duas informações são iguais, mas poderíamos colocar o número de matrícula na propriedade value, sendo assim o HTML mostraria o nome do aluno mas na verdade, estaria guardando o seu número de matricula.

Dica: se você deseja deixar uma opção selecionada por padrão, dentro da tag de abertura insira a palavra selected, que é uma propriedade da OPTION que indica se ela está selecionada ou não.

d) Os Botões
Os botões são objetos que usamos para acionar alguma mudança na página. Eles serão os nossos “mensageiros”, ou seja, eles que acionaram o código JS.

<INPUT type=”button” name=”insere” value=”>>” OnClick=”TrocaList(document.form.List1,document.form.List2)”>

Note que o nome será usado apenas como referência interna e a value conterá o texto que será mostrado no botão. O evento OnClick é acionado quando o botão é clicado. Ele chamará o nosso tão esperado código JS: a função TrocaList com os parâmetros document.form.List1 e document.form.List2 que serão explicados adiante.

Perceba também que no segundo botão a ordem dos parâmetros foi invertida. Quando estivermos na parte do JS falaremos o porque dessa troca.

e) o Script

<SCRIPT language=JavaScript></SCRIPT>

A tag SCRIPT indica o espaço onde se deve escrever o código do script. A propriedade language determina a linguagem de script que será utilizada – no nosso caso JavaScript.

2 – Finalmente, o JavaScript
Chegamos ao ponto crucial deste tutorial. Se você teve facilidade para entender o código acima, com certeza vai tirar de letra este aqui. Vamos lá então:

a) A Chamada da Função

Lembra do evento OnClick do botão, onde tinha a chamada da função:

TrocaList(document.form.List1,document.form.List2)

Então, começaremos por ele. TrocaList é o nome da função que iremos chamar, função esta que foi declarada dentro da tag SCRIPT desta página. O nome com o qual a função foi chamada deve ser exatamente o mesmo da que foi declarada.

document.form.List1 e document.form.List2 são os parâmetros passados à função que, neste caso, estão indicando as Lists que iremos utilizar. Como o JS não reconhece as Lists como objetos autônomos, eu tenho que especificar a quem elas pertencem a partir do que é comum a todos elementos desta página, a própria página. Como não podemos dar um nome a página como nos objetos, document será a palavra que usaremos para referir-se a ela , form é o nome do formulário e List1 e List2 são as ListBoxes que queremos manipular. Como o ponto(.) indica que o que vem após ele é uma propriedade, objeto ou método de quem vem antes, List1 e List2 são objetos que estão contidos no formulário form que por sua vez é um objeto da página HTML.

b) A Declaração da Função

function TrocaList(ListOrigem,ListDestino)

Essa é a declaração da função. A palavra function indica ao JS que iremos declarar uma função. TrocaList será o nome da nossa função, e ListOrigem e ListDestino as variáveis que armazenaram o valor dos parâmetros que enviamos quando chamamos ela lá nos botões. A primeira variável, ListOrigem, como o próprio nome sugere será a List que enviará as opções e a segunda, ListDestino, a que receberá estes. Lembra que a ordem dos parâmetros no segundo botão estava invertida?! Justamente por isso, o primeiro botão envia as informações da List com o nome dos alunos para a List da classe que está sendo montada, e o segundo faz exatamente o contrário.

Nota: Poderíamos enviar o nome das Lists diretamente para função sem utilizar parâmetros, mas neste caso teríamos que fazer uma função para cada botão e nosso código JS dobraria de tamanho.

c) As Variáveis

var i;
var Op = document.createElement(“OPTION”);

Essas serão as variáveis que iremos usar, além das que receberam os parâmetros. Declararemos a variável i como um contador apenas e a variável Op como um objeto da página através do método createElement() do objeto document, ou seja, a página.

d) Fazendo a Transferência

Na verdade, não é possivel enviar uma OPTION de uma List para outra. O que? Como não? Calma leitor,  este tutorial não foi feito a toa. Como para tudo existe uma solução o que faremos será copiar os dados da OPTION selecionada numa variável – pra isso a declaração da variável Op -, remove-la da List de origem e criar uma nova com os mesmos valores na List de destino. Vamos as linhas:

for (i = 0; i < ListOrigem.options.length ; i++)

Como na nossa tag SELECT especificamos a propriedade multiple que possibilita selecionar mais de uma OPTION ao mesmo tempo ,teremos que controlá-las dentro do nosso código. Para isso, usaremos o comando for que é uma estrutura de repetição, juntamente com o nosso contador i que controlará o índice que identifica cada opção, já que a propriedade ListOrigem.options é uma matrix que referência todas as opções da List. O primeiro parâmetro do for, i = 0 indica o valor inicial do contador, que no caso é zero.

O segundo parâmetro, i < ListOrigem.options.length, indica a condição de existência do for, ou seja, enquanto esta sentença for verdadeira o for será executado. Neste caso i deve ser menor que a quantidade de opções – options.length – que a List de origem contém. O terceiro parâmetro indica o que deve ocorrer cada vez que o for for executado, que no caso é o incremento do nosso contador – i++ é a mesma coisa que i = i + 1 – para que ele possa percorrer todas as opções da List.

Sendo assim a segunda vez que o for for executado o contador valerá 1, na terceira vez 2 e assim sucessivamente até que i alcance o valor de ListOrigem.options.length, o que determinara o fim da execução do comando. Tudo que será executado pelo for deve estar entre chaves.
Vamos agora, analisar o seu conteúdo:

if (ListOrigem.options[i].selected == true)

O comando if determina uma condição. Neste caso só será executado o que está no seu interior se a opção de índice i estiver selecionada na List.

var Op = document.createElement(“OPTION”);

Esta variável está sendo declarada aqui para que não precisemos limpar seu conteúdo toda vez que formos reutilizá-la. Então, quando o if é iniciado ela é criada com seu conteúdo vazio e quando ele é encerrado ela é apagada.

Op.text = ListOrigem.options[i].text;

Aqui atribuímos o valor do text – que representa a informação que será mostrada na página – da opção a ser copiada da List de origem para nossa variável.

Op.value = ListOrigem.options[i].value;

Da mesma forma, aqui atribuímos o valor da opção – que representa a informação que será utilizada – para a variável.

ListDestino.options.add(Op);

Aqui utilizaremos o método add() da matriz ListDestino.options, que adicionará uma nova opção com os valores da variável Op que foi passada como parâmetro. Note que dessa vez não utilizamos índice pois a opção será adicionada na matriz de opções e não em uma opção específica.

ListOrigem.options.remove(i);

E para terminar removeremos a opção, que já está armazenada na List de destino, da List de origem através de método remove() da matriz ListOrigem.options.

i–;

Agora imagine que o contador estivesse com o valor 3. Quando removermos esse item de índice 3 o JS vai passar este índice para a opção subseqüente, ou seja, a opção que tinha o índice 4 agora passa a ter índice 3. Logo, quando o for for executado novamente e incrementar a variável i, esse item será pulado criando assim um bug em nosso código. Por isso, no final de todo código ainda dentro if devemos decrementar o contador – i– é a mesma coisa que i = i -1 – , para que ele retorne a este mesmo índice e não pule esse item.

Nota: Cuidado para não colocar o decremento fora do if. Se isso acontecer você estará criando o que chamamos de loop eterno, o que poderá travar o seu navegador quando for executar a página.

IV – Observações
Pronto, você viu como é simples ? Agora para finalizar preciso passar a você algumas observações que podem ser vitais ao bom funcionamento deste código:

1. Case Sensitive
O JavaScript é uma linguagem case sensitive, ou seja, ela diferencia letras maiúsculas de minúsculas – então cuidado com elas.

2. Ponto-e-Vírgula
Esquecer um ponto-e-vírgula no JS é “caso de morte”: todas as sentenças que não utilizarem chaves devem conter um ponto-e-vírgula no final.

3. Chaves
As chaves delimitam estruturas de repetição ou de condição ou funções. Recomendo que ao abrir uma chave, imediatamente feche-a e vá digitando o código entre elas, assim não há perigo de você esquecer de fechá-las.

Espero que tenha sido proveitoso este código, que apesar de simples tem muita utilidade, principalmente para quem faz sites comerciais 🙂 …

Tabela de cores com Javascript


Em HTML construímos qualquer cor misturando o vermelho, verde e azul (RGB) nas proporções que desejarmos. Isto é um fato que deveria saber antes de ler este artigo. Explicamos com detalhes a construção de cores no artigo As cores e HTML. Será necessário que, aquele que não estiver familiarizado com este assunto, leia o artigo.

Além de como construir cores, o artigo As cores e HTML mostra também quais são as cores puras, que se vêem sem problemas em todas as profundidades de cor que possa ter a configuração dos computadores dos visitantes. Para a construção de cores puras misturamos as cores RGB sempre nestas quantidades 00, 33, 66, 99, CC, FF. Novamente, para quem não conhece isto deve ler a reportagem assinalada anteriormente.

O exemplo que pretendemos construir tem a ver com as cores puras em tyodas as definições. Trata-se de construir uma tabela em uma página web que contenha todos as cores puras, além do código RGB de cada cor. Esta tabela pode servir para selecionar uma cor que pretendemos utilizar em uma página web. Se nos limitarmos somente a utilizar as cores da tabela teremos a segurança que nossa paleta será respeitada em todos os casos.

Para gerar todos as cores puras vamos utilizar três arrays Javascript com os possíveis valores para cada uma das cores RGB. Portanto, teremos três arrays como os que podem ser vistos a seguir:

var r = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
var g = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
var b = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);

Para escrever a tabela na página web, faremos um percorrido a estes três arrays. Para isso, vamos utilizar loops aninhados, que são loops dentro de outros loops.

Vamos tratar de explicar porque necessitamos os loops aninhados; se fizermos as contas das cores que devemos ir gerando obteremos uma lista como a que segue:

#000000 #000033 #000066 #000099 #0000CC #0000FF #003300 #003333 #003366 #003399 #0033CC #0033FF #006600 #006633 #006666 #006699 #0066CC #0066FF…
Pode-se ver a conta completa aqui.

Então, vemos que no início os três valores de RGB valem 00 e como em sucessivas repetições se vai aumentando o valor de B (o valor atribuído ao azul) até chegarmos a FF. Para continuar, aumenta-se o valor de G e voltamos a realizar a conta com B. É como se contássemos e as unidades fossem os valores de RBG.

O caso é que realizamos a conta com o valor B, quando chegamos a FF aumentamos o valor de G e quando chegarmos a FF em G aumentaremos em um valor R. Assim, pode-se ver a estrutura em pseudocódigo como esta.

Contamos desde 00 até FF com o valor R{
Contamos desde 00 até FF com o valor G{
Contamos desde 00 até FF com o valor R{
Imprimimos o valor atual de RGB
}
}
}

Esta estrutura imprime todos as cores puras, e já é próxima a nossa solução, embora ainda não esteja escrita em Javascript e falte colocar todas as etiquetas HTML que necessitamos para mostrar uma tabela em uma página web.

Como não importa ir um pouco mais devagar contanto que todo o mundo entenda o problema, vamos escrever em Javascript este loop para que simplesmente liste as cores puras, sem introduzi-las ainda em uma tabela. Será interessante para ver um pouco melhor o funcionamento de loops aninhados.

//criamos os arrays
var r = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
var g = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
var b = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);

//fazemos o loop aninhado
for (i=0;i<r.length;i++) {
for (j=0;j<g.length;j++) {
for (k=0;k<b.length;k++) {
//creamos el color
var nuevoc = “#” + r[i] + g[j] + b[k];
//imprimimos a cor
document.write(novoc + “<br>”);
}
}
}

Para percorrer um array os loops se criam com um índice que servirá para acessar à posição atual do array. Os índices em arrays começam em 0, é por isso que nossos loops for contém uma iniciação a 0 da variável que vai servir de índice. Ademais o índice deve crescer de um em um até chegar à última posição do array, que se obtém acessando a sua propriedade length (que salva a longitude ou o número de elementos do array).

Colocando um loop dentro de outro poderemos realizar essa conta. O loop mais externo será o que menos vezes se executar, portanto com o loop exterior levaremos a conta de R. O loop do meio será para levar a conta de G e o mais interno (o que mais vezes se repetirá) para levar a conta de B, que é o valor que vai mudando constantemente.

Podemos vê-la em funcionamento neste link.

A tabela das cores completa

Para terminar, vamos ver o exemplo completo, com todas as linhas de código que incluem os textos HTML necessários para que a tabela saia convenientemente formatada e com as cores de fundo em cada uma das células iguais à cor atual.

Para isso, o primeiro que faremos é escrever o cabeçalho da tabela e a finalização da mesma, que ficam fora da estrutura de loops. Dentro dos loops realizaremos as sentenças para imprimir cada uma das filas e células da tabela.

Nossa tabela vai ter em cada fila um conjunto de cores, onde os valores RG não mudam e o valor B varia entre todos os possíveis. Na seguinte fila se incrementaria em um o valor G e faríamos outra vez a conta de valores B… assim até terminarmos com todos os valores R, G e B possíveis.

O código é o seguinte:

<table width=”80%”>
<script language=”javascript”>
var r = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
var g = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
var b = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);

for (i=0;i<r.length;i++){
for (j=0;j<g.length;j++) {
document.write(“<tr>”);
for (k=0;k<b.length;k++) {
var novoc = “#” + r[i] + g[j] + b[k];
document.write(“<td bgcolor=\”” + novoc + “\” align=center>”);
document.write(novoc);
document.write(“</td>”);
}
document.write(“</tr>”);
}
}
</script>
</table>

Vemos que antes de começar o loop mais interno, cria-se uma nova célula com <TR> e que quando se acaba, termina também a célula com </TR>. Ademais, dentro do loop mais interno se compõe primeiro a cor atual e logo se escreve uma célula com o atributo bgcolor atribuído a essa cor atual e dentro dela o texto da cor atual.

A tabela que nos gera este script pode ser vista aqui:

var r = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
var g = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
var b = new Array(“00″,”33″,”66″,”99″,”CC”,”FF”);
for (i=0;i<r.length;i++)
for (j=0;j<g.length;j++) {
document.write(“<tr>”);
for (k=0;k<b.length;k++) {
var nuevoc = “#” + r[i] + g[j] + b[k];
document.write(“<td bgcolor=\”” + nuevoc + “\” align=center>”);
document.write(nuevoc);
}
document.write(“</tr>”);
}

#000000 #000033 #000066 #000099 #0000CC #0000FF
#003300 #003333 #003366 #003399 #0033CC #0033FF
#006600 #006633 #006666 #006699 #0066CC #0066FF
#009900 #009933 #009966 #009999 #0099CC #0099FF
#00CC00 #00CC33 #00CC66 #00CC99 #00CCCC #00CCFF
#00FF00 #00FF33 #00FF66 #00FF99 #00FFCC #00FFFF
#330000 #330033 #330066 #330099 #3300CC #3300FF
#333300 #333333 #333366 #333399 #3333CC #3333FF
#336600 #336633 #336666 #336699 #3366CC #3366FF
#339900 #339933 #339966 #339999 #3399CC #3399FF
#33CC00 #33CC33 #33CC66 #33CC99 #33CCCC #33CCFF
#33FF00 #33FF33 #33FF66 #33FF99 #33FFCC #33FFFF
#660000 #660033 #660066 #660099 #6600CC #6600FF
#663300 #663333 #663366 #663399 #6633CC #6633FF
#666600 #666633 #666666 #666699 #6666CC #6666FF
#669900 #669933 #669966 #669999 #6699CC #6699FF
#66CC00 #66CC33 #66CC66 #66CC99 #66CCCC #66CCFF
#66FF00 #66FF33 #66FF66 #66FF99 #66FFCC #66FFFF
#990000 #990033 #990066 #990099 #9900CC #9900FF
#993300 #993333 #993366 #993399 #9933CC #9933FF
#996600 #996633 #996666 #996699 #9966CC #9966FF
#999900 #999933 #999966 #999999 #9999CC #9999FF
#99CC00 #99CC33 #99CC66 #99CC99 #99CCCC #99CCFF
#99FF00 #99FF33 #99FF66 #99FF99 #99FFCC #99FFFF
#CC0000 #CC0033 #CC0066 #CC0099 #CC00CC #CC00FF
#CC3300 #CC3333 #CC3366 #CC3399 #CC33CC #CC33FF
#CC6600 #CC6633 #CC6666 #CC6699 #CC66CC #CC66FF
#CC9900 #CC9933 #CC9966 #CC9999 #CC99CC #CC99FF
#CCCC00 #CCCC33 #CCCC66 #CCCC99 #CCCCCC #CCCCFF
#CCFF00 #CCFF33 #CCFF66 #CCFF99 #CCFFCC #CCFFFF
#FF0000 #FF0033 #FF0066 #FF0099 #FF00CC #FF00FF
#FF3300 #FF3333 #FF3366 #FF3399 #FF33CC #FF33FF
#FF6600 #FF6633 #FF6666 #FF6699 #FF66CC #FF66FF
#FF9900 #FF9933 #FF9966 #FF9999 #FF99CC #FF99FF
#FFCC00 #FFCC33 #FFCC66 #FFCC99 #FFCCCC #FFCCFF
#FFFF00 #FFFF33 #FFFF66 #FFFF99 #FFFFCC #FFFFFF

Podemos ver uma página web onde está somente esta tabela.

Administre sua Empresa – Parte II


Vamos falar sobre outros tipos de categorias. São as categorias de despesas. Lembrando que na semana passada iniciamos a série de matérias nas quais passarei algumas dicas de como se administrar uma empresa e como projetar uma aplicação em cima desta necessidade. Usando o melhor da instrução reduzida e o melhor em termos de componentes do VB.

Conforme citei: para que tenhamos um bom formulário de Contas a Pagar é necessário que o mesmo seja amarrado a um fornecedor, uma conta bancária para despesa e sobretudo categorias e subcategorias de despesa. Atualmente quanto menos você permitir o usuário digitar melhor. E isso não significa encher o seu projeto de Combos. Nem muito menos validar até a alma do programa. Lembrem-se da ilustrissíma relação Performance x Segurança.
Já pensaram se o caixa automático dos bancos perguntassem além da senha, o nome do pai e da mãe. A fila daquela joça iria dobrar. Imagine se você sobre um suave acidente e na hora de lhe internarem os caras querem saber o seu C.P.F., R.G, quantas meninas beijou no Verão e ou para as garotas, quantos rapazes foram para o diário. Sendo a sim, quanto maior a segurança, menor a performance.

>Na verdade quando resolvi planejar a idéia da Categorias e SubCategorias para Despesas usada oficialmente pela Microsoft no Money, foi pelo simples fato de que o usuário poderá cadastrar novas categorias e não precisará preencher um campo específico para a Descrição da conta a pagar. É um campo do tipo CHAR a menos na base e dois índices a mais: CDCATEGORIA, CDSUBCATEGORIA. Funcionando da seguinte maneira:

Na Categoria mulheres estão cadastradas todas as SubCategorias referentes aos gastos feitos com as mulheres. É claro, de uma forma hedionda e bem machista.

Você deve tá se perguntando: _ Legal, eu entendi, mas como codificar essa tranquerada toda no VB ?

Primeiramente o desenho da estrutura de dados é impressindível. Vincule a cada SubCategoria o código da Categoria. Veja só:

Fazer isso funcionar é bem fácil. Monte o formulário abaixo e codifique uma função espeficifa para carregar o Combo de Categorias. E em seguida, no evento Lost_Focus deste Combo (CMBCD_CATEGORIA). Carregue o outro Combo (CMBCD_SUBCATEGORIA). Aplicando um Filtro (WHERE) na montagem do RecordSet com o código da Categoria.

ModFunções

   'Módulo Básico com que conterá
   'as funções mais básicas usadas
   Option Explicit
   Dim cConn As ADODB.Connection
   Dim cStrConn As Variant
   Public cMensagem As String
   Public Const cTitulo = "FINANCEIRO"

   Public Function ConectaBanco() As Boolean

        ConectaBanco = False

        'Protegendo em memória na função
        'os objetos a serem usados
        Set cConn = New ADODB.Connection

        'Não se esqueça de direcionar o path com o banco 
        'para o diretório em que o mesmo estive em sua
        'máquina. Ou ultilize um arquivo .INI para informar
        'o path de conexão com a máquina.
         cStrConn = "Provider=Microsoft.Jet.OLEDB.4.0;"
         cStrConn = cStrConn & "Data Source=D:Imasters41ª Materiafinanceiro.mdb;"
         cStrConn = cStrConn & "Persist Security Info=False" 'Abrindo conexão    com a base

         cConn.Open cStrConn 
         Set cStrConn = Nothing

         ConectaBanco = True
End Function
   Public Function DesconectaBanco() As Boolean 
         DesconectaBanco = False

            cConn.Close
            Set cConn = Nothing

         DesconectaBanco = True

   End Function

   Public Function HabilitaCampo(NomeForm As Form, _
                                 NomeCampo As TextBox, _
                                 Habilita As Boolean)

         'Instrução Reduzida para Habilitar
         'ou desabilitar Campos

         NomeForm.NomeCampo.Enable = Habilita

   End Function
   Public Function DisparaComandos(cInstrucao As String) As Boolean

         'Esta função fará as conexões com o banco e dispará    os
         'comandos direto ao objeto de conexão
         'sem o uso de command's e ou recordset's

         DisparaComandos = False

         If ConectaBanco = True Then

            If IsNull(cInstrucao) = True Then
               cMensagem = MsgBox("ERRO INTERNO: O Banco 
Recebeu uma instrução    nula.", vbCritical, cTitulo)
               Exit Function
            End If

            cConn.Execute cInstrucao
          End If

          Call DesconectaBanco

          DisparaComandos = True

   End Function 
 

frmPCOMPRA

   Function CarregaCategoria() As Boolean

   CarregaCategoria = False
   On Error Resume Next

       Set cConn = New ADODB.Connection
       Set RS = New ADODB.Recordset

       If ConectaBanco = True Then

          cSQL = " SELECT CATEGORIASUB.CD_CATEGORIA,"
          cSQL = cSQL & " CATEGORIASUB.DS_CATEGORIA"
          cSQL = cSQL & " FROM CATEGORIASUB"

          Set RS = cConn.Execute(cSQL)
          If Err.Number <> 0 Then
             cMensagem = MsgBox("ERRO INTERNO: Não foi possível carregar as 
Categorias", vbCritical & " " & Err.Description, cTitulo)
             Exit Function
          End If

          While Not RS.EOF
             cmbcd_categoria.AddItem RS("CD_CATEGORIA") & " " & RS("DS_CATEGORIA")
             cmbcd_categoria.Refresh
             RS.MoveNext
          Wend

       End If

        Call DesconectaBanco

   CarregaCategoria = True
   End Function
Function CarregaSubCategoria() As Boolean

   CarregaSubCategoria = False
   On Error Resume Next

   Set cConn = New ADODB.Connection
   Set RS = New ADODB.Recordset

   If ConectaBanco = True Then

      cSQL = " SELECT CATEGORIASUB.CD_SUBCATEGORIA,"
      cSQL = cSQL & " CATEGORIASUB.DS_SUBCATEGORIA"
      cSQL = cSQL & " FROM CATEGORIASUB"
      cSQL = cSQL & " WHERE CATEGORIASUB.CD_CATEGORIAPAI = " 
& cmbcd_categoria.Text    & ""

      Set RS = cConn.Execute(cSQL)
      If Err.Number <> 0 Then
         cMensagem = MsgBox("ERRO INTERNO: Não foi possível 
carregar as Categorias", vbCritical & " " & Err.Description, cTitulo)
         Exit Function
      End If

      While Not RS.EOF
         cmbcd_subcategoria.AddItem RS("CD_SUBCATEGORIA") & " "    
& RS("DS_SUBCATEGORIA")
         cmbcd_subcategoria.Refresh
         RS.MoveNext
      Wend

   End If

   Call DesconectaBanco

   CarregaSubCategoria = True

End Function

Agora não se esqueça de declarar as variáveis globais e fazer a chamada da Function CarregaCategoria( ) ao carregar o formulário:

   'Exigindo que as variáveis sejam
   'declaradas e no código
   Option Explicit
   Dim cSQL As Variant
   Dim RS As ADODB.Recordset
   Dim cNovo As Boolean
Private Sub Form_Load()
   If CarregaCategoria = False Then
      cMensagem = MsgBox("Não foi possível carregar CATEGORIAS.", 
vbCritical & " " & Err.Description, cTitulo)
      Exit Sub
   End If
End Sub

Um outro assunto que quero abordar é a questão das Validações. Nem sempre encher o Form de eventos Validate é uma boa opção. Quanto mais você prende o usuário. Mais você o irrita.

Adote na programação Cliente/Servidor a mesma estética do projeto WEB. Valide tudo o que você tem que validar quando o usuário enviar os dados ao banco. O que chamamos na WEB de: “Dar o Submit”. E isso não é boiolagem !!!

Para seguir esta estética criei uma única função chamada de VALIDACAMPOS( ). Nela validarei tudo o que preciso à acionando no instante em que o feinho do usuário gravar ou atualizar algum dado. Veja só:

Function ValidaCampos() As Boolean

   ValidaCampos = False

   Dim cData As Date

   If cmbcd_categoria.Text = "(Nenhuma Categoria)" Then
      cMensagem = MsgBox("Categoria de Despesa não informada.", vbCritical, cTitulo)
      Exit Function
   End If

   If cmbcd_subcategoria.Text = "(Nenhuma SubCategoria)" Then
      cMensagem = MsgBox("SubCategoria de Desepasa não informada.", vbCritical, cTitulo)
      Exit Function
   End If

   cData = txtdt_emissao.Text
   If IsNull(cData) = True Then
      cMensagem = MsgBox("Data de Emissão não informada.", vbCritical, cTitulo)
      Exit Function
   End If

   cData = txtdt_vencimento.Text
   If IsNull(cData) = True Then
      cMensagem = MsgBox("Data de Vencimento não informada.", vbCritical, cTitulo)
      Exit Function
   End If

   cData = txtdt_pagamento.Text
   If IsNull(cData) = True Then
       txtdt_pagamento.Text = cData
       Exit Function
   End If

   If cmbds_formapg.Text = (Nenhum) Then
      cMensagem = MsgBox("Forma de Pagamento não informada.", vbCritical, cTitulo)
      Exit Function
   End If

   If txtds_juros.Text = vbNullString Then
      txtds_juros.Text = "0"
   End If

   If txtds_multa.Text = vbNullString Then
      txtds_multa.Text = ""
   End If

   If txtcd_fornecedor.Text = vbNullString Then
      cMensagem = MsgBox("Fornecedor não informado.", vbCritical, cTitulo)
      Exit Function
   End If

   If txtcd_contamemo.Text = vbNullString Then
      cMensagem = MsgBox("ContaMemo não informada.", vbCritical, cTitulo)
      Exit Function
   End If

   'Cheque
   If cmbds_formapg.ListIndex = 1 Or _
      txtcd_cheque.Text = vbNullString Then
      cMensagem = MsgBox("Pagamento em Cheque com 
número do cheque não informado.", vbCritical, cTitulo)
      Exit Function
   End If

   If txtvl_conta.Text = vbNullString Then
      cMensagem = MsgBox("Valor não informado.", vbCritical, cTitulo)
      Exit Function
   End If

   If txtvl_contapago.Text = vbNullString Then
      txtvl_contapago.Text = txtvl_conta.Text
   End If

   If txtds_obs.Text = vbNullString Then
      txtds_obs.Text = "Nenhum"
   End If

   ValidaCampos = True

   End Function




Um último assunto a ser abordado no Formulário de Contas a Pagar é a questão do Button Hit.

Trata-se de um componente construído, para vinculação de Chaves Estrangeiras. Ao invés montar um combo com todos os fornecedores cadastrados. O que com um tempo poderá levar a um Combo enorme com mais de 999 registros e conseguentemente o seu combo deixaria de funcionar ou o seu formulário demoraria uma década para carregar os dados.

Com o Button Hit o mentecapto do usuário digita o código do fornecedor ou da conta memo e o sistema pesquisa e exibe a descrição no campo ao lado. Caso não encontre, exibirá que o registro não foi encontrado. Daí se o usuário não souber o código, basta clicar no botão e chamar o cadastro de fornecedores por exemplo, para fazer a pesquisa.

Segue o código para que o Button Hit funcione. Se caso queira maiores detalhes, consulte a matéria sobre Button Hit.

Function ButtonHit(nCodigo As Integer, _
                   cTabela As String) As Boolean

   ButtonHit = False
   On Error Resume Next

   If ConectaBanco = True Then

   If IsNull(nCodigo) = True Then
      cMensagem = MsgBox("Código não Informado.", vbCritical, cTitulo)
      Exit Function
   End If

   If IsNull(cTabela) = True Then
      cMensagem = MsgBox("Tabela não encontrada.", vbCritical, cTitulo)
      Exit Function
   End If

   If Trim(cTabela) = "FORNECEDOR" Then
      cSQL = " SELECT FORNECEDOR.CD_FORNECEDOR,"
      cSQL = cSQL & " FORNECEDOR.NM_FANTASIA"
      cSQL = cSQL & " FROM FORNECEDOR"
      cSQL = cSQL & " WHERE FORNECEDOR.CD_FORNECEDOR = " & nCodigo    & ""
   Else
      cSQL = " SELECT CONTAMEMO.CD_CONTAMEMO,"
      cSQL = cSQL & " CONTAMEMO.NM_TITULAR"
      cSQL = cSQL & " FROM CONTAMEMO"
      cSQL = cSQL & " WHERE CONTAMEMO.CD_CONTAMEMO = " & nCodigo    & ""
   End If

   Set RS = cConn.Execute(cSQL)
   If Err.Number <> 0 Then
         cMensagem = MsgBox("Não foi possível carregar os dados."    _
                            , vbCritical & " " & Err.Description, cTitulo)
         Exit Function
   End If

   If IsNull(RS) = True Then
      If Trim(cTabela) = "FORNECEDOR" Then
         txtcd_fornecedor.Text = ""
         txtnm_fantasia.Text = "Fornecedor não encontrado"
         Exit Function
      Else
         txtcd_contamemo.Text = ""
         txtno_contamemo.Text = "Conta Memo não cadastrada"
         Exit Function
      End If
    End If

   If Trim(cTabela) = "FORNECEDOR" Then
      txtcd_fornecedor.Text = RS("CD_FORNECEDOR")
      txtnm_fantasia.Text = RS("NM_FANTASIA")
      Exit Function
   Else
      txtcd_contamemo.Text = RS("CD_CONTAMEMO")
      txtno_contamemo.Text = RS("NM_TITULAR")
      Exit Function
   End If

   Call DesconectaBanco
   
   End If

   ButtonHit = True

End Function

Por fim, o restante do código. Note a única rotina para Salvar e Atualizar dados. As rotinas para Exclusão e movimentação dos dados no formulário fica prá semana que vem.

Private Sub cmdContaMemo_Click()
   frmCONTAMEMO.Show
End Sub

Private Sub cmdFornecedor_Click()
   frmFORNECEDORES.Show
End Sub

Private Sub cmdNova_Click()
   cNovo = True
End Sub

Private Sub cmdSair_Click()
   End
End Sub

Private Sub cmdSalvar_Click()
   If ValidaCampos = False Then
      Exit Sub
   End If

   If cNovo = True Then
      cSQL = " INSERT INTO PCOMPRA"
      cSQL = cSQL & " (PCOMPRA.CD_CATEGORIA,"
      cSQL = cSQL & " PCOMPRA.CD_SUBCATEGORIA,"
      cSQL = cSQL & " PCOMPRA.CD_FORNECEDOR,"
      cSQL = cSQL & " PCOMPRA.CD_CONTAMEMO,"
      cSQL = cSQL & " PCOMPRA.DT_PAGAMENTO,"
      cSQL = cSQL & " PCOMPRA.DT_VENCIMENTO,"
      cSQL = cSQL & " PCOMPRA.DT_EMISSAO,"
      cSQL = cSQL & " PCOMPRA.DS_OBS,"
      cSQL = cSQL & " PCOMPRA.DS_FORMAPG,"
      cSQL = cSQL & " PCOMPRA.CD_CHEQUE,"
      cSQL = cSQL & " PCOMPRA.VL_CONTA,"
      cSQL = cSQL & " PCOMPRA.VL_CONTAPAGO,"
      cSQL = cSQL & " PCOMPRA.DS_JUROS,"
      cSQL = cSQL & " PCOMPRA.DS_MULTA)"
      cSQL = cSQL & " VALUES(" & cmbcd_categoria.Text & ","
      cSQL = cSQL & " " & cmbcd_subcategoria.Text & ","
      cSQL = cSQL & " " & txtcd_contamemo.Text & ","
      cSQL = cSQL & " '" & txtdt_pagamento.Text & "',"
      cSQL = cSQL & " '" & txtdt_vencimento.Text & "',"
      cSQL = cSQL & " '" & txtdt_emissao.Text & "',"
      cSQL = cSQL & " '" & txtds_obs.Text & "',"
      cSQL = cSQL & " '" & cmbds_formapg.Text & "',"
      cSQL = cSQL & " " & txtcd_cheque.Text & ","
      cSQL = cSQL & " " & txtvl_conta.Text & ","
      cSQL = cSQL & " " & txtvl_contapago.Text & ","
      cSQL = cSQL & " " & txtds_juros.Text & ","
      cSQL = cSQL & " " & txtds_multa.Text & ")"
      cMensagem = "Dados Gravados com Sucesso."
   Else
      cSQL = " UPDATE PCOMPRA SET"
      cSQL = cSQL & " PCOMPRA.CD_CATEGORIA = " & cmbcd_categoria.Text    & ","
      cSQL = cSQL & " PCOMPRA.CD_SUBCATEGORIA = " & cmbcd_subcategoria.Text    & ","
      cSQL = cSQL & " PCOMPRA.CD_FORNECEDOR = " & txtcd_fornecedor.Text    & ","
      cSQL = cSQL & " PCOMPRA.CD_CONTAMEMO = " & txtcd_contamemo.Text    & ","
      cSQL = cSQL & " PCOMPRA.DT_PAGAMENTO = '" & txtdt_pagamento.Text    & "',"
      cSQL = cSQL & " PCOMPRA.DT_VENCIMENTO = '" & txtdt_vencimento.Text    & "',"
      cSQL = cSQL & " PCOMPRA.DT_EMISSAO = '" & txtdt_emissao.Text    & ","
      cSQL = cSQL & " PCOMPRA.DS_OBS = '" & txtds_obs.Text &    "',"
      cSQL = cSQL & " PCOMPRA.DS_FORMAPG = '" & cmbds_formapg.Text    & "',"
      cSQL = cSQL & " PCOMPRA.CD_CHEQUE = " & txtcd_cheque.Text    & ","
      cSQL = cSQL & " PCOMPRA.VL_CONTA = " & txtvl_conta.Text &    ","
      cSQL = cSQL & " PCOMPRA.VL_CONTAPAGO = " & txtvl_contapago.Text    & ","
      cSQL = cSQL & " PCOMPRA.DS_JUROS = " & txtds_juros.Text &    ","
      cSQL = cSQL & " PCOMPRA.DS_MULTA = " & txtds_multa.Text &    ""
      cSQL = cSQL & " WHERE PCOMPRA.CD_PCOMPRA = " & txtcd_conta.Text    & ""
      cMensagem = "Dados Atuallizados com Sucesso."
   End if

     If DisparaComandos(cSQL) = True Then
        cMensagem = MsgBox(cMensagem, vbInformation, cTitulo)
     Else
        cMensagem = MsgBox("ERRO INTERNO: Não foi possível executar    
a operação" & " " & Err.Description, vbCritical,    cTitulo)
        Exit Sub
      End If
   End If

End Sub
 

Agora parem tudo !!! Largem o copo de leite, desliguem a TV, tranquem as portas . . .

Quase todo iniciante em VB tem dúvidas na hora de aplicar um filtro e gerar uma SPREAD, um GRID em cima destes dados filtrados. Exemplo: Selecionar todas as contas a pagar em um determinado período de vencimento. Observe:

frmGRIDPCOMPRA

   Option Explicit
   Dim cSQL As Variant
   Dim cMensagem As String
   Dim RS As New ADODB.Recordset

Private Sub Form_Load()
   If CarregaGrid = False Then
      cMensagem = MsgBox("ERRO INTERNO: Não foi possível carregar os dados.", 
vbCritical & " " & Err.Description, cTitulo)
      Exit Sub
   End If
End Sub

Function CarregaGrid() As Boolean
   CarregaGrid = False

   Set cConn = New ADODB.Connection
   Set RS = New ADODB.Recordset
   Dim cDataInicial As Date
   Dim cDataFinal As Date

   cDataIncial = InputBox("Digite a Data Inicial", cTitulo, cDataInicial)
   cDataFinal = InputBox("Digite a Data Final", cTitulo, cDataFinal)
   cSQL = " SELECT PCOMPRA.CD_PCOMPRA ""Código"""
   cSQL = cSQL & " PCOMPRA.CD_CATEGORIA ""Categoria"""
   cSQL = cSQL & " PCOMPRA.CD_SUBCATEGORIA ""SubaCategoria"""
   cSQL = cSQL & " PCOMPRA.VL_CONTA ""Valor"""
   cSQL = cSQL & " PCOMPRA.DT_VENCIMENTO ""Vencimento"""
   cSQL = cSQL & " WHERE PCOMPRA.DT_VENCIMENTO >= '" & Format(cDataInicial,
    "dd/mm/yyyy") & "',"
   cSQL = cSQL & " AND PCOMPRA.DT_VENCIMENTO <= '" & Format(cDataFinal,
    "dd/mm/yyyy") & ""
  Set RS = cConn.Execute(cSQL)

   Set grdPCONTA.DataSource = RS

   CarregaGrid = True

End Function

>O segredo está em deixar o formulário solto e gerar uma instrução SQL passando como parâmetros as datas imputadas e em seguida carregando um objeto Recordset e passando o mesmo como propriedade DataSource para o GRID. Fazendo isso, o seu Grid, será carregado em tempo de execução com os dados filtrados. E quantas e quantas vezes você disparar esta função, o seu Grid será atualizado.

Legenda do código:

Comentários
Destaque
Códigos

Finalmente concluimos o Form de Contas a Pagar e na semana que vem. Eu volto com os formulários restantes.

Abraços a todos!

Administre sua Empresa – Parte I


Tenho juntado um punhado de dúvidas de diversos leitores ao longo de algum tempo; dúvidas com GRID, SPREAD, em suma; Todas estão relacionadas com o grupo de Componentes do Visual Basic.

Afinal, é indispensável para o bom programador VB, saber carregar um SPREAD, um MSFLEX GRID, um DBGRID e até mesmo uma PROGRESS BAR. E o melhor, de forma higiência. Criando funções específicas e separadas.

Juntei este ao qual chamarei de catalógo de dúvidas e resolvi destinar o meu espaço no Imasters para comentar sobre o uso dos componentes mais sensacionais do Front End Visual Basic, em cima de alguma lógica plausível e bem postada.

Acompanhando uma série de estatíticas sobre a administração das empresas nacionais, sofri uma catalepsia momentânea !

O resultado me assustou tanto, foi pior do que tomar um fora de uma baranga em festa de formatura.
É justo, mas 90% dos microempresários brasileiros não sabem realmente quanto ganham e quanto gastam. Vou ainda mais longe, pois 88% das microempresas paulistas não possuem um Prolabore estimado. Têm o capital dos sócios administrado concomitantemente em paralelo à receita da empresa. Isso é como você montar uma barraquinha de Hot Dog e administrar os seus gastos pessoais em cima da renda bruta obtida com as vendas do seu negócio.

E não é necessário ser pós graduado em Administração de Empresas para saber que o correto é: estimar o capital bruto, retirar a despesa líquida ou o caixa para rêpor a mercadoria, no caso da barraquinha de Hot Dog. E por fim, a sobra é aplicada a um fundo de caixa e o restante é o que chamamos de Prolabore. A renda que deve ser destinada aos respectivos sócios e submetida a um processo semelhante.

O problema é que nem tudo mundo detém essa forma de administrar como uma regra básica, como uma lei!

É é ai que mora o perigo. E onde morre esta série de colunas; pois tentarei ao máximo simplificar resumindo todo o processo de Contas a Pagar/Contas a Receber e Livro Caixa. Em um único projeto. Usando em matéria de componentes, o que o Visual Basic tem de melhor.

Meu amigo, antes que você saia como um pedreiro codificando o que vê pela frente.
Faremos um breve estudo e em cima deste construiremos a base de dados.
Parte por parte. Nada de construir a base toda e depois ir desenvolvendo os formulários no decorrer das outras matérias.

Tentarei ao máximo adicionar um fechamento a cada coluna.

1.1 Contas a Pagar

Para que se obtenha sucesso no ato de fazer um fechamento de gastos mensal e tirar o seu Prolabore.
Ter todas as contas a pagar em dia é fundamental. E mais fundamental ainda é construir um projeto que atenda as espectativas financeiras e proceda uma amarração contábil eficiente.
Sendo assim, para o formulário de Contas a Pagar funcione corretamente vincularemos o mesmo a três chaves estrangeiras:
Fornecedores, Contas Memo (Contas Bancárias) e Categorias/Sub Categorias de Despesa.

Já com a questão das CONSTRAINTS após a criação das tabelas. É bem simples!
Todos os relacionamentos deste pequeno módulo, estão concentrados da tabela PCOMPRA. Afinal, uma conta a pagar provém de um Fornecedor, é paga a partir de uma conta bancária e possui uma Categoria / Sub Categoria para despesa, exemplo Categoria – Despesas Domésticas, Sub Categoria – Conta de Luz, assim como o Microsoft Money.
Foi uma idéia oficializada neste software e que eu particularmente adorei.

O Relacionamento Categoria com SubCategoria, ocorrerá numa mesma tabela; de forma sintética e analítica.
E com essa base devidamente preenchida você já terá um controle simples das suas despesas podendo até fazer um fechamento mensal de gastos.
Mas é claro, vamos dar uma cara a essa lógica. Usando o nosso bom e velho Visual Basic, portando algumas técnicas de programação modernas, generalizando o código em Funções Globais ao invés de ficar copiando e colando código.

Dentre as funções genéricas, separei algumas neste módulo:

ModFunções

 'Módulo Básico com que conterá
 'as funções mais básicas usadas
 Option Explicit
 Dim cConn As ADODB.Connection
 Dim cStrConn As Variant
 Public cMensagem As String
 Public Const cTitulo = "FINANCEIRO"

 Public Function ConectaBanco() As  Boolean

 	ConectaBanco = False

 	'Protegendo em memória na função
 	'os objetos a serem usados
 	Set cConn = New ADODB.Connection

    'Não se esqueça de direcionar o path com o banco	
    'para o diretório em que o mesmo estive em sua
    'máquina. Ou ultilize um arquivo .INI para informar
    'o path de conexão com a máquina.
    cStrConn = "Provider=Microsoft.Jet.OLEDB.4.0;"
 	cStrConn = cStrConn & "Data Source=D:Imasters40ª Materiafinanceiro.mdb;"
 	cStrConn = cStrConn & "Persist Security Info=False" 'Abrindo conexão  com a base

    cConn.Open cStrConn 
    Set cStrConn = Nothing

    ConectaBanco = True

 End Function

 Public Function DesconectaBanco() As Boolean 

      DesconectaBanco  = False

      cConn.Close
      Set cConn = Nothing

      DesconectaBanco = True

 End Function

 Public Function HabilitaCampo(NomeForm As Form, _
                               NomeCampo As TextBox, _
                               Habilita As Boolean)

      'Instrução Reduzida para Habilitar
      'ou desabilitar Campos

       NomeForm.NomeCampo.Enable = Habilita

  End Function

 Public Function DisparaComandos(cInstrucao As String) As Boolean

      'Esta função fará as conexões com o banco e dispará  os
      'comandos direto ao objeto de conexão
      'sem o uso de command's e ou recordset's

      DisparaComandos = False

      If ConectaBanco = True Then

        If IsNull(cInstrucao) = True Then
          cMensagem = MsgBox("ERRO INTERNO: O Banco 
Recebeu uma instrução  nula.", vbCritical, cTitulo)
          Exit Function
        End If

        cConn.Execute cInstrucao

      End If

      Call DesconectaBanco

      DisparaComandos = True

 End Function

Notem que generalizei ao máximo. Tudo o que for usado em um ou mais formulários recomenda-se aplicar em funções globais com retorno Booleano ou seja, sempre vamos ter a certeza de que aquela função foi executada com sucesso.

frmContaMemo

Este é o cadastro simples de contas bancárias, que mandará um código Chave Estrangeira para o formulário frmPCompra.
Este será codificado passo a passo na semana que vem. Notem o encaixe dos componentes:

Atualmente ando abolindo o uso do DataControl para cordenação de registros em um Cadastro.

Seu método de acesso ao banco é arcaíco e mau estruturado. Seus procedimentos são meio desengonçados.
Ele protege além do objeto de conexão, outro objeto em memória de forma preemptiva.
Imagine um passageiro no ônibus sem o número da passagem.

O ideal na hora de programar qualquer tipo de cadastro, é deixar o formulário o mais solto possível.
Fazendo as rotinas de alteração/inclusão e exclusão via instrução SQL direto no objeto de conexão; sem a necessidade de
um ponteiro recordset.Que a propósito só deve ser aberto, quando os botões de navegação forem acionados.
No caso do exemplo da figura abaixo são os botões Próximo e Anterior.

Não se esqueça ainda de aplicar validações rigorosas e de preferência na hora de disparar as rotinas dentro do banco,
como uma página em ASP quando faz o Submit. Note na figura que o Combo com o Nome do Banco é carregado em
tempo de execução. Não há nenhuma tabela de cadastros de bancos na nossa base de dados.
Talvez até houvesse a necessidade em sistemas de escrita contábil. Então todos sabemos que existem menos de 20
bancos economicamente participantes em nosso país. Por que não carregar em tempo de execução o Combo.
E se caso o meliante do usuário desejar optar por um que não tenha sido carregado.
Basta clicar no botão ao lado e incluir um novo banco ao cadastro, naquela execução.
Pois não há o mínimo interesse em aumentar o volume de dados do Combo.

frmFornecedores

Já neste Form. A auto numeração foi deixada por conta do banco. É só será exibida no quando as rotinas de navegação entre os
registros for disparada. Neste formulário foi codificado as rotinas essenciais e não se esqueça de inserir a mascára no campo
referente a Data de Entrega. Observe:

Clique  aqui para abrir a janela pop up com o código

frmCATEGORIASUB

Com este aqui, coloque a mão na massa. E obtenha assim uma idéia básica de como iniciar um simples plano de despesas para
administrar a sua microempresa. É claro que empresas como a Votorantim,
possuem um plano de contas muito mas muito mais complexo. Qualquer dúvida, eu tô na área . . .

Legenda do código:

destaque
comentários
códigos

Na semana que vem. Volto com a continuação enquanto vocês se recuperam dos estragos causados pelo Carnaval. Ainda por fim, preciso comunicar-lhes sobre os problemas que estive com minha conta de email do Imasters e acabei por não receber nenhum email enviado no período de 26/02/2003 a 05/03/2003. Porém quero comunicar-lhes que já está tudo certo e o meu email continua o mesmo: fernando.andrade@imasters.com.br.

Abraços a todos. Beijos para as meninas. E quando chegar o final de semana:

Esse negócio de se trajar de mulher no Carnaval e sobretudo afirmar que isso é só por que é Carnaval. Não é digno. Eu particularmente acho que isso é uma perobagem adquirida e um processo de encapsulamento que mais cedo ou mais tarde poderá expandir-se e lhe tornar uma mulher presa no corpo de um homem.

Atualizando listas dinamicamente sem refresh


Vou tratar de um assunto que vejo direto em fóruns de discussão sobre ASP. Como atualizar dinamicamente campos do tipo select, sem precisar dar refresh na página? Por exemplo, tenho 2 boxes, um com marcas de carros, e o outro com os carros, e gostaria de que quando eu mudasse a marca do carro, a caixa com os nome dos carros alterasse sem ter que dar refresh. Isso é possível?

Bom, apenas com ASP isso é impossível! ASP é uma tecnologia “server-side”, ou seja, ela só roda no servidor. Depois do momento em que todo o código é enviado para o browser do cliente, ele perde todo o controle da página. Ele não sabe se você alterou algum textbox, ou mudou o item do select. O único modo de fazer o ASP saber o que aconteceu é postando novamente a página.

Para resolver isso, podemos usar uma pequena “gambiarra”, mesclando ASP com JavaScript. Nós vamos fazer com que o ASP escreva um código JavaScript que faça essa atualização!

Como eu dei o exemplo dos carros, vamos utilizá-lo pelo resto do artigo. Vamos criar um arquivo no Access, de nome carros.mdb, com as duas tabelas abaixo:

Marcas

Carros

ID – AutoNumeração
Marca – Texto

ID – AutoNumeração
Marca – Número
Carro – Texto

Crie o seguinte relacionamento: Carros.Marca = Marcas.ID

Agora vamos colocar alguns dados na nossa tabela:

Fiat

– Stilo
– Palio
– Siena

Volks

– Gol
– Bora
– Golf

Ford

– KA
– Focus
– Ranger

Pronto! Já temos nossa tabela, com dados falsos! Vamos criar agora nossa página, onde iremos listar as marcas e os carros (que por enquanto não vai listar nada). Até aí não temos nada de mais, isso é feito com frequência.

<%
“Criando conexão com o banco de dados!
Set Conexao = Server.CreateObject(“ADODB.Connection”)
Conexao.Open “Provider=Microsoft.Jet.OleDB.4.0;Data Source=” & Server.MapPath(“carros.mdb”)

“Abrindo a tabela MARCAS!
Sql = “SELECT * FROM Marcas ORDER BY Marca”
Set Rs = Conexao.Execute ( Sql )
%>
<html>
<head></head>
<body>
<form name=”iMasters”>
Marcas:<br>
<select name=”marcas” onChange=”javascript:atualizacarros(this.form);”>

<% While NOT Rs.EoF %>
<option value=”<% = Rs(“id”) %>“><% = Rs(“Marca”) %></option>
<% Rs.MoveNext %>
<% Wend %>

</select>
<br><br>Carros:<br>
<select name=”carros”></select>
</form>
</body>
</html>

<%
“Fechando os objetos!
Rs.Close
Set Rs = Nothing

Conexao.Close
Set Conexao = Nothing
%>

Pronto! Salve como carros.asp! Se rodarmos este script, iremos ver apenas um select, e dentro do select, todas as marcas. Embaixo dele, temos o Select dos carros, que ainda está vazio. Repare no método onChange do SELECT marcas. Esse método é chamado toda vez que acontece alguma troca de item, ou seja, cada vez que o usuário mudar a marca, a função AtualizaCarros será chamada!

O que essa função tem que fazer? Cada vez que o usuário selecionar uma marca, ela deve atualizar o SELECT dos carros.

Bom, o JavaScript, ao contrário do ASP, é uma linguagem “client-side”, ou seja, ele só roda na máquina do cliente, portanto ela não tem acesso à nossa base de dados. O que faremos então? Vamos fazer com que o ASP forneça ao JavaScript todos os dados de que ele precisa!

Vamos escrever a função EscreveFuncaoJavaScript no ASP:

<%
Function EscreveFuncaoJavaScript ( Conexao )

“O parametro conexao receberá uma conexao aberta!
“Em funcoes, geralmente não criamos objetos do tipo conexões!
“Opte por sempre deixar sua função o mais compatível possível com qualquer projeto!

“Primeiro vamos escrever o cabecalho de qualquer script javascript!
Response.Write “<script language=””JavaScript””>” & vbcrlf
Response.Write “function atualizacarros (form) {” & vbcrlf

“Essa função JavaScript recebe o form em que estão os campos a serem atualizados!
“Veja na chamada da função no método OnChange em que se passa o this.form!

“Vamos criar um switch para ele verificar qual opção foi selecionada!!

Response.Write “switch (form.marcas.options[form.marcas.selectedIndex].value) {
” & vbcrlf

“Agora entramos com o banco de dados! Temos que jogar aqui todas as opções de carro!
SqlMarcas = “SELECT * FROM Marcas ORDER BY Marca”

Set rsMarcas = Conexao.Execute ( SqlMarcas )

While NOT rsMarcas.EOF

“Caso tenha sido essa marca selecionada…

Response.Write “case “” & rsMarcas(“ID”) & “”:” & vbcrlf

“Apagamos tudo o que tem na caixa dos carros!
Response.Write “form.carros.length=0;” & vbcrlf

“Abrimos todos os carros relativos a essa marca!
SqlCarros = “SELECT ID, Carro FROM Carros WHERE Marca = ” & rsMarcas(“ID”)
Set rsCarros = Conexao.Execute ( SqlCarros )

“Fazemos um loop por todos os carros, criando uma nova opção no SELECT!
i = 0
While NOT rsCarros.EoF

Response.Write “form.carros.options[” & i & “] = new Option(“” & rsCarros(“carro”) & “”,”” & rsCarros(“ID”) & “”);” & vbcrlf
i=i+1

rsCarros.MoveNext
Wend

“Imprimos um break! (Verifique tutoriais de JavaScript, se tiverem alguma dúvida da sua utilização!
Response.Write “break;” & vbcrlf

“Próxima marca!
rsMarcas.MoveNext
Wend

“Fecha chaves do switch e da função! E fecha o script!
Response.Write “}}” & vbcrlf & “</script>” & vbcrlf

End Function
%>

Pronto! Nossa função ASP escreve uma função JavaScript pronta para atualizar nosso SELECT carros ! Para colocarmos ela em nossa página, basta colarmos essa função no início do arquivo, e modificarmos a tag HEAD para:

<head><% EscreveFuncaoJavaScript ( Conexao ) %></head>

Teste o script! Ele atualiza corretamente o SELECT! Clique aqui para baixar o código inteiro!

Considerações finais

Esse exemplo é muito bom quando temos poucos dados. Quando a quantidade de dados é grande, isso causa uma grande perda de desempenho, pois você está jogando o conteúdo das duas tabelas INTEIRAS no arquivo ! Ou seja, se você tiver 1 milhão de registros, a página vista pelo usuário conterá 1 milhão de linhas de comandos JavaScript, deixando sua página pesada e mais demorada para o usuário baixar ela inteira!

Bom, espero que tenham gostado desse meu primeiro artigo! Se alguém tiver alguma dúvida em relação ao script, basta me mandar um e-mail!

Abraços, e até a próxima!

MasterPages Hierárquicas


Mais uma vez estou aqui para escrever um pouco sobre .NET. Desta vez, vou falar sobre como criamos MasterPages hierárquicas.

O que são MasterPages?

Com uma Master Page você consegue desenvolver uma página padrão que será utilizada em todo o site, ou seja, é como se fosse uma página default contendo menus, cabeçalhos e rodapés. Qualquer outra página criada, pode herdar a Master Page, o qual você poderá apenas utilizar a área que não seja a da Master Page. Como isto é feito em tempo de execução, você adotar qualque tipo de manutenção na página, e em tempo de execução é que o .NET monta as duas páginas em apenas uma.

Comparando a baixo nível, MasterPages são como os includes no PHP, sendo que melhor 😀

E para que irei utilizar MasterPages hierárquicas?

Mas, você deve ter sentido a necessidade, ao longo do desenvolvimento de seus projetos, de fazer tipo uma hierarquia de MasterPage, onde haveria uma MasterPage principal, contendo os menus e outras informações e uma segunda MasterPage que irá herdar dela, que poderia conter campos personalizados para algumas páginas. Com este artigo irei demonstrá-los que este tipo de procedimento não é dos mais complicados, muito pelo contrário, é muito simples de se implementar.

Vamos aos códigos!

Na sua MasterPage principal, a pai de todas, não é necessário especificar nada de diferente, só devemos definir um nome amigável para o ContentPlaceHolder, que é responsável por conter todo o conteúdo das páginas filhas desta.

<% @ Master Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 
    1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html  >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
<form id="Form1" runat="server">
<div>
<h1>Master Pai</h1>
<p style="font:color=red">Este é o conteúdo da master page pai.</p>
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
</form>
</body>
</html>

Parent.master

E na MasterPage filha, colocamos o seguinte código:

<%@ Master Language="C#" MasterPageFile="~/Parent.master"%> 
<asp:Content id="Content1" ContentPlaceholderID="MainContent" runat="server">
   <h2>Master filha</h2>

   este é um conteúdo da masterpage filha. 
</asp:Content>

Child.master

Veja o quanto é simples criar uma Master filha, usamos o mesmo comando ‘MasterPageFile=’ neste arquivo como se este fosse um arquivo aspx comum!

Simples não acham?

Apenas um detalhe

O Visual Studio 2005 não suporta a visualização de MasterPages hierárquicas no modo Design, portanto, você não poderá trabalhar neste modo para adicionar componentes ou modificar o design de suas páginas, apenas poderá utilizar o modo Source. Na próxima versão do Visual Studio, esta característica já estará disponível 😀

Por hoje é só pessoal.

Até a próxima.

DataGrid sem borda no ASP.NET


Olá Pessoa,

No ASP.Net quando precisamos utilizar o componente padrão de grid (asp:datagrid), notamos que ele gera uma tabela como resultado no HTML. Por um lado isto é bom, pois segue as normas do W3C para este tipo de dado. Porém, por padrão, ele acrescenta alguns atributos na tabela, creio que para facilitar no desenvolvimento. Um destes atributo é uma borda em cada linha.

Para remover esta borde e fazer com que a nossa tabela html de resultado venha com a borda zerada “border=0”, temos que modificar uma propriedade do componente chamada GridLines para None.

Veja abaixo o código asp.net do grid antes da alteração:

<asp:DataGrid ID="grdListagem" runat="server" AutoGenerateColumns="false">
<Columns>
     <asp:BoundColumn DataField="procedimento" HeaderText="Código"></asp:BoundColumn>
     <asp:BoundColumn DataField="descricao" HeaderText="Descrição">
          <ItemStyle Width="350px" />
     </asp:BoundColumn>
</Columns>                    
<HeaderStyle CssClass="cabecalho" />
</asp:DataGrid>

E agora depois da alteração:

<asp:DataGrid ID="grdListagem" runat="server" AutoGenerateColumns="false" GridLines="None">
<Columns>
     <asp:BoundColumn DataField="procedimento" HeaderText="Código"></asp:BoundColumn>
     <asp:BoundColumn DataField="descricao" HeaderText="Descrição">
          <ItemStyle Width="350px" />
     </asp:BoundColumn>
</Columns>                    
<HeaderStyle CssClass="cabecalho" />
</asp:DataGrid>

Note que no resultado do HTML temos uma simples tabela com o atributo “border=0”.

<table rules="all" border="0" id="ctl00_grdListagem">...

Pronto. Agora podemos definir da forma que desejarmos a borda pelo CSS.

Espero que tenham gostado da dica.

Até a próxima!

Abraços, Alex.

Diferença entre ResolveUrl e Server.MapPath


Olá Pessoal,

Quando desenvolvemos nossas páginas em ASP.Net e utilizamos os controles para exibição de imagens, bastamos apenas adicionar o sinal de “~” na URL que o próprio .Net se encarrega de traduzir e apontar para o endereço completo da imagem.

Mas e se não utilizarmos os controles? Como fazemos para continuar com nossas URLs com o “~”?

Então, no .Net existem 2 métodos que fazem ações parecidas: um para traduzir as Urls e o outro para traduzir o path (caminho no servidor). São eles:

Page.ResolveUrl – este método foi desenhado para criar URLs amigavelmente. Por exemplo:

Page.ResolveUrl("~/_imgs/logo.png")

O retorno será:

/myapp/_imgs/logo.png

Server.MapPath – este métdod serve para procurar o caminho completo no sistema para aquele recurso. Por exemplo:

Server.MapPath("web.config")

O retorno disto será:

c:\inetpub\wwwroot\web.config

Simples não?

Até a próxima.

Gerenciamento de URLs com PHP


Estou devendo aos meus leitores um artigo sobre como criar e gerenciar um bom esquema de URLs usando PHP e freqüentemente sou cobrado por isso.

Neste texto vou tentar explicar o funcionamento e as vantagens do gerenciamento de URLs com PHP em relação ao gerenciamento de URLs usando apenas mod_rewrite.

Este artigo não é uma tradução, mas é fortemente baseado no artigo de Till Quack para o A List Apart, How to succeed with URLs.

A principal vantagem de se usar PHP ao invés de apenas o mod_rewrite é que o PHP é bem mais simples. O mod_rewrite é conhecido tanto pelo seu poder quanto pela sua complexidade, não apenas pelo fato de ser necessário um bom entendimento de expressões regulares para poder usá-lo mas também por ser um tanto obscuro e difícil de entender, principalmente para os iniciantes.

É importante que você entenda o que eu quero dizer com o termo gerenciamento de URLs antes de ler o restante deste texto. Dois textos escritos por mim podem ajudá-lo a entender melhor o que isso significa: Gerenciamento de URLs – Criando URLs amigáveis e URLs amigáveis – esclarecendo dúvidas.

O principal conceito a ser entendido sobre as URLs é que elas nem sempre se referem a um arquivo ou diretório existente no disco. Na realidade, URLs nunca devem se referir a arquivos diretamente. Isso torna suas URLs voláteis, vulneráveis a mudanças. Afinal, como diria Tim Berners-Lee, cool URIs don’t change.

Para usar as técnicas descritas neste texto você precisa do servidor web Apache com o mod_rewrite habilitado, PHP e, principalmente, um bom planejamento. Antes de qualquer coisa, planeje como você quer que suas URLs sejam. Use URLs que resumam de maneira adequada e sucinta o conteúdo do recurso que descrevem.

Bem, agora que você já tem seu esquema de URLs bem planejado, vamos ao que interessa. Mãos à obra.

Crie um script PHP. Vamos chamá-lo de urls.php. Todo tráfego do site (com algumas exceções) será direcionado para esse script. Para fazer isso, crie um arquivo .htaccess na raiz do seu site com o seguinte conteúdo:

RewriteEngine On
RewriteRule !\.(gif|jpg|png|css)$ /raiz_do_site/urls.php

A primeira linha serve para ligar o mod_rewrite e a segunda é a que direciona o tráfego para urls.php. O conteúdo entre parêntesis define as extensões de arquivo que devem ser excluídas desse processo, ou seja, devem ser tratadas da maneira padrão pelo servidor web. Você pode querer incluir mais algumas extensões nessa lista (swf, svg, xml, js, txt, por exemplo), de acordo com a sua necessidade.

Você deve substituir raiz_do_site pelo caminho completo do seu site no servidor, por exemplo, /home/httpd/dominio.com/. Porém, em algumas configurações do apache (todas que eu particularmente já usei), apenas o caminho relativo já é o suficiente, no caso /urls.php ou apenas urls.php.

Agora vamos começar a escrever o script urls.php.

O primeiro passo é verificar se a requisição refere-se a um arquivo existente.

<?php
//Código retirado do A List Apart
$DOCUMENT_ROOT = $_SERVER['DOCUMENT_ROOT'];
$REQUEST_URI = $_SERVER['REQUEST_URI'];
$SCRIPT_FILENAME = $_SERVER['SCRIPT_FILENAME'];
if(file_exists($DOCUMENT_ROOT.$REQUEST_URI)
and ($SCRIPT_FILENAME!=$DOCUMENT_ROOT.$REQUEST_URI)
and ($REQUEST_URI!="/")){
    $url=$REQUEST_URI;
    include($DOCUMENT_ROOT.$url);
    exit();
}

Simplesmente verificamos se a URL refere-se a um arquivo existente, incluimos este arquivo e encerramos o script.

O próximo passo é dividir a URL em pedaços separados por “/” e verificar se o user-agent fez uma requisição pela index do site.

$url=strip_tags($REQUEST_URI);
$url_array=explode("/",$url);
array_shift($url_array); //o primeiro índice sempre será vazio
if(empty($url_array)){
	include("site_index.php");
exit();
}

Trivial, não? Se $REQUEST_URI estiver vazia significa que o usuário está requisitando a index do site. Neste caso, incluimos o script referente à index e encerramos o script.

Bom, se o usuário não requisitou um arquivo existente nem a index do site, chegou a hora de verificar se o que ele está tentando acessar é um conteúdo dinâmico. Provavelmente algo armazenado em um banco de dados, arquivos XML ou o que quer que você use pra armazenar o conteúdo dinâmico do seu site.

Neste caso não há uma fórmula pronta. Cada caso é um caso. Como você já planejou previamente o seu esquema de URLs, com certeza você sabe o que cada URL descreve. Portanto, você deve cuidar dessa parte.

Vou usar uma função fictícia verifica_conteudo() que retorna true caso a URL requisitada corresponda a algum dado presente, por exemplo, no seu banco de dados e uma outra exibe_conteudo() que cuidará para que este conteúdo seja exibido da forma adequada.

if (verifica_conteudo()){
	exibe_conteudo();
	exit();
}

Se também não houver conteúdo dinâmico referente à URL requisitada, só nos resta enviar um erro 404, informando ao user agent que o recurso requisitado não existe.

header("HTTP/1.1 404 Not Found");
exit();

Alguns cuidados devem ser tomados em relação a usuários maliciosos que queiram tentar acessar arquivos do seu sistema que podem causar danos ou garantir acesso privilegiado. Para prevenir esse tipo de coisa, adicione no início do script algumas linhas de código verificando se o usuário está requisitando algo como “../../../algum_script” ou coisas do tipo.

Acessos a URLs longas demais também devem ser prevenidos. Para isso, inclua o seguinte no início do script:

if(strlen($REQUEST_URI)>100){
	header("HTTP/1.1 404 Not Found");
	exit();
}

E é isso. O desenvolvimento desse script vai depender exclusivamente do seu caso específico. A idéia é essa. Se você a entendeu vai ser fácil adaptá-la para a sua necessidade.

Mas, além disso, há outra coisa interessante que se pode fazer com esse script que – para mim pelo menos – não é possível fazer usando apenas regras do mod_rewrite.

Lembra quando você ainda não conhecia as vantagens de se usar URLs amigáveis e usava URLs do tipo index.php?var1=valor1&var2=valor2…? Então, agora você está usando URLs totalmente diferentes e não é legal deixar “quebrados” todos os links e bookmarks que apontam para as URLs antigas, concorda?

Desde que haja alguma correspondência (é bem provável que haja) entre as URLs antigas e as novas, é possível mantê-las funcionando, lançando mão de redirecionamentos permanentes (código HTTP 301).

Como? Bem, a o código vai variar de acordo com o esquema de URLs usado. Você pode criar um código que analise a URL e redirecione para a URL nova. Exemplo: digamos que suas URLs antigas fossem da forma index.php?s=secao&a=artigo e as novas sejam da forma /secao/artigo. Neste caso, ao dividir a URL em pedaços teríamos $url_array[0] = “index.php?s=secao&a=artigo”. O que precisamos fazer é dividí-la novamente em pedaços, pegar os valores das variáveis que nos interessam, manipulá-las se for necessário e redirecionar para a URL correta.

$url = explode("?", $url_array[0]);
array_shift($url);
$url = explode("&", $url[0]);
$secao = explode("=", $url[0]);
$secao = $secao[1];
$artigo = explode("=", $url[1]);
$artigo = $artigo[1];
$url = "http://dominio.com/$secao/$artigo";
header("HTTP/1.1 301 Moved Permanently");
header("Location: " . $url);

Acho que não preciso explicar esse pedaço de código, não é? Bom, de qualquer maneira, você precisa adaptá-lo para o seu caso.

Por último temos que cuidar dos diretórios que eventualmente precisem ser manipulados diretamente pelo servidor web, sem a interferência do mod_rewrite e do nosso script. Por exemplo, você pode ter um diretório “/unsorted/” onde você guarda arquivos aleatórios e deseja que o conteúdo desse diretório seja listado da maneira padrão pelo apache. Ou então, diretórios com arquivos index.html que devem se comportar da maneira padrão. Ou ainda diretórios protegidos por senha.

Neste caso, será necessário adicionar uma regra de reescrita em nosso .htaccess para cada diretório desses. Em princípio eu imaginei que fosse possível colocar todos em uma regra só, utilizando o alternador “|” mas, por algum motivo que desconheço, não funciona. A regra é a seguinte:

RewriteRule   ^unsorted/.*$ - [L]

O “-” informa ao mod_rewrite para sair do caminho e deixar o apache cuidar sozinho da requisição e o “[L]” faz com que essa regra, se satisfeita, seja a última a ser executada. Nenhuma RewriteRule posterior será avaliada. No caso, seu .htaccess deve ficar mais ou menos assim:

RewriteEngine On
RewriteRule   ^unsorted/.*$ - [L]
RewriteRule !\.(gif|jpg|png|css)$ /raiz_do_site/urls.php

Concluindo, mais uma vez deixo claro que não há fórmula mágica para gerenciar suas URLs. Mas o processo não é complicado e, uma vez entendido, é simples aplicá-lo a qualquer caso. Desde que você planeje seu esquema de URLs da maneira adequada.

Um forte abraço !