terça-feira, 16 de dezembro de 2008

Grid com AJAX, Paginação, Ordenação e Filtro no PHP

Estou em meio ao desenvolvimento de um site em PHP e precisei de uma Grid que além de me auxiliar na paginação, busca e ordenação dos registros, também fosse em AJAX.
Depois de procurar no site PHP Classes (http://www.phpclasses.org/) achei uma Grid bem interessante chamada EyeDBGrid.

Para download da classe, acesse o link: http://www.phpclasses.org/browse/package/4951/download/zip.html

Com ela nós conseguimos recuperar dados de qualquer base Mysql.
Segue abaixo uma imagem de exemplo:


















Após feito o download você terá as classes, imagens e folhas de estilo usadas pela Grid.
Rode o exemplo no seu servidor.
A classe utiliza as proprias funções "mysql_", sendo assim, não é preciso de ativação das classes PDO pelo servidor.

Eu não tenho muito o que falar sobre as configurações e adaptações da Grid para seu sistema, pois todos os exemplos e arquivos contendo as classes estão comentados.

Espero ter ajudado vocês.
Abraços.

segunda-feira, 15 de dezembro de 2008

Criando auditoria do seu aplicativo e melhorando o desempenho com Stored Procedures no MYSQL

E ai pessoal,
Nesse post veremos como criar uma auditoria de todas as inclusões, alterações e exclusões que os usuários fazem em sua base de Dados MySQL. Faremos isso com a ajuda de Stored Procedures que, além de nos auxiliar na auditoria, já é comprovado que elas aumentam o desempenho quando vamos trabalhar com nossas tabelas de base de dados e além disso, não ficamos dependendo de qual linguagem será implementado o sistema desde que a linguagem consiga se comunicar com a base e chamar as SPs do servidor Mysql.


ENTENDENDO O USO DE STORED PROCEDURE

Primeiramente veremos como trabalha as Stored Procedures no Mysql.
A criação de SPs estão disponíveis apenas na versão 5.x do MySQL, o que foi um marco do SGBD OpenSource. Ainda faltam alguns recursos no MYSQL como vemos em outros SGBD, como a criação de Exceptions e outras funcionalidades.

Uma Stored Procedure trabalha parecido como Functions, Procedures e Métodos das linguagens de programação, onde você cria o nome e passa os paramêtros para a rotina.
Nós temos 3 tipos diferentes de métodos em SP. Esses métodos podem ser de Entrada, de Saída ou de Entrada e Saida ao mesmo tempo.

IN: este é um parâmetro de entrada, ou seja, um parâmetro cujo seu valor será utilizado no interior do procedimento para produzir algum resultado;

OUT: esté parâmetro retorna algo de dentro do procedimento para o lado externo, colocando os valores manipulados disponíveis na memória ou no conjunto de resultados;

INOUT: faz os dois trabalhos ao mesmo tempo!


CRIANDO STORED PROCEDURES

Agora veremos como criar Stored Procedures.

Exemplo de criação de SP no MYSQL:

//Criamos um delimitador, para que possamos criar várias "linhas de código" em um único script
DELIMITER $

/*Apagamos a procedure chamada sp_pessoas caso ela já exista.*/
DROP PROCEDURE IF EXISTS sp_pessoas$

/*Criamos uma procedure chamada sp_pessoas que recebe 3 parâmetros de entrada*/
CREATE PROCEDURE sp_pessoas(IN sNome_pessoa VARCHAR(35), IN sEndereco_pessoa VARCHAR(30), IN sUf CHAR(1))
BEGIN

/*Inserimos na entidade pessoas, valores passados ao chamar a Stored Procedure*/
INSERT INTO pessoas(nome_pessoa, endereco_pessoa, uf) VALUES (sNome_pessoa, sEndereco_pessoa, sUF);

END$


Para podermos chamarmos essa StoredProcedure diretamente pelo Mysql, utilizamos a função CALL.
Exemplo:
CALL sp_pessoas('Mauricio', 'Rua sem saida', 'SP');


CRIANDO A AUDITORIA

Para criarmos a auditoria, iremos criar uma tabela chamada usabilidade, na qual irá conter dados do usuário que esta efetuando o processo no sistema e um pequeno histórico sobre o processo.
Campos da tabela usabilidade :
idoperador INT(11) - (AI, PK)
data_uso TIMESTAMP - (Default value: CURRENT_TIMESTAMP)
menu VARCHAR(35)
acao VARCHAR(35)

Agora criaremos uma SP para Adicionar uma nova ou Atualizar uma pessoa já existente na entidade.
Para isso, vamos inserir algumas linhas no código do exemplo acima. Ele ficará assim:

/*Criamos um delimitador, para que possamos criar várias "linhas de código" em um único script*/
DELIMITER $

DROP PROCEDURE IF EXISTS sp_pessoas_IU$

CREATE PROCEDURE sp_pessoas_IU(sIdpessoa INT(11), sNome_pessoa VARCHAR(35), sEndereco_pessoa VARCHAR(30), sUf CHAR(1), sIdoperador INT(11))
BEGIN

/*O que faremos aqui, é verificar pelo id da pessoa, se ela já existe. Caso nao exista (seja igual a 0), insere no banco. Caso contrário, atualiza os dados*/
IF NOT EXISTS(SELECT idpessoa FROM pessoas WHERE idpessoa = sIdpessoa) THEN
INSERT INTO pessoas(nome_pessoa, endereco_pessoa, uf) VALUES (sNome_pessoa, sEndereco_pessoa, sUF);
/*Inserimos na entidade usabilidade, o historico do que o usuário processou.*/
INSERT INTO usabilidade(idoperador, menu, acao) VALUES (sIdoperador, 'CADASTROS - PESSOAS', CONCAT('O USUÁRIO INSERIU A SEGUINTE PESSOA: ', LAST_INSERT_ID()));

ELSE

UPDATE pessoas SET nome_pessoa = sNome_pessoa, sEndereco_pessoa = sNome_pessoa, uf = sUF WHERE idpessoa = sIdpessoa;
/*Inserimos na entidade usabilidade, o historico do que o usuário processou.*/
INSERT INTO usabilidade(idoperador, menu, acao) VALUES (sIdoperador, 'CADASTROS - PESSOAS', CONCAT('O USUÁRIO ATUALIZOU A SEGUINTE PESSOA: ', sIdpessoa));

END IF;


END$


Agora, criaremos a StoredProcedure para Apagar um usuário da entidade:

DROP PROCEDURE IF EXISTS sp_pessoas_D$

CREATE PROCEDURE sp_pessoas_D(sIdpessoa INT(11), sIdoperador INT(11))
BEGIN
/*Apaga a pessoa da base de dados*/
DELETE FROM pessoas WHERE idpessoa = sIdPessoa;
/*Inserimos na entidade usabilidade, o historico do que o usuário processou.*/
INSERT INTO usabilidade(idoperador, menu, acao) VALUES (sIdoperador, 'CADASTROS - PESSOAS', CONCAT('O USUÁRIO DELETOU A SEGUINTE PESSOA: ', sIdpessoa));

END$

CHAMANDO AS STORED PROCEDURES

Stored procedure de inserção:
/*Chamamos a StoredProcedure, inserindo uma nova pessoa. Nota que o IdPessoa passado no parametro da nossa SP, tem o valor 0 (ZERO). Fazendo isso, forçamos a inserção na nossa base de dados, pois nunca existirá um usuário com o Id 0(Zero) em nossa base de dados*/

/*Insere um usuario*/
CALL sp_pessoas_IU(0, 'Mauricio', 'Rua Bahia', 'SP', 1);

/*Atualiza o usuário*/
CALL sp_pessoas_IU(1, 'Mauricio', 'Rua Bahia', 'BA', 1);

/*Deletando um usuário*/
CALL sp_pessoas_D(1, 1);


Blz pessoal?
Qualquer dúvida, enviem comentários.
Terei prazer de responder ;)

