|
Nota: Artigo publicado originalmente no portal PHP Brasil em 2007 e devido a tamanha
repercussão resolvi disponibilizá-lo também aqui no site.
Neste artigo irei falar resumidamente sobre mapeamento objeto-relacional que consiste em uma
abordagem que permite a construção de sistemas utilizando o paradigma da orientação a objetos com a persistência destes objetos em bancos de dados relacionais como o Mysql.
Utilizando-se de técnicas e estratégias específicas, é possível mapear classes com seus atributos e associações para o modelo relacional.
Os bancos de dados orientados a objeto são mais adequados para a persistência de objetos manipulados por aplicações orientadas a objeto, devido à utilização do mesmo paradigma. Porém a indisponibilidade atual destes bancos de dados, seja devido ao custo, diversidade ou amadurecimento do mercado, faz com que seja necessária a busca de alternativas para a realização da persistência.
Desenvolvendo projetos desta maneira você estará contribuindo para a reutilização do seu código em diferentes áreas do seu sistema e até mesmo de projetos futuros, sem falar da legibilidade e do aspecto profissional agregados ao seu código.
Mais como seria esse mapeamento na prática?
Suponha que tenhamos as seguintes tabelas do DER abaixo no nosso banco de dados:

A partir delas iremos construir nossas classes, lembrando que a ordem não importa, conheço
algumas pessoas que costumam fazer a modelagem do banco de dados primeiro, depois as tabelas
e outras que modelam primeiro seus objetos para somente então, partir para a construção do DER.
Abaixo está o diagrama de classes que representa as tabelas do DER:
Obs.: Sinais de visibilidade de atributos e métodos utilizados seguindo os padrões da UML
Onde o sinal de "+" => private; "-" => public; "#" => protected

No diagrama de classes, cada tabela do banco de dados foi mapeada para uma classe, onde o nome da classe é o mesmo
nome da tabela só que no singular e sem o prefixo.
Os atributos possuem visibilidade private, ou seja, somente os métodos internos a classe é
que poderão acessá-los diretamente, para objetos externos acessarem estes atributos, deve-se utilizar as propriedades modificadoras, os famosos get e set, se o atributo for somente de leitura você pode omitir a propriedade set.
O método __construct pode ser utilizado para setar os valores default de cada atributo.
Relacionamentos:
No DER temos o relacionamento 1 para n indicando que uma categoria pode conter nenhum ou vários clientes, porém um cliente só está ligado a uma categoria. Para construir o relacionamento inserimos a chave estrangeira cli_idCategoria na tabela de clientes ligando-a com a chave primária cat_id da tabela de categorias. No diagrama de classes também temos os atributos cli_idCategoria e cat_id, só que como o objeto Cliente é responsável por conhecer a sua categoria, criamos o atributo objCategoria na classe Cliente, desta forma, assim que utilizarmos o método $objCliente->carregar(), este terá que chamar o método $this->objCategoria->carregar(). Estes métodos devem recuperar os dados de um determinado registro no banco e setá-los em cada atributo do objeto.
Para que possamos identificar qual registro deve ser recuperado, setamos o id do objeto:

