Back-End

14 ago, 2012

Como realizar a integração do CodeIgniter com Doctrine 2

Publicidade

Existem alguns artigos e até vídeos sobre integração do CodeIgniter e Doctrine, mas a maioria trata das versões antigas desses frameworks. O Doctrine já está em sua versão 2 e pouco material se acha na Internet sobre a integração entre eles. Então vou mostrar aqui como fazer esta integração de forma que funcione tanto a utilização no código PHP como a linha de comando do Doctrine.

Primeiros passos

Primeiro, faça o download do CodeIgniter e do Doctrine 2.2.2 (utilizado neste artigo) e prepare o ambiente. Imagino que os leitores já saibam preparar o ambiente da sua maneira, de toda forma vou publicar alguns passos básicos que eu costumo fazer nas minhas aplicações.

Eu estou utilizando o XAMPP 1.7, então, dentro da pasta htdocs criei uma outra pasta chamada “doctrine”, que será a raíz deste projeto. Nesta pasta, criei um arquivo .htaccess (com o objetivo de remover o “index.php” da URL) com o seguinte código:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

E alterei o arquivo “\doctrine\application\config\config.php” na linha 29:

$config['index_page'] = '';

Criei também um banco MySQL chamado “doctrine” e configurei o arquivo
“\doctrine\application\config\database.php” da seguinte maneira:

$db['default']['hostname'] = 'localhost';
$db['default']['username'] = 'root';
$db['default']['password'] = '';
$db['default']['database'] = 'doctrine';
$db['default']['dbdriver'] = 'mysql';

Finalmente, testei o projeto para confirmar que está tudo certo: http://localhost/doctrine/.

A integração

Agora vem a parte interessante: a integração. Para isso é importante definir alguns conceitos: na documentação do Doctrine está escrito para colocar a biblioteca do Doctrine na pasta library, dentro de System. Eu fiz um pouco diferente, pois não tenho o hábito de fazer alterações no core do framework (não acho que seja interessante listas minhas razões para isso aqui). Também não concordo em manter na pasta library dentro de application, pois esta pasta se destina a bibliotecas escritas por você, para o seu sistema.

Então, qual o melhor lugar para manter os arquivos do Doctrine? Na minha opinião, na pasta “third_party”, dentro de application, pois trata-se de uma biblioteca de terceiros e é para isso que se destina esta pasta.

Então, eu criei uma pasta chamada “DoctrineORM-2.2.2” dentro de third_party e dentro dela uma outra pasta chamada library.

Dentro de download, no Doctrine, existe duas pastas: uma chamada “bin”, onde ficam os arquivos necessários para executarmos via linha de comando – que descompactei diretamente dentro de “DoctrineORM-2.2.2” – e outra chamada Doctrine, que descompactei dentro da pasta library que criamos.

A estrutura ficou da seguinte maneira:

Então vamos fazer as devidas configurações no Doctrine: o primeiro passo é configurar o boostrap do Doctrine, que será responsável pela sua inicialização. Para isso, criamos um arquivo chamado Doctrine.php dentro da pasta library que criamos em “third_party”
(\htdocs\doctrine\application\third_party\DoctrineORM-2.2.2\libraries\Doctrine.php).

Este arquivo deve conter o seguinte código:

<?php
use Doctrine\Common\ClassLoader,
 Doctrine\ORM\Configuration,
 Doctrine\ORM\EntityManager,
 Doctrine\Common\Cache\ArrayCache,
 Doctrine\DBAL\Logging\EchoSQLLogger,
 Symfony\Component\Console;
use Doctrine\ORM\Tools\Setup;
/**
 * @property \Doctrine\ORM\EntityManager $em Gerenciador de Entidade
 */
