Delphi for PHP

Desvendando os Segredos dos Componentes Data Access

 

Sem dúvida nenhuma o tempo sempre foi um fator decisivo no desenvolvimento que agregado à qualidade torna esta tarefa um desafio. Como produzir sistemas com qualidade em tempo hábil? Como obter produtividade no desenvolvimento de meus projetos?

Nos últimos anos a indústria de TI tem investido fortemente em ferramentas que aumentem a produtividade, prova disso foi o lançamento pela CodeGear do Delphi for PHP. Uma ferramenta RAD para PHP que une uma linguagem de scripts multiplataforma, multi-bancos e free com o poder e a versatilidade da VCL. Isso tudo somado a filosofia da orientação a objetos, segmento onde a Borland possui uma larga experiência, torna o Delphi for PHP uma ferramenta bem completa que vem preencher uma lacuna que havia entre o desenvolvimento web em PHP e a produtividade.

Para provar o que estou falando vamos neste artigo desenvolver uma pequena aplicação e você verá como os componentes da VCL nos proporcionam esta produtividade, principalmente no que diz respeito a persistência em banco de dados, mas antes gostaria de deixar aqui algumas observações importantes.

Como este veículo tem em seus leitores maioria de programadores Delphi e que para muitos a linguagem PHP é uma novidade, acho por bem expor aqui algumas das particularidades desta linguagem, pois apesar da IDE ser bem parecida com a do BDS2006 a linguagem de desenvolvimento é a PHP, e sendo assim devemos respeitar a sintaxe desta linguagem.

Em primeiro lugar o PHP é Case Sensitive por tanto muita atenção na hora de declarar e de referenciar suas variáveis, métodos e classes, pois diferente do delphi uma letra maiúscula aqui faz toda diferença e na verdade declarar não seria o termo ideal a ser empregado nos casos das variáveis. Isto porque em PHP não precisamos declarar as variáveis e explicitar o seu tipo, essa linguagem não é tipada como o Delphi. Os operadores lógicos e de atribuição também são diferentes e isso pode se tornar uma dor de cabeça para muitos iniciantes que vem do Delphi e se deparam com o PHP, isso porque podemos por um lapso escrevermos a seguinte sentença:

If (!($id = null) )

{

echo (‘variável não é nula);

}

Há um erro de sintaxe na instrução acima, mas pode acreditar será muito comum se você é iniciante em PHP, pois é quase que automático, está no sangue compararmos valores com o símbolo "=", porém operador de igualdade no PHP é "= =" e o de atribuição sim que é "=".

Outro ponto importante é quanto ao escopo das variáveis dentro do script. Quando queremos fazer referência a uma variável global dentro de um método, precisamos de dentro do mesmo informar que esta variável é global, pois de outra forma será criada uma nova variável local. Um exemplo claro disso é quando adicionamos um Data Module ao nosso projeto. Não basta clicarmos em File -> Use Unit ou CTRL+F11 precisamos em cada método informarmos o objeto que representa o nosso Data Module com a palavra global e a partir daí utilizarmos nossos componentes de acesso a dados. Ex:

Function Button1Click ($sender, $params)

{

global $DM;

$DM->tbcliente1->Close ();

}

Digo isto pois tenho visto inúmeras dúvidas em diversos fóruns devido a este problema. Nosso objetivo neste artigo não é a linguagem em si e sim a utilização da ferramenta, para mais informações quanto à sintaxe e funções do PHP aconselho a leitura do Manual PHP disponível em http://www.php.net/manual/pt_BR/index.php .

Chega de papo e mãos a obra!

Nosso projeto consiste em criar um exemplo onde manipularemos dados utilizando os componentes Data Access da VCL. Veremos alguns recursos importantes da IDE e algumas técnicas do PHP, como passagem de parâmetros via URL com método GET e como nos prevenirmos de SQL Injection.

Inicie uma nova aplicação no Delphi for PHP clicando em File->New -> Application:

php1.jpg

Salve esta página como index.php e o projeto com o nome que melhor lhe convir. Neste ponto é importante salientar que o nome do arquivo aqui faz toda a diferença pois nós faremos referência a eles em nossos links, eles serão as nossas páginas. Já a propriedade Name referencia a página, ou melhor a classe dentro do script, é criada também uma variável global $Name que nada mais é do que um objeto do tipo desta classe. Ainda neste ponto adicione ao projeto um Data Module. File -> New -> Data Module, salve como datamodule.php. Altere a propriedade name do nosso Data Module para DM, a partir de agora devemos utilizar variável global $DM se quisermos acessar os recursos desta classe. Observe:

php2.jpg

 

Configurar a conexão com o banco de dados é bem simples. Nesse exemplo utilizaremos o Interbase mais especificamente o banco DBDEMOS.gdb. A IDE trás um recurso interno que nos possibilita registrar bases de dados sem a necessidade de ferramentas externas tudo isso através do Data Explorer, uma aba que se encontra no Project Manager. Nesta aba temos a opção de registrarmos bancos Interbase e MySql e com isso visualizarmos as tabelas e os campos contidos em nosso banco, mas isso não nos impede de fazermos conexão com outros servidores de banco de dados, pois os componentes Database possuem uma propriedades chamada DriverName onde podemos selecionar o driver de acesso ao banco de dados desejado.

 

 

Clique com o botão direito do mouse sobre Interbase e clique em Register Database para registrar seu banco de dados:

php3.jpg

 

A tela de registro pede os parâmetros de configuração padrão os mesmo que estamos acostumados no Delphi tradicional. Basta informar o Host, Path do Arquivo de Dados, Username e Password além de um nome para identificar esta conexão.

Se você possui alguma versão do Delphi instalada em seu computador facilmente encontrará o banco dbDemos.gdb em c:\Arquivos de Programas\Arquivos comuns\Borland Shared\Data\dbDemos.gdb. Eu lhe aconselho a criar uma pasta chamada Data dentro da pasta do seu projeto e então colocar nela uma cópia do banco, faça a mesma coisa para as imagens usadas no projeto, crie uma pasta imagens e coloque nela as imagens utilizadas no projeto. O Username e Password são os padrões do Interbase: SYSDBA e masterkey respectivamente.

php4.jpg

 

A conexão está feita e configurada, a partir de agora temos acesso a todas as tabelas do banco bem como todos os campos dessas tabelas através da própria IDE utilizando a treeview do Data Explorer.

php5.jpg

Valendo-se do bom e velho Drag and Drop vamos adicionar ao nosso Data Module os componentes que necessitamos para realizar o acesso às tabelas do nosso banco de dados. Note que na parte superior esquerda do Data Explorer há quatro botões. Eles servem para determinar qual componente Data Controls você quer que seja adicionado quando arrastarmos uma tabela ou um campo para um form. No caso do Data Modulo só serão adicionados os componentes Data Acess. Os dois primeiros botões estão relacionados às tabelas e os dois últimos aos campos, são eles: DBGrid, DBRepeater, Label e Edit. Com isso você pode escolher qual componente quer que seja adicionado ao form quando arrastar para o mesmo um campo ou tabela.

php6.jpg

Neste exemplo vamos utilizar a tabela CUSTOMER. Clique sobre ela e arraste-a para dentro do nosso Data Module. Observe que são colocado três componentes em nosso Data Module devidamente conectados entre si: um Database, uma Table e um DataSource. Eu irei manter os nomes default mas o ideal é renomeá-los para algo mais sugestivo através de sua propriedade name. O componente Database tem a função de realizar a conexão com o banco de dados e através dele que podemos criar nosso dicionário de dados, onde podemos configurar diversas propriedades dos campos de nossas tabelas.

O processo e bem simples, vá ate a propriedades dictionary e insira um nome para o nosso dicionário, por exemplo DicArtigoPHP. Agora clique com o botão direito sobre o componente Database e no menu PopUp clique em Create Dictionary, uma mensagem aparecerá confirmando a criação do dicionário de Dados e está pronto, simples assim. Uma nova tabela foi criada em nosso banco de dados para ser o nosso dicionário. Observe:

php7.jpg

Através dele podemos por exemplo substituir os captions que aparecem nos DBGrid através da propriedade Display Label. Basta incluirmos um registro informando o nome da tabela, o campo, qual propriedade queremos alterar, o valor que queremos que apareça no label da Grid, ex:

1 – CUSTOMER – COUNTRY – displaylabel – Pais

Desta forma as Grids linkadas a esta tabela mostrarão para este campo seus Caption alterados automaticamente conforme as configurações do nosso dicionário de dados.

Vamos agora ao desenvolvimento do nosso form ou melhor da nossa página. Em nossa página index.php vamos adicionar um componente Image, um Panel, e um DBGrid. Dentro deste Panel adicione três labels sendo que dois deles serão nossos links.

