Você está na página 1de 14

Abstração de Base de Dados utilizando DAO

6 02 2007

Olá pessoas : )

Bom, ontem me peguei pensando em algo para escrever aqui no blog, e me ocorreu que
nunca encontrei muitos textos por ai falando sobre a utilização de DAO com PHP, e que
por ser algo que venho usando há algum tempo agora, e que me ajuda bastante, decidi
escrever um texto que procura explicar como um DAO funciona, e como pode ser
utilizado.

Segue abaixo então, o texto. Em caso de dúvidas, sinta-se a vontade de deixar um


comentário ai, ou me escrever : )

Abstração de Base de Dados utilizando DAO


Autor: Henrique <henrique@heap.com.br>
Data: 05/02/2007

Indice
0. Introdução
1. Como funciona?
2. A classe VO (Value Object)
3. A classe DAO (Data Access Object)
4. Utilização
5. Considerações Finais
6. Bibliografia

0. Introdução
Por muitas vezes, o desenvolvedor de sistemas, se depara com um grande
problema quando necessita atualizar a base de dados da sua aplicação, ou
modificar uma query em algum lugar. Quando o sistema fica grande demais, as
queries se perdem em meio ao código, e tudo se torna uma grande bagunça. Há
casos, em que o desenvolvedor precisa migrar o software de um SGDB para outro,
e ai da-lhe correria para encontrar todas as queries e corrigi-las para
funcionar com o novo SGDB.
Para resolver esse tipo de problema, foi criado um padrão, para centralizar as
queries, e permitir que alterando apenas a classe referente a tabela no banco,
possamos ter a aplicação rodando sem problemas.

1. Como funciona?
A idéia por trás do DAO, é bastante simples: transformar as tabelas de nosso
banco de dados em classes VO, e as ações que podemos realizar em classes DAO.
As explicações e exemplos dados nesse texto, irão se basear todos na seguinte
estrutura de base de dados, utilizando MySQL como SGDB de escolha.

create table cliente (

id_cliente int not null primary key auto_increment,

nome varchar(30),
sobrenome varchar(30),

endereco varchar(50),

telefone varchar(20)

) engine=INNODB;create table conta (

id_conta int not null primary key auto_increment,

id_cliente int,

numero_conta varchar(12),

numero_agencia varchar(8),

tipo_conta varchar(20),

foreign key(id_cliente) references cliente(id_cliente)

) engine=INNODB;

A partir daqui, iremos criar as classes VO e DAO de cada uma dessas tabelas, e
então demonstrar uma maneira simples de utilização, que pode ser aprimorada,
em combinação com outros patterns, ou até mesmo com a utilização da
imaginação. Ficará então, ao critério do leitor.

2. A classe VO (Value Object)


A classe VO, é a classe que irá fazer a abstração das tabelas de nosso banco
de dados. Ela é uma classe que contém apenas os métodos ‘get’ e ’set’ para
cada uma das propriedades, que nada mais são que os campos das tabelas.
A classe da tabela cliente então, ficará da seguinte maneira:

<?php