class Doctrine
{
public $em = '';
public function __construct()
 {
// Set up class loading. You could use different autoloaders, provided by your favorite framework,
 // if you want to.
 require_once APPPATH . 'third_party/DoctrineORM-2.2.2/libraries/Doctrine/Common/ClassLoader.php';
 require_once APPPATH . "third_party/DoctrineORM-2.2.2/libraries/Doctrine/ORM/Tools/Setup.php";
Doctrine\ORM\Tools\Setup::registerAutoloadDirectory(APPPATH . "third_party/DoctrineORM-2.2.2/libraries/");
$doctrineClassLoader = new ClassLoader('Doctrine', APPPATH . 'third_party/DoctrineORM-2.2.2/libraries');
 $doctrineClassLoader->register();
 $proxiesClassLoader = new ClassLoader('Proxies', APPPATH . 'models/proxies');
 $proxiesClassLoader->register();

// Set up caches
 $config = new Configuration;
 $cache = new ArrayCache;
 $config->setMetadataCacheImpl($cache);
 $driverImpl = $config->newDefaultAnnotationDriver(array(APPPATH . 'models/Entities'));
 $config->setMetadataDriverImpl($driverImpl);
 $config->setQueryCacheImpl($cache);
$config->setQueryCacheImpl($cache);
// Proxy configuration
 $config->setProxyDir(APPPATH . '/models/proxies');
 $config->setProxyNamespace('Proxies');
// Set up logger
 #$logger = new EchoSQLLogger;
 #$config->setSQLLogger($logger);
$config->setAutoGenerateProxyClasses(TRUE);
require APPPATH . 'config/database.php';
// Database connection information
 $connectionOptions = array(
 'driver' => 'pdo_mysql',
 'user' => $db['default']['username'],
 'password' => $db['default']['password'],
 'host' => $db['default']['hostname'],
 'dbname' => $db['default']['database'],
 'charset' => 'utf8',
 'driverOptions' => array(1002 => 'SET NAMES utf8')
 );

 // Enforce connection character set. This is very important if you are
 // using MySQL and InnoDB tables!
 //Doctrine_Manager::connection()->setCharset('utf8');
 //Doctrine_Manager::connection()->setCollate('utf8_general_ci');
// Create EntityManager
 $this->em = EntityManager::create($connectionOptions, $config);
 }
}

Alguns comentários sobre este arquivo:

1. Antes da declaração da classe, eu coloquei o código:

/** * @property \Doctrine\ORM\EntityManager $em Gerenciador de Entidade */

Serve para que a IDE (no meu caso, o NetBeans 7.2) consiga fazer a leitura do framework e mostrar dicas de código.

2. Na conexão do banco de dados tem uma dica valiosa. Eu adicionei (depois de sofrer bastante) a linha a seguir para evitar erros de acentuação na minha base de dados (que foi criada com “utf8_general_ci” e o projeto no NetBeans com codificação UTF-8):

'driverOptions' => array(1002 => 'SET NAMES utf8')

Este arquivo foi retirado de uma sugestão feita pelo Doctrine (disponível no site da documentação) e foram feitos alguns ajustes para compatibilidade com o projeto que estou criando. Para que possamos utilizar a linha de comando, devemos alterar o arquivo doctrine.php que está dentro da pasta bin em “\htdocs\doctrine\application\third_party\DoctrineORM-2.2.2\bin”:

<?php
if (!defined('APPPATH'))
{
 define('APPPATH', str_replace('third_party\DoctrineORM-2.2.2\bin', '', dirname(__FILE__)));
}
if (!defined('BASEPATH'))
{
 define('BASEPATH', '');
}
require APPPATH.'third_party/DoctrineORM-2.2.2/libraries/Doctrine.php';
$doctrine = new Doctrine();
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
 'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($doctrine->em->getConnection()),
 'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($doctrine->em)
));
$cli = new \Symfony\Component\Console\Application('Doctrine Command Line Interface (CodeIgniter integration by Joel Verhagen)', Doctrine\ORM\Version::VERSION);
$cli->setCatchExceptions(true);
$cli->setHelperSet($helperSet);
$cli->addCommands(array(
 // DBAL Commands
 new \Doctrine\DBAL\Tools\Console\Command\RunSqlCommand(),
 new \Doctrine\DBAL\Tools\Console\Command\ImportCommand(),
// ORM Commands
 new \Doctrine\ORM\Tools\Console\Command\ClearCache\MetadataCommand(),
 new \Doctrine\ORM\Tools\Console\Command\ClearCache\ResultCommand(),
 new \Doctrine\ORM\Tools\Console\Command\ClearCache\QueryCommand(),
 new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(),
 new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(),
 new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(),
 new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand(),
 new \Doctrine\ORM\Tools\Console\Command\ConvertDoctrine1SchemaCommand(),
 new \Doctrine\ORM\Tools\Console\Command\GenerateRepositoriesCommand(),
 new \Doctrine\ORM\Tools\Console\Command\GenerateEntitiesCommand(),
 new \Doctrine\ORM\Tools\Console\Command\GenerateProxiesCommand(),
 new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(),
 new \Doctrine\ORM\Tools\Console\Command\RunDqlCommand(),
 new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(),
));
$cli->run();