sexta-feira, 12 de dezembro de 2008

Trabalhando com tabela Mestre e Detalhe no Delphi

E aew pessoal.
Esse post foi feito pelo meu amigo Marcos Carmo. Ele esta contribuindo com esse artigo falando sobre Mestre Detalhe no Delphi utilizando componentes ADO, DataSetProvider e ClientDataSet.
Ele também disponibilizou seu e-mail para quem quizer tirar dúvidas, enviar críticas ou sugestões com relação ao artigo:
E-mail: m4rk0s@gmail.com
MSN: m4rk0s_c4rm0@hotmail.com


SITUAÇÃO
Iniciei este artigo pensando na dificuldade que inúmeros programadores têm quando trabalham com tabelas Mestre>Detalhe, inclusive eu tive essa dificuldade quando comecei a programar.
Conheci várias maneiras para resolver isso, sendo que julguei apenas 2 delas como viáveis e irei explicar o método que prefiro e utilizo.

Métodos
Aqui estão alguns métodos que encontrei com suas respectivas qualidades e defeitos.

Método 1
Iniciar transação ao abrir o form, gravar a tabela mestre, dessa maneira você obtém o ID_MESTRE e pode gravar direto na Detalhe, em caso de cancelamento basta dar um Rollback.
Qualidade: Fácil e rápido de programar
Defeito: Transação muito tempo ativa, praticamente deixa o sistema monousuário.

Método 2
Inserir o Mestre ao abrir o form e entrar em modo de edição, dessa maneira você obtém o ID_MESTRE e pode gravar direto na Detalhe, em caso de cancelamento deverá deletar os registros.
Qualidade: Fácil e rápido de programar
Defeito: É necessário apagar tudo o que foi incluido em caso de cancelamento e cada item incluido é um acesso ao banco de dados.

Método 3
Inserir os dados em um StringGrid e passar gravar tudo ao confirmar.
Qualidade: Acesso único ao banco de dados.
Defeito: Trabalhar com StringGrid é trabalhoso, exige muitas linhas de código e tempo.

Método 4
Inserir o Mestre ao criar o form e entrar em modo de edição, sendo a query detalhe utilizando o LockType como ltBatchOptimistic, dessa maneira você obtém o ID_MESTRE e pode gravar direto na Detalhe. ltBatchOptimistic serve para trabalhar em cache, caso haja cancelamento deverá deletar o registro Mestre.
Qualidade: Considero esse método viável, é rápido de programar e trabalha em cache, tendo ótimo desempenho e contato único com o banco de dados.
Defeito: É necessário apagar o registro em caso de cancelamento e se o ID_MESTRE for um campo identidade vc perde um número da sequência.

Método 5 (Vencedor)
Utilizar ClientDataSet para a tabela Detalhe, trabalhando tudo em cache e acessando o banco apenas quando a operação for finalizada.
Qualidade: Faz tudo em cache tendo ótimo desempenho e gerando o ID_MESTRE apenas na finalização da operação.
Defeito: Utiliza muitos componentes (query, datasetprovider, clientdataset) e precisa fazer looping na tabela detalhe para gravar o ID_MESTRE.


O QUE É PRECISO

1 TADOQuery (qryMestre) - para a tabela Mestre (SELECT * FROM MESTRE)
1 TADOQuery (qryDetalhe)- para a tabela Detalhe (SELECT * FROM DETALHE WHERE ID_MESTRE = :ID_MESTRE)
1 TDataSetProvider (dspDetalhe) - que será ligado a TADOQuery da tabela detalhe {dspDetalhe.DataSet := qryDetalhe}
1 TClientDataSet (cdsDetalhe) - que será ligado ao TDataSetProvider {cdsDetalhe.ProviderName := dspDetalhe.Name}
e o básico: TForm, TButton, TDBEdit, TDBLookupComboBox, TDBGrid, etc...

É importante ressaltar que para trabalhar com o TClientDataSet é necessário ter a midas.dll na pasta system32 ou na pasta do executável do software. Existem algumas pessoas que adicionam a midas.dll ao projeto, o problema de fazer isso é que o projeto fica imenso.


COMO FAZER (HOW TO)

Não vou entrar em detalhes quanto ao básico considerando que este tutorial é para quem tem um nível intermediário com Delphi.

Primeiros passos:
Antes de mais nada vá ao dspDetalhe e altere a propriedade UpdateMode para UpWhereKeyOnly, isso significa que quando o TClientDataSet montar a instrução UPDATE (em uma edição) a única coisa que entrará na cláusula WHERE será a chave da tabela (isso depende de umas configurações que faremos adiante com os fields).
Agora vamos aos fields.
Adicione-os nas Querys e no ClientDataSet (considerando as ligações que foram citadas acima).

