Doctrine 2- Mapeando seu banco de dados

doctrine-2-mapeando-seu-banco-de-dados

 

Hoje eu me sinto honrado de apresentar para vocês o Doctrine. Quero, primeiramente, agradecer ao amigo Cleber Alves pela dica de post, afinal segundo ele próprio, há pouco conteúdo na internet sobre o assunto, e arrisco dizer que se pesquisarmos apenas por tutoriais em português, esse número fica ainda mais reduzido.

Bom, então o que é o Doctrine? O Doctrine nada mais é do que um framework para mapeamento de banco de dados relacionais (Mapeamento Objeto-Relacional, da sigla em inglês, ORM). Com o ORM, as tabelas no banco de dados são representadas através de classes, e todo o seu uso se dá através da orientação à objetos. O Doctrine trouxe para o PHP a ideia que o Hibernate implantou para Java.

(Antes de dar início, aviso que todo o código utilizado aqui no tutorial está disponível no meu Github. Acesse ou clone o repositório para tê-lo em sua máquina. Todos os arquivos criados e utilizados no tutorial estão lá, inclusive o dump do banco de dados criado)

 

Vamos começar então? O início de tudo é ir atrás do framework e baixá-lo em sua máquina. Garanta que a versão do seu PHP seja 5.3 ou maior, caso contrário, não poderá continuar. Para facilitar nossa vida, há o Composer (o que é o Composer? Isso é assunto para um outro post). Para instalá-lo, dê uma olhada nesse link. Se já o tiver em sua máquina, continue.
Após isso, crie um arquivo “composer.json” na raiz do seu diretório de teste, com o seguinte código:


 

// composer.json
{
    "require": {
        "doctrine/orm": "2.*",
        "symfony/yaml": "2.*"
    },
    "autoload": {
        "psr-0": {"": "src/"}
    }
}

 

Após salvar este arquivo, rode pelo shell (se você estiver usando Windows, sempre que ler “shell” considere “PowerShell” ok?) e rode o comando:

 

php composer.phar install

 

Isto garante que você utilizará a última versão disponível do Doctrine, as dependências do Synfony usadas por ele e também um autoloader para você não se preocupar com carregamento de classes.

 

Crie agora, dentro do seu diretório do projeto, uma pastinha chamada “src”. É aí que vamos colocar nossas entidades. O Doctrine chama de “Entidade” as tabelas mapeadas através de classes. O carregamento do Doctrine e a integração à sua aplicação se dará através do arquivo “bootstrap.php” (nomenclatura passada pela documentação do Doctrine, é alterável se desejar.) Comentei as linhas explicando as funções principais de cada parte do arquivo para facilitar o entendimento.

 

// bootstrap.php

//vamos configurar a chamada ao Entity Manager, o mais importante do Doctrine

// o Autoload é responsável por carregar as classes sem necessidade de incluí-las previamente
require_once "vendor/autoload.php";

// o Doctrine utiliza namespaces em sua estrutura, por isto estes uses
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;

//onde irão ficar as entidades do projeto? Defina o caminho aqui
$entidades = array("src/");
$isDevMode = true;

// configurações de conexão. Coloque aqui os seus dados
$dbParams = array(
    'driver'   =--> 'pdo_mysql',
    'user'     => 'root',
    'password' => '123456',
    'dbname'   => 'doctrinedb',
);

//setando as configurações definidas anteriormente
$config = Setup::createAnnotationMetadataConfiguration($entidades, $isDevMode);

//criando o Entity Manager com base nas configurações de dev e banco de dados
$entityManager = EntityManager::create($dbParams, $config);

 

Vamos usar um exemplo bem simples para facilitar o aprendizado. Considere a situação em que temos uma loja que vende produtos, e estes produtos estão divididos em categorias. São duas tabelas no banco de dados, sendo que há uma ligação entre elas. O script SQL para a criação dessas tabelas já populadas você encontra para download no meu repositório do GitHub , juntamente com todo este tutorial.

Veja a imagem abaixo para ter uma ideia clara de como é o nosso pequeno banco de testes.

desenho-database

 

Vamos mapear agora estas entidades. No Doctrine, entidades são as classes criadas para mapear as suas tabelas no banco de dados. O Doctrine 2 utiliza “Annotations”, que são anotações (comentários) que ao mesmo tempo servem para configurar determinada classe, função ou atributos. Veja o exemplo abaixo da tabela “Categoria” mapeada no padrão do Doctrine 2 (o arquivo deve ser criado DENTRO da pasta “src”, que definimos no arquivo bootstrap.php como diretório onde ficariam nossas entidades):

 