Este arquivo já vem no pacote do Doctrine, porém foram feitos alguns ajustes para que funcionasse corretamente. A referência que utilizei foi retirada do site do Joel Verhagen.

Lembrando que para conseguir executar o PHP com linha de comando de dentro da pasta do seu projeto, você deve adicionar o caminho do PHP no PATH em variáveis de ambiente (propriedades do sistema – avançado – clicar em variáveis de ambiente – selecionar “Path” – Editar). No meu caso adicionei no final da linha: “;E:\xampp\php”.

Finalmente precisamos criar uma pasta chamada “Entities” dentro de models (application\models\Entities), onde ficarão as entidades que farão a persistência.

Antes de iniciar o teste, vamos fazer mais algumas configurações no CodeIgniter para facilitar o trabalho. No arquivo “autoload.php”, vamos adicionar o pacote third_party do Doctrine e sua biblioteca:

$autoload['packages'] = array(APPPATH.'third_party/DoctrineORM-2.2.2');

$autoload['libraries'] = array('database', 'Doctrine');

Testando

Para fazer um teste, vamos criar um arquivo chamado usuario.php dentro da pasta Entities que acabamos de criar:

<?php
/**
*
* @Entity
* @Table(name="usuario")
*/
class usuario
{
/**
* @Id @Column(type="integer")
* @GeneratedValue(strategy="IDENTITY")
*/
public $id = 0;
/**
* @Column(type="string", columnDefinition="VARCHAR(50) NOT NULL")
*/
public $nome = 0;
/**
* @Column(type="string", columnDefinition="VARCHAR(50) NOT NULL")
*/
public $email = 0;
/**
* @Column(type="string", length=32, nullable=true)
* @var type
*/
public $telefone = '';
/**
* @Column(type="string", length=32, nullable=true)
* @var type
*/
public $celular = '';
}
/* End of file usuario.php */
/* Location: ./application/model/usuario.php */

Vamos, agora, criar o banco de dados a partir da entidade utilizando o seguinte comando:”php doctrine orm:schema-tool:create”:

E:\xampp\htdocs\doctrine\application\third_party\DoctrineORM-2.2.2\bin>php doctrine orm:schema-tool:create

Agora, basta olhar no banco de dados criado para ver a tabela de usuário que foi criada.

Para implementar a controller, para que ela salve uma informação no banco, podemos fazer da seguinte forma (estou utilizando a controller “welcome” apenas para verificar se o sistema está funcionando):

<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
/**
* @property usuario $usuario Classe de usuário
* @property Doctrine $doctrine Biblioteca ORM
*/
class Welcome extends CI_Controller
{
public function index()
{
$this->load->model('Entities/usuario', 'usuario');
$this->usuario->nome = 'Ricardo';
$this->usuario->email = 'meuemail@mail.com.br';
$this->usuario->telefone = '11-1122-3345';
$this->usuario->celular = '11-9988-7765';
$this->doctrine->em->persist($this->usuario);
 $this->doctrine->em->flush();
 }
}
/* End of file welcome.php */
/* Location: ./application/controllers/welcome.php */

Mais uma vez, eu utilizei @property do PHPDocumentor para que a IDE consiga fazer a leitura das classes e mostrar dicas de código.

Os arquivos do projeto podem ser baixados aqui.

Espero que esse artigo possa ajudar vocês. Um abraço e até o próximo artigo.