Agora as propriedades dos fields da tabela Detalhe. A qryDetalhe e o cdsDetalhe deverão estar iguais. ProviderFlags, todos os fields do tipo fkData (exceto o ID_DETALHE se ele for Identity) deverão estar pfInUpdate = True, o ID_DETALHE deve estar com pfInWhere e pfInKey como true. Se o ID_DETALHE for Identity o delphi o trouxe como ReadOnly True, é importante que ele seja alterado para false para um procedimento que será explicado adiante. Fields do tipo Lookup, Calculated, InternalCalc ou Aggregate devem estar com todas as ProviderFlags como False.
Importante: Fields do tipo Lookup devem estar com a propriedade LookupCache = True, caso contrário você terá a mensagem 'Erro desconhecido.' e vai surtar como eu surtei um dia.

Uma informação importante, todos os trabalhos da tabela detalhe serão feitos no cdsDetalhe, então fields lookup por exemplo não precisam ser adicionados a qryDetalhe.
Clique com o botão direito no cdsDetalhe e clique na opção FetchParams (para ele pegar o parâmetro ID_MESTRE da qryDetalhe conforme exemplo acima).

Agora vamos às linhas de código!
- qryMestre.Append (ela deve estar aberta: qryMestre.Open)
Inserção:
- O parâmetro da cdsDetalhe deve estar com um ID que não exista na tabela Mestre, 0 por exemplo, se o campo for Identity ele nunca terá o valor 0. (cdsDetalhe.Params.ParamByName('ID_MESTRE').Value := 0)
Edição:
- O parâmetro da cdsDetalhe deve estar o valor do ID da tabela Mestre. (cdsDetalhe.Params.ParamByName('ID_MESTRE').Value := qryMasterID_MESTRE.Value)
Abra a cdsDetalhe agora que ela já tem o parâmetro (cdsDetalhe.Open)
Declare no seu form uma variável pública inteira inicializada com valor -1 (no meu exemplo será ID_DETALHE). A variável deve ser negativa e será decrementada para que não haja violação de chave.
o evento OnNewRecord do cdsDetalhe você deverá fazer o seguinte:
cdsDetalheID_DETALHE.Value := ID_DETALHE; //por isso a propriedade ReadOnly deve estar como false
Dec(ID_DETALHE);
- Agora trabalhe nos botões referente à tabela Detalhe:
Inserção: cdsDetalhe.Append;
Edição: cdsDetalhe.Edit;
Confirmação: cdsDetalhe.Post;
Cancelamento: cdsDetalhe.Cancel;
Exclusão: cdsDetalhe.Delete;
- No botão de finalização do processo (confirmando) deve estar um código semelhante a este:
try (opcional)
//Iniciar transação (opcional)
qryMestre.Post;
cdsDetalhe.DisableControls; //Apenas para aumentar a performance do looping que será feito.
cdsDetalhe.First;
while not cdsDetalhe.Eof do
begin
cdsDetalhe.Edit;
cdsDetalheID_MESTRE.Value := qryMestreID_MESTRE.Value;
cdsDetalhe.Post;
cdsDetalhe.Next;
end;
cdsDetalhe.EnableControls;
if cdsDetalhe.ApplyUpdates(0) <> 0 then //Caso haja um erro ao incluir os itens ele gera uma exceção > 0 não applica atualizações com erros > -1 ignora erros e qualquer valor maior que 0 é a quantidade de erros que ele irá permitir
Raise Exception.Create('Erro ao incluir os itens (cdsDetalhe.ApplyUpdates(0))')
//commit (opcional)
except (opcional)
on e:Exception do
begin
//Retorna transação (rollback)
Application.MessageBox(pChar('Erro: '+e.Message),'Atenção',MB_ICONERROR);
end;


Bom.. é isso aí...
Não sou muito bom para explicar, mas acho que da pra entender.
Qualquer dúvida basta me contatar por e-mail.

quinta-feira, 11 de dezembro de 2008

Colunas em ComboBox no Delphi

Eu sei que tenho postado muitas coisas em Delphi, isso é devido ao projeto em que estou agora que é feito em cima do Delphi 2007, mas espero estar postando sempre mais coisas novas para diversificar.

Bom, vamos ao assunto do Post.

Quase sempre precisei utilizar ComboBox com colunas, então eu até adotava alguns meios de adicioná-las em eventos "Draw" do Combobox, mas contece que eu queria ir mais além daquelas colunas estranhas. Eu gostaria de inserir dados com letras em negrito, cores de fundo ecolunas bem mais alinhadas. Foi pesquisando que achei o componente TColumnComboBox.
Com ele é possível colocar cores e adicionar quantas colunas forem precisas em seu Combo.
Ele pode ficar mais ou menos com o estilo abaixo:







Esse é um combo que utilizo em meu sistema.
Eu estou buscando essas informações pela minha base de Dados, mas nada impede de você inserir seus dados fixos.
Nós podemos inserir um código para identificar o registro que queremos trabalhar. Isso fica muito mais visível para o usuário que utiliza o sistema e mais "fácil" para quem esta implementando.

INSTALAÇÃO

O TColumnComboBox é feito pela empresa TMS Software.
Para fazer o download do TColumComboBox, acesse a seguinte URL:
http://www.tmssoftware.com/site/colcombo.asp

A instalação é bem parecida com o FreeBoleto, que é um componente que eu ensino como instalá-lo aqui no meu Blog.


FUNCIONAMENTO DO TCOLUMNCOMBOBOX

O TColumnComboBox não possui a propriedade Items como estamos acostumados a utilizar em um ComboBox comum.
Para adicionar os dados, utilizaremos as propriedades Columns e ComboItems.
Na propriedade Columns, adicionamos a quantidade e título das colunas que quizermos e em comboItens, adicionamos as linhas do TColumComboBox.

Nesse post, ensinarei como inserir os valores em modo de Execução e além de criar o Combo, criaremos uma procedure que amplia a largura do ComboBox quando ele é clicado.

Segue abaixo o código da criação dos items do TColumnComboBox:

var
//Cria um objeto do tipo TColumnComboBox
C: TColumnComboBox;
begin
//Faz referencia a classe
C := TColumnComboBox.Create(Self);