/**
 *
 * @Entity
 * @Table(name="categoria")
 */
class Categoria
{
    /**
     * @Id
     * @GeneratedValue(strategy="AUTO")
     * @Column(type="integer", name="idCategoria")
     */
    protected $id;

    /**
     * @Column(type="string", name="nomeCategoria")
     */
    protected $nome;

    public function getId()
    {
        return $this--->id;
    }

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

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

}

 

Cada atributo da classe em questão faz referência à uma coluna na tabela. Deve-se especificar alguns dados destas colunas para o Doctrine mapeá-las corretamente. Leia abaixo a explicação:

 

Linha 3: Annotation que define a classe como uma Entidade.

Linha 4: Onde você define o nome da tabela a ser mapeada.

Linha 6: Nome da classe. Para o autoload, é obrigatório o nome do arquivo ser IGUAL ao nome da classe, caso contrário o carregamento automático não funciona!

Linha 13: Define-se o atributo referente à primeira coluna da tabela, neste caso, o Id da Categoria.

Linha 9: Annotation @Id, obrigatório para chave primária da tabela.

Linha 10: Annotation @GeneratedValue, identifica o método de geração do Id, e aqui temos um auto incremento, portanto, define-se como “AUTO”.

Linha 11: Annotation @Column, define-se aqui vários parâmetros da coluna. No caso, definimos apenas o tipo e o nome da coluna.

 

O annotation @Column deve estar presente em todos os atributos da classe, representando fielmente suas propriedades no banco de dados. Veja o que pode ser definido neste annotation lendo a documentação do Doctrine

A partir da linha 19, definimos os métodos set e get para os atributos. Eles serão necessários para acessarmos os dados das colunas quando estivemos trabalhando sobre a entidade. Mais adiante (em outro post, possivelmente), irei falar sobre os métodos mágicos que facilitam este trabalho. No caso, temos apenas 2 atributos, mas imagine uma tabela com mais de 10 colunas, que chato seria ficar definindo set e get para cada um dos atributos. Os setters e getters mágicos resolveriam este problema.

 

Vamos mapear agora a outra tabela, a de Produtos. Esta é um pouco diferente, uma vez que a partir dela temos uma ligação com a tabela Categoria, já mapeada. Crie o arquivo “Produto.php”, também dentro da pasta “src”. Vejamos o código a seguir:

 

/**
 * Produto
 *
 * @Entity
 * @Table(name="produto")
 */
class Produto
{
    /**
     * @Id
     * @Column(type="integer", name="idProduto")
     * @GeneratedValue(strategy="AUTO")
     */
    protected $id;
    /**
     * @Column(type="string", name="nomeProduto")
     */
    protected $nome;

    /**
     * @ManyToOne(targetEntity="Categoria")
     * @JoinColumn(name="idCategoria", referencedColumnName="idCategoria")
     */
    protected $categoria;

    public function getId() {
        return $this->id;
    }

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

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

    public function getCategoria() {
        return $this->categoria;
    }

    public function setCategoria($categoria) {
        $this->categoria = $categoria;
    }
}

 

O que difere este arquivo do outro é o annotation sobre o atributo “categoria”. De resto tudo está seguindo o mesmo padrão explicado anteriormente. Neste caso, temos a ligação da coluna “idCategoria” com a chave primária da entidade Categoria. Temos aqui a relação “Muitos para Um”, já que muitos produtos podem pertencer à mesma categoria. Vamos entender os novos annotations então:

 

Linha 21: @ManyToOne, o nome já diz, Muitos para Um. Dentro dele definimos a “targetEntity”, ou seja, o alvo desta ligação. A entidade ligada é a “Categoria”.

Linha 22: @JoinColumn, define as colunas que são ligadas entre as tabelas. Em “name”, define-se o nome da coluna na entidade atual. Em “referencedColumnName“, define-se o nome da coluna na entidade relacionada.

 

Neste exemplo, os nomes das colunas são iguais nas duas tabelas, mas tome cuidado para não confundir os parâmetros quando for mapear tabelas que possuem ligações através de colunas com nomes diferentes.