class ClienteVO {
/**

* @var integer

*/

private $id_cliente = NULL;

/**

* @var string

*/

private $nome = NULL;

/**
*

* @var string

*/

private $sobrenome = NULL;

/**

* @var string

*/

private $endereco = NULL;

/**

* @var string

*/

private $telefone = NULL;

public function ClienteVO ( ) {

/**

* Return the value of "$this->id_cliente"

* @return integer

*/

public function getId_cliente ( )

return $this->id_cliente;

/**

* Define the value of "$this->id_cliente"

* @return void

*/

public function setId_cliente ( $id_cliente )


{

$this->id_cliente = $id_cliente;

/**

* Return the value of "$this->nome"

* @return string

*/

public function getNome ( )

return $this->nome;

/**

* Define the value of "$this->nome"

* @return void

*/

public function setNome ( $nome )

$this->nome = $nome;

/**

* Return the value of "$this->sobrenome"

* @return string

*/

public function getSobrenome ( )

return $this->sobrenome;

}
/**

* Define the value of "$this->sobrenome"

* @return void

*/

public function setSobrenome ( $sobrenome )

$this->sobrenome = $sobrenome;

/**

* Return the value of "$this->endereco"

* @return string

*/

public function getEndereco ( )

return $this->endereco;

/**

* Define the value of "$this->endereco"

* @return void

*/

public function setEndereco ( $endereco )

$this->endereco = $endereco;

/**

* Return the value of "$this->telefone"

* @return string
*/

public function getTelefone ( )

return $this->telefone;

/**

* Define the value of "$this->telefone"

* @return void

*/

public function setTelefone ( $telefone )

$this->telefone = $telefone;

?>

Deve ser criada uma classe do mesmo tipo para a tabela ‘conta’. Não colocarei
o código aqui, para evitar de prolongar o texto demais com código.
Aconselho ao leitor, criar a classe da tabela ‘conta’ manualmente, para pegar a prática
do funcionamento da classe, e memorizar o seu layout.
Agora que as classes estão criadas, vamos partir para a criação das classes
DAO, pois sem elas, as classes VO nos são inúteis.

3. A classe DAO (Data Access Object)


As classes DAO são as responsáveis por realizar o acesso aos dados, em nossa
base de dados. Normalmente, as classes DAO podem ser do tipo Singleton, pois
não a necessidade de se manter mais de uma instancia da mesma, já que os dados
serão todos armazenados nas classes VO. Caso não esteja familiarizado com o
conceito de Singleton, recomendo que dê uma pesquisada no assunto, pois vale
bastante a pena.
Nesse texto, criarei as classes DAO sem utilizar da pattern Singleton, para
facilitar a visualização do funcionamento, para quem não conhece esse pattern.
O DAO que irei demonstrar, terá apenas alguns métodos básicos de busca, e
também um método para inserir registros, um para atualizar e um para apagar.
Você não precisa limitar sua classe DAO a apenas esses métodos, podendo criar
métodos de busca que lhe sejam mais úteis.
Vejamos então:

<?php
class ClienteDAO {

/**

* Método que recebe um objeto do tipo ClienteVO

* e insere seus valores na base de dados

* @param $objVo ClienteVO

*/

public function insert( ClienteVO $objVo )

$values = array(

addslashes( $objVo->getNome( ) ),

addslashes( $objVo->getSobrenome( ) ),

addslashes( $objVo->getEndereco( ) ),

addslashes( $objVo->getTelefone( ) )

);

$sql = sprintf('insert into cliente (nome, sobrenome,


endereco,

telefone) values( "%s","%s","%s","%s" )',

addslashes( $objVo->getNome( ) ),

addslashes( $objVo->getSobrenome( ) ),

addslashes( $objVo->getEndereco( ) ),

addslashes( $objVo->getTelefone( ) )

);

mysql_query( $sql );

$objVo->setId_cliente( mysql_insert_id( ) );

return $objVo;

/**

* Método que retorna todos os registros da tabela


* em um array de objetos VO

* @return array Array com objetos VO

*/

public function getAll( )

$objVo = new ClienteVO( );

$return = array( );

$sql = 'select * from cliente';

$resultado = mysql_query( $sql );

while( $rs = mysql_fetch_array( $resultado ) ) {

$objVo->setId_cliente( stripslashes( $rs['id_cliente']


) );

$objVo->setNome( stripslashes( $rs['nome'] ) );

$objVo->setSobrenome( stripslashes( $rs['sobrenome'] )


);

$objVo->setEndereco( stripslashes( $rs['endereco'] )


);

$objVo->setTelefone( stripslashes( $rs['telefone'] )


);

$return[] = clone $objVo;

return $return;

/**

* Retorna o objVo, referente ao valor de id especificado

* para o campo de chave primária da tabela


*

* @param $id int Valor do campo de chave primária

* @return ClienteVO Objeto VO com os dados referentes ao


registro

*/

public function getById( $id )

$objVo = new ClienteVO( );

$sql = sprintf( 'select * from cliente where id_cliente =


"%s"',

$id

);

$resultado = mysql_query( $sql );

while ( $rs = mysql_fetch_array( $resultado ) ) {

$objVo->setId_cliente( stripslashes( $rs['id_cliente']


) );

$objVo->setNome( stripslashes( $rs['nome'] ) );

$objVo->setSobrenome( stripslashes( $rs['sobrenome'] )


);

$objVo->setEndereco( stripslashes( $rs['endereco'] )


);

$objVo->setTelefone( stripslashes( $rs['telefone'] )


);

$return = clone $objVo;

return $return;

public function update( ClienteVO $objVo )

{
if ( !$objVo->getId_cliente( ) )

throw new Exception( 'Valor da chave primária


inválido' );

$sql = sprintf('update cliente set nome="%s",


sobrenome="%s",

endereco="%s", telefone="%s"

where id_cliente = "%s" ',

addslashes( $objVo->getNome( ) ),

addslashes( $objVo->getSobrenome( ) ),

addslashes( $objVo->getEndereco( ) ),

addslashes( $objVo->getTelefone( ) )

);

mysql_query( $sql );

public function delete( ClienteVO $objVo )

if ( $objVo->getId_cliente( ) == null )

throw new Exception('Valor da chave primária


inválido.');

$sql = sprintf('delete from cliente where id_cliente =


"%s"',

$objVo->getId_cliente( )

);

mysql_query( $sql );

public function save( ClienteVO &$objVo )

{
if ( $objVo->getId_cliente( ) !== null ) {

$this->update( $objVo );

} else {

$this->insert( $objVo );

?>

Nessa classe DAO, voce pode criar por exemplo um método de busca que receba um
objeto VO como parametro, ou um método que receba um nome de campo e um valor,
ou que receba um valor para limit na query, então use a imaginação quando for
criar os métodos que lhe forem ser úteis.
Podemos ver que, as queries estão todas nesse arquivo, então quando existir a
necessidade de utilizar um novo SGDB por exemplo, basta escrever as classes
DAO para esse novo SGDB, e o sistema deverá funcionar normalmente.
A seguir, veremos como utilizar as classes DAO/VO, em um exemplo bastante
simples.

4. Utilização
Tendo os DAOs e VOs criados, podemos utiliza-los de maneiras diversas. No
exemplo que montei acima, utilizei as funções de mysql diretamente no DAO, sem
estabelecer nenhuma conexão, pois assumi que a conexao será inicializada no
começo da execução do script. Caso o leitor deseje, pode criar uma forma de
inicializar a conexão, ao instanciar a classe DAO por exemplo.
Irei criar agora então, um simples formulário para cadastro de clientes, que
faz um submit para a própria página, e utiliza método POST.

<?phpif( isset($_POST['enviar']) ) {

// Conectar na base de dados

mysql_connect('localhost','root','');

mysql_select_db('daoTutorial');

// Incluir classe VO

include_once('clientevo.class.php');

// Incluir classe DAO

include_once('clientedao.class.php');

// Instanciamos o objeto VO, e o preenchemos

$cliente = new ClienteVO( );

$cliente->setNome( $_POST['nome'] );
$cliente->setSobrenome( $_POST['sobrenome'] );

$cliente->setTelefone( $_POST['telefone'] );

$cliente->setEndereco( $_POST['endereco'] );

$clienteDAO = new ClienteDAO( );

$cliente = $clienteDAO->insert( $cliente );

printf('Registro inserido com sucesso. O id do cliente é


%s<br><br>', $cliente->getId_cliente( ));

?>

<html>

<head>

<title>Exemplo uso de DAO</title>

</head>

<body>

<form method='POST'>

Nome: <input type='text' name='nome'><br>

Sobrenome: <input type='text' name='sobrenome'><br>

Endereço <input type='text' name='endereco'><br>

Telefone <input type='text' name='telefone'><br>

<input type='submit' value='Enviar' name='enviar'>

</form>

</body>

</html>

Acessando essa pagina, um formulário simples será apresentado. Quando


preenchido e submetido, o php irá checar se o botão enviar foi realmente
clicado, e caso sim, o objeto VO será preenchido com as informações que foram
passadas no formulário, e fará com que a classe DAO insira esses dados na base
de dados. O método insert da classe DAO retorna o objeto preenchido com os
dados, mais ovalor que recebeu como chave primária.
Para testar esse exemplo, não esqueça de colocar a classe VO e a classe DAO no
mesmo diretorio que se encontra o script, e arrumar as informações de conexão
com a base de dados.
Se deseja listar todos os registros da base de dados, pode criar um script de
listagem, com código semelhante ao que segue:
<?php // Conectar na base de dados

mysql_connect('localhost','root','');

mysql_select_db('daoTutorial');

// Incluir classe VO

include_once('clientevo.class.php');

// Incluir classe DAO

include_once('clientedao.class.php');

$clienteDAO = new ClienteDAO( );

// pega todos os clientes

$clientes = $clienteDAO->getAll( );

if( sizeof($clientes) > 0 ) { // verifica se há algum cliente


cadastrado

foreach( $clientes as $objVo ) {

printf('Nome: %s <br>',$objVo->getNome( ));

printf('Endereço: %s <br>', $objVo->getEndereco( ));

echo '<hr><br>';

?>

Os métodos de update e delete, exigem que o campo de chave primária esteja


preenchido para realizarem a sua ação, então fique atento a isso.

5. Considerações finais
Os exemplos apresentados, não dão muita importancia a segurança, embora
apresentem algumas boas práticas de programação, como procurar comentar o
código. Percebam que uma medida de segurança é tomada, ao usar o comando
addslashes nas queries SQL, para evitar injection, mas isso apenas pode não
ser o bastante. Uma filtragem dos dados mais bem feita com certeza se faz
necessária. Veja também que no método de update, não é feita nenhuma
verificação, para saber se o registro realmente existe na base de dados, antes
de tentar atualizar, o que pode causar problemas.
A pattern DAO pode ser combinada com outras patterns, para desenvolvimento de
sistemas de todos os portes, e é bastante interessante pois concentra toda a
relação com o banco de dados em um só lugar, e permite que o filtro das
informações que são enviadas, possa ser feito nesse mesmo lugar, facilitando a
tomada de medidas de segurança no desenvolvimento.

6. Bibliografia
Não consigo me lembrar exatamente que textos li para me aprofundar nesse
assunto, nem quais sites visitei, já que há algum tempo que utilizo isso. Devo
agradecer ao Carlos (que provavelmente nem vai ler esse texto), pois ele me
apresentou o conceito de DAO. Talvez possa encontrar algo no google, que possa
ter informações interessantes. Encontrei um texto no site da IBM,que parece
interessante:

http://www-128.ibm.com/developerworks/java/library/j-dao/

E um ‘texto’ bem esdruxulo da wikipedia

http://en.wikipedia.org/wiki/Data_Access_Object