with C do
begin
Parent := Panel1;
Name := 'cmbFormaPagto';
Left := 10;
Top := 10;
Visible := true;
CharCase := ecUpperCase;
AutoSize := true;
//Inserimos uma função no evento ondropdown do ComboBox, para assim que
//Clicar no ComboBox, a largura seja ampliada.
OnDropDown := ExpandirComboFormaPagto;

//Cria a primeira coluna
with Columns.Add do
begin
Width:=25;
Font.Style:=[fsBold];
Color := clRed;
end;

//Cria a segunda coluna
with Columns.Add do
begin
Width:=220;
end;

//Cria a terceira coluna
with Columns.Add do
begin
Width:=220;
Font.Color:=clBlue;
Font.Style:=[fsBold];
Color := $00D1FCDC;
end;

//Adciona os itens aos combobox
with ComboItems.Add do
begin
Strings.Add('1');
Strings.Add('Primeiro item');
Strings.Add(' Descrição 1');
end;

with ComboItems.Add do
begin
Strings.Add(2');
Strings.Add('Segundo item');
Strings.Add(' Descrição 2');
end;

end;
end;

Segue abaixo o código da procedure para apliar a largura do ComboBox:

begin
//Aqui decidimos a largura do ComboBox para 500, mas você pode mudar a largura que quizer.
TComboBox(Sender).Perform(CB_SETDROPPEDWIDTH, 500, 0);
end;

Beleza pessoal?
Abraços e até +.

quarta-feira, 10 de dezembro de 2008

Uso de Aggregates no ClientDataSet

Olá pessoal.
Hoje nesse post, falarei sobre o uso de aggregates no ClientDataSet.


PARA QUÊ E ONDE EU UTILIZO AGGREGATES?

Uma das funções do aggregate, é poder gerar expressões que envolvam todas as ocorrências adquiridas em uma Query como Somar, Contar, adquirir o valor Mínimo, Máximo e média total.
Muitos programadores costumam fazer isso atribuindo valores a um loop Do While Next;
Mas essa é uma alternativa lerda em que caso for contar uma quantidade grande de registros, a aplicação pode ficar lenta.

Você pode estar se perguntando: "Eu não posso fazer isso pelo InternalCalc?".
Com o Internalcalc, eu consigo fazer operações no registro onde esta o ponteiro, mas não em todos os registros.


UTILIZANDO AGGREGATES

Vamos botar a mão na massa.
Arraste um Panel, um ClientDataSet, um DataSource e um DBGrid para o formulário.
Marque a opção Align do panel para AlBottom e a opção Align do DBGrid para AlClient.

Vamos carregar os dados no ClientDataSet de um arquivo XML.
A instalação do Delphi gera alguns arquivos XML por padrão, para uso de testes dentro do Delphi.
  • Clique no ClientDataSet e clique na elipse(...) da propriedade FileName.
  • Vá na raiz onde esta instalado o Delphi-> Arquivos de Programas ->Arquivos Comuns->Borland Shared (ou CodeGear Shared) ->Data.
  • Escolha o arquivo Employee.xml
  • Marque a propriedade Active do CDS para TRUE.
  • Aponte a propriedade DataSet do DataSource1 para o ClientDataset1.
Seu Form deverá ficar assim:












  • Clique 2x no ClientDataSet, e tecla CTRL+F(Add All Fields).
  • Marque a opção AggregatesActive do CDS para True.
  • No FieldsEditor do CDS, tecle CTRL+M(New Field).
  • em Name, digite SOMA e em FieldType, marque a opção Aggregate. Note que o Type do novo Field, também ficará como Aggregate.














Note que o FieldEditor adicionou uma nova linha separada com o campo Agregado. O CDS faz isso com todos os campos agregados que lhe é carregado.
Clique no TField Soma e vá até a propriedade Expression no Object Inspector.
Digite o seguinte: SUM(salary) e ainda no TFieldSoma, marque a propriedade Active para TRUE.
Arraste um DBText para o Panel abaixo do DBGrid. Aponte o DataSource1 na propriedade DataSource do DBText e em DataField selecione a opção SOMA (que é o novo TField agregado que criamos).
Note que o Caption do DBText já é alterado pegando a soma total do campo Salary em todas as ocorrências. Caso você filtre o ClientDataSet, a somatotal do DBText será a soma de todos os registros filtrados.

Nossa aplicação não fica beeeeeeeeeeem mais rápida assim?
:D
legal né?

Em caso de dúvidas, podem comentar que respondo o mais rápido que eu puder.

Abraços e até a proxima.

terça-feira, 9 de dezembro de 2008

Transactions com DBExpress 4 e MySQL 5

E ai pessoal. Antes de começar o Post, gostaria de agradecer aos meus amigos pelos comentários e pelos parabéns que tenho recebido por msn e orkut :).

Nesse Post falarei sobre Transaction no Mysql utilizando o próprio MySQL e/ou Delphi 2007 com DBExpress 4.0.

TRANSACÇÃO DE DADOS (TRANSACTION)

O que seria uma transacção de dados?
Transacção de dados, nada mais é do que um acordo entre duas operações, uma regra de negócio que para ser finalizada, todos os dados precisam estar completos e fazendo parte de um acordo.

Para exemplificar, imagina uma operação financeira. Dentro de uma conta a pagar, é necessário emitir 6 faturas e, essas faturas completam o valor total da conta criada.
Ficaria assim:
Valor total da conta a pagar: R$ 600
Total de faturas: 6 faturas de R$100,00

Agora imagina você cadastrando a conta e quando vai gerar as faturas, o servidor cai, seu computador desliga ou ocorre algum outro erro? O que acontece?
Seus dados podem não estar completos, gerando inconsistência nos dados e, ao invés de você cadastrar as 6 faturas, acaba registrando apenas 4. Fora os problemas e erros que podem gerar na base de dados.
É ai que a TRANSACTION entra em ação!

Resumindo e quase "desenhando" como a transaction age em nosso sistema e base de dados:

Sistema: Banco, esta ai? inicia uma transação ai pra mim.
Base de dados: Transação realizada.
Sistema: Ei banco vlw, registra pra mim essa conta.
Base de dados: Legal, conta registrada, pode continuar.
Sistema: Registra essa fatura:
Base de dados: Fatura registrada.
Sistema: Banco, registra essa outra fatura:
Sistema: Banco??? Banco???? Cadê vc????
Sistema: Como não consegui registrar tudo, entao vou cancelar a conta e a fatura já cadastrada para mais tarde quando a base voltar do banheiro, fazer tudo novamente.