Para localizar mais rapidamente os componentes na Tool Palette a IDE também oferece um recurso, basta pressionar o atalho Ctrl+Alt+P e digitar o nome de um componente, DBGrid por exemplo. Um filtro irá selecionar o componente bastando pressionar enter para que o componente seja adicionando a página. Os usuários do DBS2006 já estão habituados com esse recurso. Disponha os componentes na página da maneira que achar melhor.

Precisamos acessar os componentes do nosso Data Module. Para isso vamos declarar que esta página utilizará recursos que estão em outra página. Menu File-> Use Unit ou simplesmente Alt+F11, selecione datamodule.php e pressione Ok. Agora basta apontar a propriedade DataSource do DBGrid para DM.dsCUSTOMER1, executar a aplicação e ver o resultado:

 

php8.jpg

 

Observe que de uma forma simples e rápida disponibilizamos em nossa página uma Grid com os dados de nossa tabela e sem escrever uma única linha sequer, isso é RAD. Este componente DBGrid ainda nos permite mais, por exemplo: os dados exibidos na tela podem ser editados diretamente na Grid sem a necessidade de nenhum comando. Basta dar um duplo clique sobre ao campo, editar os dados e pressionar enter para que seja gravado no banco. Simples assim !!

Podemos ainda ocultar colunas, mudá-las de posição e redimensioná-las tudo isso através do componente da VCL com seus métodos e esse é apenas um dos mais de 50 componentes existentes na VCL.

Vamos adicionar um pouco mais de emoção ao nosso projeto. Nossa aplicação terá um menu que será montado dinamicamente para apresentar todos os países onde possuímos clientes e ao clicarmos em um país vamos mostrar em uma página, também montada dinamicamente, os clientes do país selecionado.

Dentro do Panel, abaixo do label "By Country", vamos adicionar um componente chamado DBRepeater e dentro dele adicionar mais um label. Apague o Caption deste componente, coloque uma cor no fundo e altere seu nome para LbCountry.

Esses são os componentes que precisamos para nosso menu: um DBRepeater e um Label. O DBRepeater é mostrado na tela para cada registro do DataSet ao qual está conectado, desta forma todos os componentes que estiverem contidos nele também serão "repetidos". Com isso podemos fazer com que esses componentes se comportem ou assumam valores de acordo com o registro corrente do DataSet. Realizaremos uma consulta ao banco que nos retornará os países onde possuímos clientes e passaremos o resultado ao DBRepeater para que ele se encarregue do resto. Quando digo passar o resultado quero dizer "linkar" o DBRepeater ao DataSet em questão através da propriedade DataSource. Faça isto:

Adicione um componente Query ao nosso DataModule e altere as seguintes propriedades:

Database

dbdbdemos1

Limit Count

-1

LimitStart

-1

Active

True

SQL

select distinct country from customer

 

O Database dispensa comentários, é através dele que a nossa query se conecta ao banco. LimitCount -1 indica que a query irá mostrar todos os registros que forem retornados pela consulta, se colocarmos por exemplo LimitCount 10 nossa query mostraria somente 10 registros.

LimitStart configura a partir de que posição os registro serão mostrados, -1 indica que não há um Start configurado. Como em LimitCount, se colocarmos LimitStart 10, nossa query retornaria os registros a partir da Décima posição. Active abre a nossa query e executa o comando contido em SQL no nosso caso "select distinct country from customer".

Insira também um DataSource altere seu nome para DsMenu e aponte-o para a Query que acabamos de configurar. Volte ao DBRepeater e aponte a propriedade DataSource para DM.DsMenu. Os componentes que irão formar o nosso menu já estão configurados. Como falei, o DBRepeater será "renderizado" tantas vezes quantos registros forem retornados em nossa Query, e com isso nosso label também será, sendo assim, vamos fazer com que o label mostre em seu caption o nome do país corrente no momento em que for mostrado na tela. Faremos isso através do evento BeforeShow do label.

Selecione o label LbCountry clique na aba Events do Object Inspector e dê um duplo - clique no evento onBeforeShow, no evento criado digite o código abaixo:

 

global $DM;

$sender->Caption = $DM->Query1->COUNTRY;

$sender->Link = "search.php?id=". $DM->Query1->COUNTRY;

Como o PHP não é compilado, pode-se digitar praticamente qualquer coisa e mandar executar a página no servidor e lá um erro será gerado. Porém antes de executarmos um script podemos verificar a integridade da sintaxe, para isso a IDE disponibiliza um recurso chamado Syntax Check, podemos então verificar se há erros em nosso código antes de executá-lo.

 

