2
respostas

Ajuda para desacoplar banco de dados da camada de apresentação e separar camada de modelo e camada de persistência

Caros,

Gostaria de abrir este tópico para juntos conseguirmos elaborar uma forma mais padronizada de estruturar nosso código de acordo com as melhores práticas. Colocarei aqui uma sugestão. A ideia é separar totalmente a camada modelo da camada de persistência e desacoplar a camada de apresentação do banco de dados .

É comum o nome do campo no banco de dados não ser igual ao nome do atributo/propriedade da nossa classe do modelo. Geralmente, na primeira, as palavras são separadas por underline e, na segunda, os nomes são digitados em camel case. Ex.: categoria_curso_id e categoriaCursoId.

O meu problema é que não sei se existe alguma forma de mapear os campos das tabelas do banco de dados com os atributos da respectiva classe. Pesquisei sobre o método fetch() usando a opção PDO::FETCH_CLASS, mas se os nomes dos atributos forem diferentes, o PHP não "encaixa" os valores respectivos.

Segue minha proposta: (o que eu quero é eliminar os métodos preencheObjeto() e preencheColecao() fazendo, se possível, que o próprio fetch() preencha os valores no objeto ou numa coleção).

A classe CategoriaCurso

<?php

    class CategoriaCurso {

        private $categoriaCursoId;
        private $nome;

        public function getCategoriaCursoId() {
            return $this->categoriaCursoId;
        }
        public function setCategoriaCursoId($categoriaCursoId) {
            $this->categoriaCursoId = $categoriaCursoId;
        }

        public function getNome() {
            return $this->nome;
        }
        public function setNome($nome) {
            $this->nome = $nome;
        }
    }
?>

A classe CategoriaCursoDAO

<?php

require_once 'global.php';

    class CategoriaCursoDAO {

        private function preencheObjeto($linha) {
            $obj = new CategoriaCurso();
            $obj->setCategoriaCursoId($linha['categoria_curso_id']);
            $obj->setNome($linha['nome']);

            return $obj;
        }

        private function preencheColecao($lista) {

            $col = array();
            $i = 0;

            foreach ($lista as $linha) {
                $col[$i] =  $this->preencheObjeto($linha);
                $i++;
            }

            return $col;
        }

        public function findById($id) {

            $query = "SELECT categoria_curso_id, nome " . 
                     "  FROM categoria_curso " . 
                     " WHERE categoria_curso_id = " . $id;

            $resultado = Conexao::getConexao()->query($query);

            $lista = $resultado->fetchAll();
            foreach ($lista as $linha) {
                return $this->preencheObjeto($linha);
            }
        }

        public function findAll() {

            //throw new Exception('Erro ao tentar carregar todas as categorias.');

            $query = "SELECT categoria_curso_id, nome FROM categoria_curso";
            $resultado = Conexao::getConexao()->query($query);
            $lista = $resultado->fetchAll();

            return $this->preencheColecao($lista);
        }

        public function save($categoriaCurso) {

            if ($categoriaCurso->getCategoriaCursoId() == 0) {
                $query = "INSERT INTO categoria_curso (nome) VALUES ('" . $categoriaCurso->getNome() . "')";
            }
            else {
                $query = "UPDATE categoria_curso SET " .
                               " nome = '" . $categoriaCurso->getNome() . "' " .  
                         " WHERE categoria_curso_id = " . $categoriaCurso->getCategoriaCursoId();
            }

            Conexao::getConexao()->exec($query);
        }

        public function delete($id) {

            $query = "DELETE FROM categoria_curso " . 
                     " WHERE categoria_curso_id = " . $id;

            Conexao::getConexao()->exec($query);
        }
}
?>

E na camada de apresentação que não precisa conhecer a estrutura do banco de dados:

... código omitido ...

try {
    $dao = new CategoriaCursoDAO();
    $lista = $dao->findAll();
}
catch(Exception $e) {
    Erro::trataErro($e);
}

... código omitido ...

    <?php foreach ($lista as $obj): ?>
        <tr>
            <td><a href="/categorias-detalhe.php" class="btn btn-link"><?php echo $obj->getCategoriaCursoId() ?></a></td>
            <td><a href="/categorias-detalhe.php" class="btn btn-link"><?php echo $obj->getNome() ?></a></td>
            <td><a href="/categoria-curso-editar.php?id=<?php echo $obj->getCategoriaCursoId() ?>" class="btn btn-info">Editar</a></td>
            <td><a href="/categoria-curso-excluir-post.php?id=<?php echo $obj->getCategoriaCursoId() ?>" class="btn btn-danger">Excluir</a></td>
        </tr>
    <?php endforeach ?>
2 respostas

Oi Franco, tudo bom?

Essa camada de isolamento entre o modelo e o banco na qual a gente puxa os dados do banco e cria instancias de objetos é o que chamamos de ORM. Uma ferramenta que mapeia os objetos para o mundo relacional. Resumidamente, você consegue indicar quais classes serão tabelas no banco e quais atributos dessa classe serão colunas.

Normalmente, todo ORM, implementa um padrão utilizando a nomenclatura da própria classe/atributos nas tabelas/colunas. Porém, todos nos dão uma forma de indicar um nome customizado (normalmente por anotações).

Em PHP, a gente tem dois ORMs o Eloquent do laravel e o Doctrine que não está amarrado a nenhum framework e foi desenvolvido baseado na especificação do Java para persistencia (JPA).

Ambos utilizam o PDO como forma de conexão e automatizam todo o processo de construção de instancias e tanto no banco quanto na memória =)

Abraço!

Show! Vou pesquisar!