Obs.: Omiti a função “setId()” em ambas as entidades porque não iria utilizá-la em hipótese alguma, já que este ID é gerado automaticamente pelo banco de dados.

 

Pronto, você já fez o mais difícil. A parte de mapeamento do Doctrine é a que mais dá dor de cabeça, e até aqui foi tranquilo, não? Tá certo que nosso exemplo é didático e não envolve a complexidade de um caso real, mas para entender o funcionamento da ferramenta é o suficiente.

Vou dividir o post em duas partes, pois estou vendo que este aqui irá ficar muito longo. Encerramos por aqui o mapeamento das tabelas, e no próximo post você irá ver como se utilizam estas tabelas já mapeadas.

 

Quer continuar agora mesmo? Sem problemas, leia a parte dois, Doctrine 2 – Trabalhando com entidades mapeadas.

 


Publicado em Banco de Dados, Desenvolvimento, Tecnologia
  • noob

    cara véio, muito bem explicado, vc merece aquela coca bem gelada rsrs

    • Ricardo Brusch

      Fico feliz que esse artigo tenha te ajudado “noob”, huauhauhahuahua

      Temos pouco conteúdo sobre essas tecnologias em português. Normalmente quando achamos algo é em inglês, e mesmo sabendo que é obrigatório dominar essa língua na nossa área, as vezes sinto falta de um bom tutorial em PT-BR. O problema é que quando encontramos algo, normalmente é copiado dos gringos e traduzido com o Google, o que fica uma m*rda, por isso resolvi eu mesmo escrever, da maneira mais simples e clara possível, um pouco sobre elas. O resultado são os diversos tutoriais que tu encontra por aqui. Fica a vontade pra navegar, cara!

      Obrigado pelo comentário!

  • Rafael Capretz

    Man, como vc fez pra gerar essas classes de entidade? pq aqui eu tenho meu bd criado ja e ele gera só o YML.. como faço pra gerar as classes pra poder gerar os metadados?

    • Ricardo Brusch

      E aí Rafael, blz? Cara, eu fiz na mão essas classes aí, não utilizei o CLI do Doctrine não. Dá uma olhada no link (http://docs.doctrine-project.org/en/2.0.x/reference/tools.html#entity-generation), eles mesmos aconselham a utilizar o mínimo possível o EntityGenerator… uhauhaauhuh vai entender… “Eu te dou a ferramenta, mas nem usa muito que não é bacana…”

      De qualquer forma, talvez a documentação possa te ajudar no teu propósito, boa sorte aí e sucesso!

      • Rafael Capretz

        Obrigado pela resposta Ricardo, eu consegui aqui com um amigo.. da pra gerar sim.. mas confesso que o Composer instalou tudo bem desorganizado aqui.. deu bastante trabalho pra organizar tudo e acertar os caminhos.. eles poderiam melhorar a documentação também. De qualquer forma eu to fazendo aqui uma e quando estiver top eu disponibilizo em algum lugar. Obrigado mais uma vez e sucesso pra você também, Ricardo!

  • Hackaid Tecnologia

    Rafael realmente é uma raridade encontrar algo sobre ele em pt. Tenho uma dúvida, se puder me ajudar. Posso usar o doctrine em qualquer projeto php ou tem que ser em um framework como Symfony, Zend… Pergunto isso porque se eu tiver um projeto feito por mim em PHP OO, será suficiente para que as entidades sejam reconhecidas pelo Doctrine? Obrigado e forte abraço!

    • Ricardo Brusch

      Olá amigo, desculpe a demora em responder… O Doctrine é totalmente independente do framework, você pode utilizá-lo em qualquer projeto PHP com ou sem frameworks envolvidos. Forte abraço! Att.

  • diegobezerra

    Otimo artigo, exatamente oque eu estava em duvida.

  • Rafael Andrade

    Cara, muito bom seu artigo. Realmente é dificil achar conteúdo de qualidade em pt-br sobre o Doctrine.

Volte Sempre!
Meus artigos te ajudaram de alguma forma e você não sabe como me agradecer? Que tal me pagar uma Coca-Cola bem gelada?

Sobre o autor

Me chamo Ricardo Brusch, sou programador e desenvolvedor de sistemas para internet. Também sou aspirante a escritor, e você pode ler alguns de meus contos malucos em contos.ricardobrusch.com.br.
Parceiros





Publicidade