O Doctrine é um mapeador objeto-relacional (ORM) para PHP, aos moldes do Hibernate para Java. Este ORM elimina a tarefa de escrever consultas SQL básicas, além de facilitar a conexão com o banco de dados, através da extensão PDO. O Doctrine permite que você crie seu model escrevendo suas classes em PHP (seguindo alguns padrões pré-definidos), através de arquivos YAML ou ele se encarrega da geração do model através das tabelas já criadas no banco de dados. Uma vez que o model está criado, você pode definir validadores para campos específicos da tabela realizando essas alterações na classe gerada que estende cada model. Dessa forma, seu model fica preservado, você apenas altera a classe estendida, tornando fácil desfazer modificações.

Instalação

Baixe a última versão estável no site do projeto. No momento em que escrevo este post, a última versão estável é a 1.2.3. A versão 2 escontra-se em fase beta. Quem sabe quando ela for lançada sai mais um post. Crie uma pasta para seu projeto no seu webserver e dentro dela crie uma pasta lib. Após criar a pasta, extraia o Doctrine para ela. A estrutura deverá ficar semelhante a esta:

seu_projeto/lib/Doctrine
seu_projeto/lib/vendor
seu_projeto/lib/Doctrine.php

Crie também uma pasta chamada “models” na raíz do projeto, dando permissão 777 a ela. Esta pasta irá conter o model da aplicação.

seu_projeto/models

Configuração

Crie um arquivo na pasta raíz do projeto chamado “bootstrap.php”. Esse arquivo irá conter as configurações e parâmetros de funcionamento do Doctrine. Abaixo está o arquivo que eu uso. Você pode definir outros parâmetros consultando a documentação oficial.

<?php // seu_projeto/bootstrap.php

require_once(dirname(__FILE__) . '/lib/Doctrine.php');

spl_autoload_register(array('Doctrine', 'autoload'));
spl_autoload_register(array('Doctrine_Core', 'modelsAutoload'));

$manager = Doctrine_Manager::getInstance();

// Configurações do banco de dados. O banco deve ser criado previamente.
$user = 'postgres';
$password = 'teste';
$host = 'localhost';
$dbname = 'testdoctrine';
$driver = 'pgsql';

$conn = Doctrine_Manager::connection($driver.'://'.$user.':'.$password.'@'.$host.'/'.$dbname);
$conn->setOption('username', $user);
$conn->setOption('password', $password);

$manager->setAttribute(Doctrine_Core::ATTR_EXPORT, Doctrine_Core::EXPORT_ALL);
$manager->setAttribute(Doctrine_Core::ATTR_MODEL_LOADING, Doctrine_Core::MODEL_LOADING_CONSERVATIVE);
$manager->setAttribute(Doctrine_Core::ATTR_AUTOLOAD_TABLE_CLASSES, true);
$manager->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL);

// Permite o override dos metodos do model.
$manager->setAttribute(Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE, true);

// Formato das sequências (uso para PostgreSQL)
$manager->setAttribute(Doctrine_Core::ATTR_SEQNAME_FORMAT, '%s_seq');

// Carrega os models da pasta especificada, no caso "models"
Doctrine_Core::loadModels('models');

Criação dos models

Com seu projeto configurado, o próximo passo é criar o model. Vou mostrar as 3 formas disponíveis.

Gerando as classes através das tabelas já existentes

Crie um arquivo chamado “test.php” que será usado neste e nos próximos passos. Deverá ter o seguinte conteúdo:

<?php
require_once('bootstrap.php');  

Agora, basta adicionar as linhas abaixo ao seu arquivo “test.php”. Comente-a após a geração, pois senão os models serão gerados novamente a cada execução.

<?php // seu_projeto/test.php
require_once('bootstrap.php');

Doctrine_Core::generateModelsFromDb('models', array('doctrine'), array(	  
  'generateTableClasses' => true  
));

Você pode usar como exemplo as tabelas abaixo:

CREATE TABLE cidade (
  id bigint NOT NULL,
  nome character(500) NOT NULL,
  uf character(2) NOT NULL
);

CREATE TABLE pessoa (
  id bigint NOT NULL,    
  nome character(500) NOT NULL,    
  data_nasc date,    
  id_cidade bigint
);

ALTER TABLE ONLY cidade ADD CONSTRAINT cidade_pkey PRIMARY KEY (id);
ALTER TABLE ONLY pessoa ADD CONSTRAINT pessoa_pkey PRIMARY KEY (id);

ALTER TABLE ONLY pessoa ADD CONSTRAINT pessoa_id_cidade_cidade_id FOREIGN KEY (id_cidade) REFERENCES cidade(id);

Gerando as classes através de um arquivo YAML

Um arquivo YAML (extensão .yml) é um arquivo semelhante a um arquivo XML e eu diria muito mais poderoso (minha opinião). Ao invés de tags, os dados são representados pela identação dos atributos e seus valores (o pessoal do Python ama isso). A identação deve ser feita com espaços e não com tabulações. Para mais informações, consulte a Wikipédia.

Esta forma permite representar seus models no arquivo YAML.

Se você ainda não tem classes definidas, crie o arquivo “schemas.yml” na raíz do projeto com o conteúdo abaixo:

