A first look at Doctrine 2.1
About one and a half year ago I remember that I had a look at Doctrine 1. It was pretty easy to install and use. The functions where pretty intuitive and it looked very cool. Even when i wanted to implement it to the Zend Framework.
I hadn’t been using Doctrine for a while and decided to pick it up two weeks ago, as we wanted to see if we can implement it for our CMS at our office. So I setup a clean installation of the zend framework (1.11.9) and tried tried to implement Doctrine.
The main goal was to see if we can reverse engineer existing databases and then start doing some queries.
Finding 1:
It was quite hard to get it going. I was confronted to numerous terminologies which I didn’t understand. What are Proxies, why do we need them? What are annotations? What is the entityManager for? And so on.
Finding 2:
It was hard to get directions to get the Doctrine classes working with the Zend Framework. We had a hard time getting all autoloaders functioning correct. It also plays a role that Doctrine 2.1 uses Namespaces and the Zend Framework doesn’t yet.
protected function _initDoctrine()
{
// Get the configuration options from the application.ini file
$options = $this->getOption('doctrine');
// Get the Zend Autoloader
$zendAutoloader = Zend_Loader_Autoloader::getInstance();
// Autoload the doctrine objects
$autoloader = array(new \Doctrine\Common\ClassLoader('Doctrine'), 'loadClass');
$zendAutoloader->pushAutoloader($autoloader, 'Doctrine');
// Autoload the models
$autoloader = array(new \Doctrine\Common\ClassLoader('Entities', $options['entitiesPath']), 'loadClass');
$zendAutoloader->pushAutoloader($autoloader, 'Entities');
// Now configure doctrine
if ('development' == APPLICATION_ENV) {
$cacheClass = isset($options['cacheClass']) ? $options['cacheClass'] : 'Doctrine\Common\Cache\ArrayCache';
} else {
$cacheClass = isset($options['cacheClass']) ? $options['cacheClass'] : 'Doctrine\Common\Cache\ApcCache';
}
$cache = new $cacheClass();
// Setup the Doctrine configuration
$config = new Configuration();
$config -> setMetadataCacheImpl($cache);
$config -> setMetadataDriverImpl(Doctrine\ORM\Mapping\Driver\AnnotationDriver::create(array($options['entitiesPath'])));
$config -> setQueryCacheImpl($cache);
$config -> setProxyDir($options['proxiesPath']);
$config -> setProxyNamespace('Proxies');
$config -> setEntityNamespaces(array('Entities'));
$config->setAutoGenerateProxyClasses(true);
$em = EntityManager::create(
$options['connection'],
$config
);
// Register the default ORM annotations for Doctrine. This has all the commonly
// used annotations for the entities.
AnnotationRegistry::registerFile('Doctrine/ORM/Mapping/Driver/DoctrineAnnotations.php');
// Once we have the EntityManager ready, add it to the registry
Zend_Registry::set('em', $em);
// end
return $em;
}
I created a resource in my bootstrap file in order to setup, load and configure Doctrine.
Then in my index controller I created a function to generate my entities. When generating my entities based on an existing mysql database i had the following problems
- All tables need to have a primary key, without a primary key Doctrine 2 will not generate the entities.
- We had some tables with geometry fields. Doctrine 2 cannot handle these field types yet. I had to change them to doubles or bynaries
Here is the code I used to generate my Entities.
public function generateFromDb()
{
try {
$this->_em->getConfiguration()->setMetadataDriverImpl(
new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
$this->_em->getConnection()->getSchemaManager()
)
);
$cme = new Doctrine\ORM\Tools\Export\ClassMetadataExporter;
$cme = new \Doctrine\ORM\Tools\Export\ClassMetadataExporter();
$cmf = new Doctrine\ORM\Tools\DisconnectedClassMetadataFactory;
$cmf>setEntityManager($this->_em);
$generator = new \Doctrine\ORM\Tools\EntityGenerator();
$generator->setUpdateEntityIfExists(true); // only update if class already exists
$generator->setGenerateStubMethods(true);
$generator->setGenerateAnnotations(true);
$result = $generator->generate($metadata, APPLICATION_PATH . '/models/');
}
catch(Exception $e) {
Zend_Debug::dump($e->getMessage());
}
}
After I generated my entities I wasn’t yet able to start my queries. This because I had errors that it couldn’t find my classes `Entities\User`. Further investigation learned that each Entity class was missing the line `namespace Entities;`. I thought it was just a setting to get this working. But I ended up debugging the `\Doctrine\ORM\Tools\EntityGenerator();`.
Bug?
What happens behind the scenes is that Doctrine creates an metadata array with objects of each database table. Each object has a `name` property which is by default set to have the name of the table. Doctrine scans this name to find a `\\` if it finds the two shlashes it will create a namespace else it will skip and not create a namespace. Huh?? Yes that’s also what I thought.
The easiest solution to solve this was to loop through the objects and and change the name property to something like: `Entities\\User`. When i did this, I was able to create entities having the namespace declaration. And now I am able to start working with queries.
public function generateFromDb()
{
try {
$this->_em->getConfiguration()->setMetadataDriverImpl(
new \Doctrine\ORM\Mapping\Driver\DatabaseDriver(
$this->_em->getConnection()->getSchemaManager()
)
);
$cme = new Doctrine\ORM\Tools\Export\ClassMetadataExporter;
$cme = new \Doctrine\ORM\Tools\Export\ClassMetadataExporter();
$cmf = new Doctrine\ORM\Tools\DisconnectedClassMetadataFactory;
$cmf->setEntityManager($this->_em);
$metadata = $cmf->getAllMetadata();
foreach($metadata as $k => $v){
$bla = $v->name;
$v->name = 'Entities\\'. $bla;
}
$generator = new \Doctrine\ORM\Tools\EntityGenerator();
$generator->setUpdateEntityIfExists(true); // only update if class already exists
$generator->setGenerateStubMethods(true);
$generator->setGenerateAnnotations(true);
$result = $generator->generate($metadata, APPLICATION_PATH . '/models/');
}
catch(Exception $e) {
Zend_Debug::dump($e->getMessage());
}
}
}
I think this is a bug, maybe someone in the community has a different solution to this. I would be glad to hear about it.
First thoughts on Doctrine 2.1
The only thing what keeps me going with doctrine 2.1 at the moment is that Doctrine ‘s query’s are easier and faster. The problem is that I haven’t seen much of this yet as it took me a lot of time to get the basic configuration up and running. I also have a lot of question’s which i hope to become clear in the next few days as I continue to work on my little Zend Framework 1.11.x and Doctrine integration 2 project.
There are already a lot of resources available on the Internet. I have looked at various configurations, like for example the `bisna` project from Guilhere Blanco. But I keep saying that it’s really difficult and has a steep learning curve. Doctrine 1.2 was really simple. Doctrine 2.x is a lot more difficult to get into.

Pingback: Jigal Sanders ‘Blog: Ein erster Blick auf Doctrine 2,1 | PHP Boutique
Pingback: Jigal Sanders’ Blog: A first look at Doctrine 2.1 | Scripting4You Blog
Pingback: Jigal Sanders’ Blog: A first look at Doctrine 2.1