Isso é uma transaction gerada pelo sistema. Você também pode fazer a mesma coisa dentro de uma Stored Procedure ou uma trigger, direto pelo banco, sem a utilização do seu sistema, independentemente se é feito em Delphi, PHP, C#, Java ou qualquer outra linguagem de programação.

Este tipo de utilização da transaction, depende do processo que você irá realizar.

Por exemplo, se você deseja armazenar dados em um relacionamento 1-N, a melhor forma de utilizar a transaction é pelo sistema, caso contrário, você pode fazer a transaction diretamente pelo banco, como em uma auditoria de cadastros e atualizações das entidades da sua base de dados.


TRANSACTION UTILIZANDO DBEXPRESS 4

Em uma transação, temos:
Inicio da transação
Comandos SQL DML
Se tudo deu certo, COMMIT (comete)
Se deu algo errado, ROLLBACK (Volta e desfaz tudo!)

Então, vamos la.

var
Trans: TDBXTransaction;
Qry: TSQLQuery;
begin
//Inicia a transacão com o componente de conexão com a base de dados, chamada de
//CONEXAO. Ele é um TSQLConnection da aba DBExpress
//Todos os objetos que se conectarem a essa conexão, estarão em transação
Trans := CONEXAO.BeginTransaction(TDBXIsolations.ReadCommitted);

//Aqui utilizamos um try para verificar se tudo vai ocorrer bem.
try
//Cria um objeto da classe TSQLQuery para conectar-se ao componente de conexao a
// base de dados criada anteriormente
Qry := TSQLQuery.Create(Self);
with Qry do
begin
SQLConnection := CONEXAO;
SQL.Text := 'INSERT INTO contas (documento, valor_original, valor_total) VALUES ('+QuotedStr('00043244')+', '+QuotedStr('35.50')+', '+QuotedStr('40.00')+')';
ExecSQL;

SQL.Text := 'INSERT INTO faturas (idconta, valor_total, data_lancamento, data_pagamento) VALUES ('+QuotedStr('1')+', '+QuotedStr('2008/08/03')+', '+QuotedStr('2008/08/10')+')';
ExecSQL;

SQL.Text := 'INSERT INTO faturas (idconta, valor_total, data_lancamento, data_pagamento) VALUES ('+QuotedStr('1')+', '+QuotedStr('2008/08/03')+', '+QuotedStr('2008/08/10')+')';
ExecSQL;

Close;
end;

//Caso tudo ocorreu normalmente, Comete a transação, ou seja. Insere todos os dados na
//base de dados
CONEXAO.CommitFreeAndNil(Trans);

Except
//Caso ocorreu algum erro, cancela TODAS as operações acima
DM1.CONEXAO.RollbackFreeAndNil(Trans);

end;

end;


Esse cadastro foi feito apenas para explicação. Crie sua base de dados e provoque erros no código para testar sua aplicação utilizando TRANSACTION.

TRANSACTION DIRETAMENTE PELO MYSQL

Para utilizar Transações no Mysql 5, o Engine das suas tabelas precisam estar como INNODB.
Por padrão, MySQL é executado em modo autocommit. Isto significa que assim que você executa uma instrução que atualiza (modifica) uma tabela, o MySQL armazena a atualização no disco.
você pode colocar o MySQL em modo não autocommit com o seguinte comando:
SET AUTOCOMMIT=0

Depois de disabilitar o modo autocommit configurando a variável AUTOCOMMIT com zero, você deve utilizar COMMIT para armazenar suas alterações em disco ou ROLLBACK se você deseja ignorar as alterações que você fez desde o início da sua transação.

Se você quiser disabilitar o modo autocommit para uma única série de instruções, você pode utiliar a instrução START TRANSACTION:


START TRANSACTION;

INSERT INTO contas(documento, valor_original, valor_total) VALUES ('343434', '45.50', '50.00');

INSERT INTO faturas(idfatura, data_vencimento, data_pagamento) VALUES (LAST_INSERT_ID(), '2008-12-01', '2008-12-01');

COMMIT;

Caso queira cancelar a transação, ao invés de COMMIT, use ROLLBACK.

Pessoal, tentei explicar da forma mais simples possível como utilizamos Transações pelo Delphi utilizando o componente DBExpress e diretamente pelo Mysql.

Blz pessoal?
Abraços e até mais.

sábado, 6 de dezembro de 2008

SQL: Relacionamentos Self One-to-Many

Esses dias para o plano de contas do sistema, precisei criar um cadastro que funcionasse de forma hierarquica, onde cada cadastro obedecia uma sequência.

Exemplo
DESPESAS OPERACIONAIS
- ASSISTÊNCIA MÉDICA
- VALE TRANSPORTE
- ALIMENTAÇÃO
- PRO-LABORE
- SALÁRIOS


Note que os últimos 5 itens ficam dentro de um item de nível superior.
Nós podemos fazer isso usando duas tabelas e fazendo um relacionamento 1-N
ou, podemos criar um relacionamento chamado Self One-to-Many que utiliza a mesma tabela para poder fazer esses relacionamentos.

O SQL pode tratar uma mesma tabela de diferentes modos.


CRIANDO A TABELA

Iremos criar uma tabela bem simples de um cadastro de categorias para um restautante.
As categorias do restaurante costumam ser: Bebidas, Doces, Salgados....e dentro dessas categorias ou grupos, existem outros grupos que se encaixam como em Bebidas, eu posso ter: ÁGUAS, REFRIGERANTES, BEBIDAS ALCOÓLICAS, etc.

Para essa referência, criaremos um campo que funciona como chave estrangeira. É a mesma coisa como se fossemos criar uma outra tabela para fazer o relacionamento das categorias.

O Código para criação das tabelas para uma base MySQL, é a seguinte:

Create table `test`.`categorias`( `idcategoria` int(11) NOT NULL AUTO_INCREMENT , `idsubcategoria` int(11) , `nome` varchar(50) , PRIMARY KEY (`idcategoria`), KEY `FKcategoria` (`idsubcategoria`), CONSTRAINT `FKcategoria` FOREIGN KEY (`idsubcategoria`) REFERENCES `categorias` (`idcategoria`)) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=latin1;