Cidade:
  connection: 0
  tableName: cidade
  columns:
    id:
      fixed: false
      notnull: true
      primary: true
      autoincrement: true
      type: integer(8)
    nome:
      fixed: true
      notnull: true
      type: string(500)
    uf:
      fixed: true
      notnull: true
      type: string(2)
  relations:
    Pessoa:
      local: id
      foreign: id_cidade
      type: many
Pessoa:
  connection: 0
  tableName: pessoa
  columns:
    id:
      fixed: false
      notnull: true
      primary: true
      autoincrement: true
      type: integer(8)
    nome:
      fixed: true
      notnull: true
      type: string(500)
    data_nasc: date(25)
    id_cidade: integer(8)
  relations:
    Cidade:
      local: id_cidade
      foreign: id
      type: one

Caso você já tenha as classes definidas, basta remover o código de geração das classes do arquivo “test.php” e adicionar as linhas abaixo:

<?php // seu_projeto/test.php
require_once('bootstrap.php');
Doctrine_Core::generateYamlFromModels('schema.yml', 'models');

Após executar o test.php, você verá um arquivo chamado “schema.yml” na pasta raíz, com a definição do model. Crie agora um arquivo chamado “generate.php” com o código abaixo. Esse arquivo será responsável por remover as tabelas do banco de dados (se existirem) e recriá-las com base no arquivo “schema.yml”, gerando também as classes PHP. Portanto, muito cuidado, só execute quando for estritamente necessário, sob a pena de perder os dados do banco.

<?php // seu_projeto/generate.php
require_once('bootstrap.php');

//Remova as próximas 2 linhas caso não queira remover e criar seu banco a cada execução.
Doctrine_Core::dropDatabases();
Doctrine_Core::createDatabases();
  
Doctrine_Core::generateModelsFromYaml('schema.yml', 'models');
Doctrine_Core::createTablesFromModels('models');

Definindo manualmente suas classes PHP

Usarei como exemplo duas classes, Pessoa e Cidade, sendo que uma pessoa pertence a uma cidade. Basta criar dois arquivos na pasta “models”, Pessoa.php e Cidade.php, com o código abaixo:

<?php // seu_projeto/models/Cidade.php
class Cidade extends Doctrine_Record{
  public function setTableDefinition(){	  
    $this->hasColumn('id', 'integer', null, array(	  
      'fixed' => false,
      'notnull' => true,
      'primary' => true,
      'autoincrement' => true
    ));

    $this->hasColumn('nome', 'string', 500, array('fixed' => true, 'notnull' => true));
    $this->hasColumn('uf', 'string', 2, array('fixed' => true, 'notnull' =>; true));  
  }
}
<?php // seu_projeto/models/Pessoa.php
class Pessoa extends Doctrine_Record{
  public function setTableDefinition(){	  
    $this->hasColumn('id', 'integer', null, array(
      'fixed' => false,
      'notnull' => true,
      'primary' => true,
      'autoincrement' => true
    ));

    $this->hasColumn('nome', 'string', 500, array('fixed' => true, 'notnull' => true));
    $this->hasColumn('data_nasc', 'date');
    $this->hasColumn('id_cidade', 'integer');
  }

  public function setUp(){
    $this->hasOne('Cidade', array(
      'local' => 'id_cidade',
      'foreign' => 'id'
    ));
  }
}

Após a definição das classes, rode o arquivo “test.php” com a linha “Doctrine_Core::generateYamlFromModels(‘schema.yml’, ‘models’);”. Após rodar esse arquivo, execute o “generate.php”, que irá apagar o banco de dados, criá-lo novamente e criar as tabelas referentes as classes.

Realizando consultas

Com o model pronto, vamos realizar algumas consultas.

Inserindo pessoa com uma cidade associada a ela

<?php
$cidade = new Cidade();  
$cidade->nome = 'Marau';
$cidade->uf = 'RS';
$cidade->save();

$pessoa = new Pessoa();
$pessoa->nome = "Jonnas Fonini";
$pessoa->data_nasc = date('1990-04-12');
$pessoa->id_cidade = $cidade;
$pessoa->save();

Consultando informações de uma pessoa

<?php
$pessoa = Doctrine_Core::getTable('Pessoa')->find(1);  

echo 'Id: '.$pessoa->id.'<br />';
echo 'Nome: '.$pessoa->nome.'<br />';
echo 'Data Nasc.: '.$pessoa->data_nasc.'<br />';
echo 'Cidade: '.$pessoa->Cidade->nome;

Atualizando informações de uma pessoa

<?php
$pessoa = Doctrine_Core::getTable('Pessoa')->find(1);  
$pessoa->data_nasc = date('Y-m-d');
$pessoa->save();

Removendo uma pessoa

<?php
$pessoa = Doctrine_Core::getTable('Pessoa')->find(1);  
$pessoa->delete();

Download

Clique aqui para baixar o projeto já pronto. Mude as configurações do banco de dados no arquivo “bootstrap.php”.

Conclusão

O Doctrine facilita muito a manipulação do banco de dados em PHP, poupando a você o trabalho de escrever consultas SQL. Incremente ainda mais seus estudos estudando o framework Symfony, um dos mais completos da atualizade e que faz uso do Doctrine. Pretendo criar mais posts sobre o Doctrine em breve.