A implementação dos métodos CRUD (Create, Read, Update e Delete), ou seja, cadastrar, carregar, alterar e excluir, vai depender de quantas camadas sua aplicação estará dividida.
O ideal é que nas classes Cliente e Categoria você só realize operações envolvidas com a camada de negócios, fazendo com que estes métodos chamem outros métodos de uma camada de nível mais baixo, como por exemplo DaoCliente::carregar() e DaoCategoria::carregar(). (Dao vem de Data Access Object)
Estas classes sim é que poderiam ter métodos com cláusulas SQL como SELECT, INSERT, UPDATE E DELETE.
Da mesma forma, você pode criar classes de nível mais alto para gerenciar a camada de apresentação, nestas classes você irá tratar códigos HTML, Javascript, CSS e etc.
Codificando desta forma seus objetos ficarão muito mais reutilizáveis!!
Então chega de conversa e mãos a obra! Na próxima página postei o código fonte das classes.
<?php
class ClienteException extends Exception { }
/** * Classe responsável pelo gerenciamento das informações de um cliente * * @package MeuSistema * @subpackage Clientes * @author Diego Botelho <
Este endereço de e-mail está protegido contra spambots. Você deve habilitar o JavaScript para visualizá-lo.
> * @link http://www.diegobotelho.com.br * @date 2007-01-30 21:07:00 */ class Cliente { /** * @var int * @access private */ private $cli_id; /** * * @var int * @access private */ private $cli_idCategoria; /** * @var object * @access private */ private $objIdCategoria; /** * @var string * @access private */ private $cli_nome;
/** * @var string * @access private */ private $cli_cpf; /** * @var string * @access private */ private $cli_email; //---------------------------------------------------------------------- /** * Seta o valor do atributo $cli_id * @param int $intId * @access public */ public function setId($intId) { $this->cli_id = $intId; } /** * Obtém o valor do atributo $cli_id * @access public */ public function getId() { return $this->cli_id; } //... A mesma coisa para os outros atributos //---------------------------------------------------------------------- /** * Construtor da classe * @access public */ public function __construct() { $this->setId(""); $this->setIdCategoria(""); $this->setCategoria(new Categoria); $this->setNome(""); $this->setCpf(""); $this->setEmail(""); } /** * Destrutor da classe * @access public */ public function __destruct(){} /** * Cadastra um novo cliente * @access public */ public function cadastrar() { try { DaoCliente::insert($this); } catch(Exception $e) { throw new ClienteException($e->getMessage()); } } /** * Altera um cliente existente * @access public */ public function alterar() { try { DaoCliente::update($this); } catch(Exception $e) { throw new ClienteException($e->getMessage()); } }
/** * Exclui um cliente existente * @access public */ public function excluir() { try { DaoCliente::delete($this); } catch(Exception $e) { throw new ClienteException($e->getMessage()); } }
/** * Recupera um cliente armazenado em meio persistente * @access public */ public function carregar() { try { DaoCliente::load($this); // Carregando a categoria do cliente DaoCategoria::setId($this->idCategoria); DaoCategoria::load($this->objCategoria); } catch(Exception $e { throw new ClienteException($e->getMessage()); } } } ?>
<?php class CategoriaException extends Exception { }
/** * Classe responsável pelo gerenciamento das informações de uma categoria * * @package MeuSistema * @subpackage Categorias * @author Diego Botelho <
Este endereço de e-mail está protegido contra spambots. Você deve habilitar o JavaScript para visualizá-lo.
> * @link http://www.diegobotelho.com.br * @date 2007-01-30 21:07:00 */ class Categoria { /** * @var int * @access private */ private $cat_id; /** * * @var string * @access private */ private $cat_nome; //---------------------------------------------------------------------- /** * Seta o valor do atributo $cat_id * @param int $intId * @access public */ public function setId($intId) { $this->cat_id = $intId; } /** * Obtém o valor do atributo $cat_id * @access public */ public function getId() { return $this->cat_id; } /** * Seta o valor do atributo $cat_nome * @param int $strId * @access public */ public function setNome($strNome) { $this->cat_nome = $strNome; } /** * Obtém o valor do atributo $cat_nome * @access public */ public function getNome() { return $this->cat_nome; } //---------------------------------------------------------------------- /** * Construtor da classe * @access public */ public function __construct() { $this->setId(""); $this->setNome(""); } /** * Destrutor da classe * @access public */ public function __destruct() { } /** * * Cadastra um nova categoria * @access public */ public function cadastrar() { try { DaoCategoria::insert($this); } catch(Exception $e) { throw new CategoriaException($e->getMessage()); } } /** * Altera uma categoria existente * @access public */ public function alterar() { try { DaoCategoria::update($this); } catch(Exception $e) { throw new CategoriaException($e->getMessage()); } }
/** * Exclui uma categoria existente * @access public */ public function excluir() { try { DaoCategoria::delete($this); } catch(Exception $e) { throw new CategoriaException($e->getMessage()); } }
/** * Recupera uma categoria armazenado em meio persistente * @access public */ public function carregar() { try { DaoCategoria::load($this); } catch(Exception $e) { throw new CategoriaException($e->getMessage()); } } /** * Retorna uma lista com as categorias cadastradas * @access public */ public function listar() { try { return DaoCategoria::collection($this); } catch(Exception $e) { throw new CategoriaException($e->getMessage()); } } } ?>
Bom é isso, apesar de ser bem superficial, espero que tenha ajudado.
Vale a pena programar orientado a objetos com PHP5!
Um abraço e até o próximo artigo!
|