php9.jpg

 

 

Caso haja algum erro uma mensagem é exibida no panel Message na parte inferior da IDE mostrando a linha, o arquivo onde o erro ocorreu e a mensagem de erro. Também podemos acessá-lo através do menu View -> Message.

 

php10.jpg

 

Sintaxe verificada e Ok, resta executar a aplicação para vermos o resultado:

php11.jpg

Repare que temos uma página pronta, acessando uma base de dados, estamos realizando consultas e criando um menu dinamicamente e com quantas linhas de código? Apenas três. Esta é a produtividade que eu falava no início do artigo, isto é possível pois os componentes possuem propriedades e encapsulam métodos que proporcionam essa versatilidade. Foi o que fizemos no evento BeforeShow, antes de mostrá-lo ao usuário configuramos as propriedades caption e link com os Dados da Query linkada ao DBRepeater:

$sender->Caption = $DM->Query1->COUNTRY;

Na instrução seguinte chamamos a página search.php que criaremos em seqüência e passamos para ela, via URL, um valor através da variável "id":

$sender->Link = "search.php?id=". $DM->Query1->COUNTRY;

Essa prática é muito comum quando desenvolvemos um site dinâmico, pois temos a necessidade de passar alguns valores de uma página para a outra, para podermos, então, realizar operações como consultas, filtros e inserções no banco, autenticação de usuários, etc. No PHP os dois métodos mais utilizados para isso são o GET e POST. Neste exemplo utilizaremos o método GET onde os valores e seus respectivos identificadores são transmitidos pela URL, não sendo preciso a abertura de uma nova conexão.

Como os valores são passados pela URL, há um limite para o número de bytes que serão enviados, que neste método é de no máximo 1024 caracteres, o que nos limita bastante. Para casos onde haja necessidade de se passar valores mais extensos utilizamos o método Post, mas isso fica para uma outra oportunidade, nos resta agora criar a página search.php que irá receber nosso parâmetro e montar nossa página dinamicamente.

Adicione um novo form ao projeto. File-> New-> Form. Salve-o como search.php. Adicione à página um DBRepeater, e dentro dele seis labels. Altere a propriedade name de cada label para LbCompany, LbAdd, LbCity, LbCountry, LbPhone e LbContact. Disponha-os na tela de maneira organizada, coloque o Font.Size do LbCompany para 15px, Font.Weight para bold e Font.Style para fsItalic. No DBRepeater altere a propriedade BorderWidth para 1. Abaixo uma idéia :

php12.jpg

Como dito anteriormente todo DBRepeater precisa estar conectado a um DataSet, neste caso vamos conectá-lo a tabela tbCUSTOMER1 que será filtrada mais a frente para exibir os clientes de acordo com o país selecionado. Vá até a propriedade DataSource do DBRepeater e aponte-a para DM.dsCUSTOMER1. Agora configure o evento BeforeShow de cada label para mostrar o valor dos seus respectivos campos na tela. Os códigos são bem parecidos mudando apenas o nome do campo que será exibido. Configure os eventos onBeforeShow de cada label seguindo o exemplo abaixo:

Para LbCompany:

global $DM;

$sender->Caption = $DM->tbCUSTOMER1->COMPANY;

Para LbAdd:

global $DM;

$sender->Caption = $DM->tbCUSTOMER1->ADDR1;

Para LbCity:

global $DM;

$sender->Caption = $DM->tbCUSTOMER1->CITY;

Para LbCountry:

global $DM;

$sender->Caption = $DM->tbCUSTOMER1->COUNTRY;

Para LbPhone:

global $DM;

$sender->Caption = $DM->tbCUSTOMER1->PHONE;

Para LbContact :

global $DM;

$sender->Caption = $DM->tbCUSTOMER1->CONTACT;

Nosso DBRepeater e nossos labels já estão prontos para mostrar os dados, falta apenas filtrar a tabela mediante o parâmetro que será passado pelo método GET e é nesse ponto que devemos nos habituar a tratar possíveis SQL Injection’s. Claro que aqui não estamos lidando com dados críticos porém esta é uma prática saudável que deve ser exercitada. Devemos ter em mente que se os valores são passados via URL, e desta forma são visíveis ao usuário, por isso devemos nos precaver que um usuário mal intencionado não irá passar uma outra instrução que não aquela que estamos esperando. Nada impede que ele digite "search.php?id=qualquer coisa", no nosso caso isso não nos afetaria, a página apenas não exibiria dados pois não há cliente com este país.