Eu usei o tipo da tabela como INNODB, mas você poderá usar MyISAM normalmente.

Com a tabela criada, insira os dados na tabela como na imagem abaixo:


Veja que há um relacionamento de Refrigerantes, Alcoólicas e água com a categoria BEBIDAS.




CAPTURANDO DADOS RELACIONAMENTOS PELA MESMA TABELA


Para fazer a query e receber os dados relacionados, tratamos a tabela de categorias como 2 tabelas distintas relacionadas.

Para isso, podemos criar a seguinte query:
SELECT CONCAT(c.nome, ' >> ', s.nome) as categorias FROM categorias c, categorias s
WHERE s.idsubcategoria = c.idcategoria

O Concat serve para concatenar dados em uma query SQL.
O resultado será o seguinte:











Maravilha né?
Dessa forma, como utilizamos a mesma estrutura de dados para as tabelas, podemos fazer o relacionamento Self One-to-Many.

Qualquer dúvida, favor comentar ;)
Abraços...e até +

sexta-feira, 5 de dezembro de 2008

Arrays (Vetores/Matrizes) no PHP

Quando comecei a programar, tive muitas dúvidas de como usar arrays ou até mesmo o que é um array, vetor ou matriz.

Esses dias no meu trabalho meu amigo meio "Bixinha" me perguntou:
Aiiii...como que eu posso armazenar valores diferentes em uma mesma variável?
Dai foi então que eu expliquei: ARRAY!

O QUE É UM ARRAY?

Essa foi a pergunta da minha linda namorada antes da prova da faculdade.
O que eu expliquei pra ela foi o seguinte:
Array, é como se fosse um livro.
Dentro de um livro, possuimos índices e, em cada índice, o livro possui um valor, que é o conteudo daquele indice.
Exemplo:
livro[0]
livro[1]
livro[2]

No exemplo acima e seguindo o exemplo que dei à minha namorada sobre o livro, lemos o seguinte:
Livro índice 0
Livro índice 1
Livro índice 2
Então, esse livro possui 3 índices e cada índice do livro, possui textos diferentes.
O array trabalha da mesma forma.
Na programação, nós podemos dar valores aos índices de uma variável do tipo array.

Exemplo:
livro[0] = 'Branca de neve encontrou os sete anões'
livro[1] = 'Branca de neve foi morar com os 7 anões'
livro[2] = 'Branca de neve mordeu a maça da bruxa e dormiu eternamente'


UTILIZANDO ARRAY NO PHP


Uma dica que eu dou para as pessoas que tiram dúvidas comigo, é: Consulte o manual!!
O manual do php é ótimo e além de fornecer informações sobre as funções e estruturas da linguagem, contém exemplos enviados pela comunidade "PHPense".
Algumas funções já possuem manual em português.
Para acessar o manual, basta entrar em www.php.net

Meu patrão sempre me fala que manual é o guia dos "burros", mas na minha opinião, os espertos não perdem tempo fazendo besteiras e já os consultam logo de cara!

Existem várias formas de criar um array, a forma mais fácil na minha opinião é descrita abaixo:

$livro[0] = "Branca de neve encontrou os sete anões";
$livro[1] = "Branca de neve foi morar com os 7 anões";
$livro[2] = "Branca de neve mordeu a maça da bruxa e dormiu eternamente";

Além de criar vetores por índices como feito acima, podemos criar vetores com seus índices e referenciá-los por um nome, exemplo:

$livro[0]["titulo"] = "Branca de neve e os sete anões";
$livro[0]["autor"] = "Mariana";
$livro[0]["anopublicacao"] = "2000"

$livro[1]["titulo"] = "Cinderela";
$livro[1]["autor"] = "Maurício";
$livro[1]["anopublicacao"] = "1980"

O que o array acima esta fazendo, é criar uma "tabela" com seus índices e valores para cada "título"

Imagine agora os dados digitados acima em uma tabela do word, que nas colunas contenha os títulos e valores:

Título | Autor | Ano Publicacao
Branca de... Mariana 2000
Cinderela Maurício 1980

É exatamente isso que estou fazendo ao criar o array.

ONDE E QUANDO USAR ARRAY?


O array é muito utilizado quando você deseja guardar em memória, valores diferentes em uma mesma variável.
Essa função é muito utilizada em E-commerce, para inserir produtos em um carrinho de compras. Enquanto o usuário que navega o site nao finalizar a compra, todos os itens que ele solicitou ficam guardados em um array, até que na finalização da compra, o sistema passa todas as informações armazenadas do array para a base de dados.

No exemplo do carrinho de compras, como queremos guardar os valores enquanto o usuário visita o site e mantê-los mesmo que ele acesse diferentes páginas do mesmo site, podemos criar variáveis de Sessão ($_SESSION) como arrays. Tá ai a dica.



FUNCÕES NATIVAS DO PHP PARA O USO DE ARRAY

Existem algumas funções no PHP que nos auxilia no uso de array. Eu citarei as que eu acho mais importantes:

count() — Conta o número de índices de um array
array_key_exists — Checa se uma chave ou índice existe em um array
array_keys — Retorna todas as chaves de um array
array_values — Retorna todos os valores de um array
print_r — Retorna valores de uma variável
array_search — Procura por um valor em um array e retorna sua chave correspondente caso seja encontrado

Adeus StringGrid, Olá ClientDataSet

Muitas vezes que precisei armazenar dados em memória e tinha que mostrar esses dados em uma grid, utilizava o componente do Delphi chamado StringGrid, que armazena dados em forma de array e joga para a grid.

Toda vez que eu tinha que fazer esse procedimento, já me dava uma preguiiiiiiça só de pensar q teria q montar a grid, de fazer os procedimentos para deletar itens, alterar, ou até mesmo para zebrar a stringgrid.

O ClientDataSet é um componente muito poderoso e nos permite gravar dados em memória e usar um DataSource para interagir com meus componentes, como DBGrid ou qualquer outro que se utiliza de um DataSource para capturar os dados.
Além disso, podemos gravar os dados em um arquivo XML para depois utilizar os dados registrados para outros fins. Ótimo não???!!!

Então vamos a mão na massa.
Arraste para seu formulário um ClientDataSet e um DataSource, ambos da paleta DataAccess.

Clique duas vezes no ClientDataSet. Isso abrirá o FieldEditor.
Clique com o botao direito do mouse nele e New Field(CTRL+N).
em Name, digite: ID
em Type, escolha a Opção AutoIc.











Essa opção funciona como uma chave primária e nos volta um valor incrementado(AutoIncrement).

em FieldType, marque a opção Data.
Clique em OK.
Nós faremos um exemplo bem simples, por isso, adicionaremos apenas mais 2 campos, chamados nome e endereco.
Faça o mesmo procedimento acima, apenas mudando a propriedade Name para nome e endereco e o Type desses 2 novos TFields para String e em Size, digite 50.

O FieldsEditor ficará assim:









Clique com o botao direito no ClientDataSet e escolha a opção Create DataSet.

Ligue a propriedade DataSet do DataSource1 ao ClientDataSet1.
Arraste uma DBGRID e um DBNavigator ao formulário e ligue a propriedade DataSet dos 2 componentes ao DataSource1.
Percebeu que os titulos da DBGrid já pegou o nome dos campos que você adicionou ao ClientDataSet?
Legal né.
No ClientDataSet1, marque a propriedade Active para TRUE e rode a aplicação.
Veja como você manipula os dados pelo DBNavigator.
Feche o programa e os dados não estarão mais la, pois o ClientDataSet gravou os dados em memória e assim que o aplicativo é encerrado, os dados são perdidos.
Você pode usar o mesmo procedimento para componentes de terceiros como Jedi, RXLib, etc.

GERANDO E REMOVENDO OS FIELDS EM EXECUÇÃO

É possível gerar os TFields em modo de execução.
Sempre que adicionamos um novo campo em um ClientDataSet, o que estamos fazendo na realidade é adicionando um item a propriedade FieldDefs do ClientDataSet.
Abra a propriedadede FieldDefs e note que todos os campos que acrescentamos como TField estarão lá com suas propriedades.
E como geramos esses campos em modo de execução?
Simples.
Nós referenciamos os objetos pelo tipo do dados. Por exemplo:
Para um campo String, teremos que criar um objeto proveniente da classe TStringField, para um Field do tipo Float, utilizamos a classe TFloatField e para um Field Auto Incremento, utilizamos a classe TAutoIncField.
Criação de um TStringField:
var
Campo: TStringField;
begin
with ClientDataSet1 do
begin
with FieldDefs do
begin
Campo := TFloatField.Create(Self);
with Campo do
begin
FieldName := 'novoCampo';
DisplayLabel := FieldName;
DataSet := cdsDemonstrativo;
Name := cdsDemonstrativo.Name+FieldName;
cdsDemonstrativo.FieldDefs.Add(Campo.Name, ftString, 1, False);
end;
Update;
end;
end;


Como falei anteriormente, utilizamos FieldDefs para a criação do novo Field.

Para liberar um TField da memória, podemos usar o seguinte código:


Campo :=TFloatField(Self.FindComponent('novocampo'));
if Assigned(Campo) then
Campo.Free;


Qualquer dúvida, podem comentar que eu respondo.
Abraços.

quinta-feira, 4 de dezembro de 2008

BOLETOS BANCÁRIOS COM DELPHI 6 AO 2007

Logo de manhã pela empresa, me foi pedido para adicionar ao sistema financeiro uma forma de enviar boletos bancários para os clientes assim que a conta com suas faturas fossem criadas.
Eu já tinha criado boletos bancários via Web pelo PHP e pelo ASP.

Pelo PHP, eu tinha as bibliotecas do PHP boleto f'ácil, pelo ASP eu criava os boletos seguindos os layouts dos bancos (móu trabalhão ferrado).
A maravilha do Delphi, é que temos uma comunidade muito grande que cria componentes quase que diariamente :D .

Eu testei dois componentes e que a maravilha dos dois, é que eles são openSource :D
Os componentes são os seguintes:

GBBoleto:
http://sourceforge.net/projects/gbboleto/ (Delphi 5, 6 e 7)
Bancos disponíveis:
  • Itaú
  • NossaCaixa
  • Banespa
  • Unibanco
  • Real
  • Bradesco
  • Caixa Federal
  • Banco do Brasil
  • Santander
  • Banco de crédito nacional
  • Sudameris
  • Mercantil do Brasil
  • Safra
  • Sicredi


FreeBoleto:
http://sourceforge.net/projects/freeboleto/ (Delphi 7 ao 2007)
Bancos disponíveis:
  • Itaú
  • NossaCaixa
  • Banespa
  • Unibanco
  • Real
  • Bradesco
  • Caixa Federal
  • Banco do Brasil
  • Santander


Instalando o FreeBoleto no Rad Studio 2007

Para instalar o componente no RAD Studio 2007, basta clicar em File, Open e abra o arquivo FreeBoleto_D11.dproj.

O Project Manager do Delphi ficará dessa forma:

Clique no FreeBoleto_D11.bpl com o botão direito do mouse, Build e depois clique em Install.
Uma nova paleta chamada FreeBoleto é criada.













Entendendo como funciona o boleto bancário.
Para criarmos boleto bancário, precisamos evidentemente possuir uma conta bancária em um dos bancos que o componente disponibiliza a geração do boleto.
Abaixo estão alguns dados referente ao boleto bancário que você precisa conhecer:

Código cedente: Este campo varia conforme o banco, mas em
geral é composto pelo número da carteira, agência, conta e dígito, que dependendo
do banco pode ser: agencia+conta ou mesmo carteira+agencia+conta, cada banco
tem um padrão. Você precisa entrar em contato com o seu banco, e solicitar seu código cedente para geração de boleto.


Cateira:
Contem o código da carteira que está sendo utilizada. Isto também muda de banco
para banco
.
É justamente este campo que indica o tipo de cobrança escolhida pelo cedente.
Por exemplo, no Unibanco a carteira sem registro é conhecida como "ESPECIAL"
e a registrada como "REGISTRADA". Já no Itaú, a sem registro é conhecida como
"174" ou "175" e a registrada como "109" e assim vai.
Existem umas grandes variedades de modalidade de cobrança, para boletos cada
uma tem uma finalidade, vantagens e desvantagens. Descrevi apenas as principais
diferenças entre os dois tipos mais comuns, que atende a maioria dos usuários,
temos mais detalhes sobre elas que não deu pra abordar neste artigo, mas o principal
você já sabe.
Se tiver maiores dúvidas, consulte seu banco, este sim poderá fornecer maiores
detalhes sobre os tipos de cobrança.