Agora imagine o cenário onde temos uma página de login que recebe um usuário e senha e consulta no banco para verificar a existência do usuário:

$usu = $_POST[‘Usuario’];

$pwd = $_POST[‘Senha’];

$query_string = "Select * from user

where username = ‘ ".$usu." ‘and password = ‘ ".$pwd." ‘ ";

Este é um script perfeito para ser vitima de SQL Injection, veja a instrução gerada se passarmos a sentença abaixo como senha.

‘ or ‘A’ = ‘A

A instrução gerada seria:

Select * from user

where username = ‘ A ‘and password = ‘‘ or ‘A’ = ‘A

Não há usuário com o nome A e com senha em branco porem A é igual a A, esta sentença retornaria verdadeira e o acesso seria liberado.

Este tipo de vulnerabilidade e facilmente tratada no PHP através da função addslashes (), que insere uma barra invertida antes de cada aspa simples ou aspa dupla, veja:

$usu = addslashes( $_POST[‘Usuario’] );

$pwd = addslashes( $_POST[‘Senha’] );

$query_string = "Select * from user

where username = ‘ ".$usu." ‘and password = ‘ ".$pwd." ‘ ";

Desta vez a instrução gerada com a mesma senha passada acima seria:

Select * from user

where username = ‘ A ‘and password = ‘\‘ or \‘A\’ = \‘A

Este é um comando simples mas de extrema importância e nós faremos uso dele.

No carregamento da página search.php vamos verificar o parâmetro passado e de posse dele filtramos os dados da nossa tabela para exibirmos os clientes do país selecionado. Como nosso DBRepeater já esta linkado a tabela ele se encarregará de montar a página com os dados.

Com o Form selecionado vá até a aba Events do Object Inspector e localize o evento onShow, dê um duplo clique neste evento e digite o código abaixo:

$id = addslashes( $_GET[id] );

//Se o parâmetro não é nulo

if (!($id = = null))

{

global $DM;

$DM->tbCUSTOMER1->Close();

$DM->tbCUSTOMER1->Filter = "COUNTRY = " . $id . " ";

$DM->tbCUSTOMER1->Open();

}

O código é bem simples, utilizamos a "Super Global" $_GET para capturar o valor passado via URL e entre os [ ] colocamos o nome do parâmetro que queremos capturar, pois poderíamos passar mais de um parâmetro como por exemplo pagina.php?action=deletar&id=125 ou produto.php?cat=25&fab=125&cód=256. Utilizamos a função addslashes() para previnir possíveis SQL Injection e passamos o parâmetro para uma variável local $id.

Após fazer uma verificação quanto ao conteúdo da variável, fechamos nossa tabela, passamos um comando para a propriedade filter, concatenando o campo Country com o país passado como parâmetro:

$DM->tbCUSTOMER1->Filter = "COUNTRY = Brasil ";

Feito isso abrimos a tabela e voila, temos uma página contendo os clientes do país selecionado:

php13.jpg

 

Conclusão

Este artigo não teve a pretensão de abordar todos os aspectos dos componentes de acesso a dados do Delphi PHP, porém ele demonstra de uma forma simples como realizar operações no banco de dados utilizando os principais componentes. Com as informações aqui expostas, é possível adicionar mais recursos ao nosso projeto como por exemplo, colocar um link na página acima para cada cliente que ao ser acessado nos remeteria para uma página que mostraria informações detalhadas deste cliente, como últimos pedidos, média de compras, produtos mais comprados, etc.

Questões como layout, tratamentos de erros e desempenho não são abordados neste artigo, mas devem ser levadas em consideração. O exemplo disponível para download possui algumas páginas a mais onde trabalho com frames entre outras coisas.

Sem dúvida nenhuma produtividade é a palavra chave, e espero que isso tenha ficado claro com o projeto acima. Esta é uma ferramenta nova e há muito ainda que se aprender sobre ela, e não há feedback melhor do que aquele vindo de que quem está à frente da batalha, então não deixe de entrar em contato, envie suas dúvidas e sugestões pois terei prazer em respondê-los.

Um grande abraço a todos e até a próxima.


Assinatura
TDS Tecnologia.
Centro de Treinamentos Oficias Borland CodeGear no Rio de Janeiro
BDS 2006 Win32 Product Certified
Skype: r_c_mourao 
Cel: (21) 8245-4101