Nosso número: Este campo também varia conforme o banco, mas você deve dar uma atenção especial à ele, porque quando o boleto é pago, é com esse número que aparece no seu extrato, assim você tem como identificar o boleto pago por um sistema administrador da sua conta fornecido pelo seu banco (Esse sistema gerenciador não é obrigatório).
Você pode usar esse número para administrar seu sistema, como identificação de número da duplicata, número do boleto pago, ou algo dessa forma.
Portanto esse número deve ser diferente para cada boleto emitido, e não podendo haver duplicidades.
Alguns bancos fornecem uma faixa de números que o cliente pode trabalhar, outros já deixam a critério do cliente.


Modalidade da conta: O banco tem varias modalidades de cobrança, e emissão de boletos. Vou descrever
as duas principais e mais utilizadas e com as quais já trabalhei.

Cobrança Registrada

Quando emitir seus boletos com cobrança registrada, você deve enviar um arquivo
de remessa para o banco, este arquivo de remessa segue um padrão, que não vem
ao caso agora, senão o artigo vai ficar enorme.

Este arquivo de remessa que é enviado ao banco e serve para registrar os boletos
emitidos. Assim, se algum sacado não pagar, o banco pode automaticamente ou
por instrução do cedente, pode mandar o nome do sacado para protesto, ou mesmo
o para o cadastro do spc.

Ou seja, este tipo em geral é utilizado quando as empresas querem ter uma segurança
maior, de modo que se o cliente não pagar eles tem um meio legal de protestar
o sacado e cobrar a dívida.

Cobrança sem Registro

Nessa cobrança você simplesmente emite o boleto e o envia para o sacado pagar
e não há registro no banco sobre este boleto emitido, o banco só saberá da existência
do boleto quando ele for pago.
Esta é a cobrança mais indicada para uso na internet, porque se o cliente não
pagar, simplesmente o pedido não é enviado.

Agora que você já conhece os dois principais tipos de cobrança, vamos falar
sobre o campo "carteira" do boleto. É justamente este campo que indica o tipo
de cobrança escolhida pelo cedente.

Por exemplo, no Unibanco a carteira sem registro é conhecida como "ESPECIAL"
e a registrada como "REGISTRADA". Já no Itaú, a sem registro é conhecida como
"174" ou "175" e a registrada como "109" e assim vai.

Existem umas grandes variedades de modalidade de cobrança, para boletos cada
uma tem uma finalidade, vantagens e desvantagens. Descrevi apenas as principais
diferenças entre os dois tipos mais comuns, que atende a maioria dos usuários,
temos mais detalhes sobre elas que não deu pra abordar neste artigo, mas o principal
você já sabe.

Se tiver maiores dúvidas, consulte seu banco, este sim poderá fornecer maiores
detalhes sobre os tipos de cobrança.


Convênio:
Este campo serve apenas para o banco do brasil (pelo menos o que eu sei até agora).
Caso seu banco seja o B.B, entre em contato com sua agencia/gerente e obtenha mais informações.
Como eu utilizo o Bradesco, não precisei utilizar este campo.


Documento:
Você pode usar este campo para dizer qual documento/nota fiscal este boleto bancário pertence. Este campo não é obrigatório.

Criando o formulário e objetos para geração do boleto com o componente.

Você pode criar os objetos com as classes TFreeBoleto e TFreeBoletoImagem ou apenas arrastar os componentes que foram registrados na paleta FreeBoleto.

No diretório do arquivo compactado que você efetuou o download, há um diretório chamado Demo.
Abra o projeto e verifique os passos para a criação do boleto.
O exemplo é bem simples.
Em caso de dúvidas, há um grupo de discussões no yahoo do Freeboleto, que pode ser acessado pela URL:
http://br.groups.yahoo.com/group/freeboleto

Aqui esta "a cara" do boleto bancário utilizando o arquivo de demonstração do FreeBoleto:
















Fmz pessoal?
Abraços e até a proxima.

quarta-feira, 3 de dezembro de 2008

DIA DO PROGRAMADOR

Tá pensando que apenas médicos, veterinários e advogados tem seu dia?
Também temos o nosso!!
Não sei se foi por acaso, mas o dia do programador cai 3 dias após meu aniversário :P

Peguei esse post no blog do Luciano pimenta, que também trabalha no nosso ramo e tem seu blog.

" Se você ficou assustado ao ler o título, fique calmo e feliz, pois existe o nosso dia :). Claro que alguém lembraria daquele profissional, que nem sempre é entendido, muitos chamam de nerd, que usa óculos de grau elevado (nem todos) e que os assuntos sempre são voltados para tecnologias (também, nem todos), ou seja, nós programadores.

A definição do dia é a cara do programador ou seja o 256º dia do ano, o dia 13/Set ou 12/Set em anos bissextos. Saiba mais em: http://pt.wikipedia.org/wiki/Dia_do_Programador.
No mesmo link temos como é comemorada a data pelos programadores americanos.

INTRODUÇÃO AO BLOG

Meu nome é Maurício Vinicius, sou tecnologo em processamento de dados pela FATEC (Faculdade de tecnologia), trabalho como Analista desenvolvedor, possuo conhecimento em linguagens de programação e banco de dados e, comecei nesse ramo há 10 anos pelo Coldfusion ainda quando ele pertencia a Allaire.
Resolvi criar esse blog para expôr todos problemas, resoluções e novidades que todo Analista/desenvolvedor se depara todos os dias.

Tentarei passar meus conhecimentos e experiências da forma mais didática possível.
Minha maior experiência e conhecimento são nas linguagens, SGBD, bibliotecas e ferramentas:

Web:
Coldfusion, PHP, ASP, ASP.NET, RAD STUDIO for .NET, EXTJS, JQUERY e CSS.
Win32:
Delphi .
SGBD:
MySql, POSTGRESQL, SQL SERVER e FIREBIRD
Análise:
UML

Já trabalhei nas seguintes empresas:
VE Provedor Internet - www.ve.com.br
HAIDAR - Adm. de comércio Exterior - www.haidar.com.br
KUHLMANN - Surveyors & Consultants - www.kuhlmann.com.br

Volte sempre ao meu blog que tentarei efetuar posts todas as semanas.
Abraços e até lá.