Zend Framework and Doctrine Part 1
I’ve begun to investigate the Doctrine ORM library and how to integrate it into Zend Framework applications. I figure this post and any subsequent ones on the topic can grow into some sort of discovery series.
So, my first post is going to be a simple one – bootstrapping with Doctrine 1.2.
I figured the most robust and consistent way to get Doctrine into my applications was to create an application resource plugin so without further delay, here it is.
// library/Tolerable/Application/Resource/Doctrine.php class Tolerable_Application_Resource_Doctrine extends Zend_Application_Resource_ResourceAbstract { /** * @var Doctrine_Manager */ protected $_manager; /** * @var Doctrine_Cache_Interface */ protected $_cacheDriver; /** * @var string|array */ protected $_cache; /** * @var array */ protected $_connections = array(); /** * Set cache options * * @param string|array $cache * @return Tolerable_Application_Resource_Doctrine */ public function setCache($cache) { $this->_cache = $cache; return $this; } /** * @return string|array */ public function getCache() { return $this->_cache; } /** * Set connection configuration * * @param array $connections * @return Tolerable_Application_Resource_Doctrine */ public function setConnections(array $connections) { $this->_connections = $connections; return $this; } /** * Initialise and return Doctrine_Manager instance * * @return Doctrine_Manager */ public function getManager() { if (null === $this->_manager) { $manager = Doctrine_Manager::getInstance(); $manager->setAttribute(Doctrine_Core::ATTR_MODEL_LOADING, Doctrine_Core::MODEL_LOADING_CONSERVATIVE); $manager->setAttribute(Doctrine_Core::ATTR_VALIDATE, Doctrine_Core::VALIDATE_ALL); $manager->setAttribute(Doctrine_Core::ATTR_AUTO_ACCESSOR_OVERRIDE, true); $manager->setAttribute(Doctrine_Core::ATTR_AUTOLOAD_TABLE_CLASSES, true); $manager->setAttribute(Doctrine_Core::ATTR_USE_DQL_CALLBACKS, true); $manager->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true); if ($cacheDriver = $this->_getCacheDriver()) { $manager->setAttribute(Doctrine_Core::ATTR_QUERY_CACHE, $cacheDriver); } $this->_manager = $manager; } return $this->_manager; } /** * Initialise and return query cache driver if configured * * @return Doctrine_Cache_Interface|null */ protected function _getCacheDriver() { if (null === $this->_cacheDriver) { $options = $this->getCache(); if (empty($options)) { return null; } if (is_array($options)) { if (!array_key_exists('driver', $options)) { throw new Zend_Application_Resource_Exception('Missing Doctrine cache driver'); } $driver = $options['driver']; unset($options['driver']); } else { $driver = (string) $options; $options = array(); } if (!class_exists($driver)) { Zend_Loader::loadClass($driver); } $this->_cacheDriver = new $driver($options); } return $this->_cacheDriver; } /** * Initialise any configured connections * * @return void */ protected function _initConnections() { foreach ($this->_connections as $name => $options) { if (!is_array($options)) { $options = array('dsn' => $options); } if (array_key_exists('charset', $options)) { $charset = $options['charset']; unset($options['charset']); } else { $charset = 'utf8'; } // Attempt to find "dsn" or "connection_string" keys // falling back to an array of connection options if (array_key_exists('dsn', $options)) { $adapter = $options['dsn']; } else if (array_key_exists('connection_string', $options)) { $adapter = $options['connection_string']; } else { $adapter = $options; } $connection = $this->getManager()->openConnection($adapter, $name); $connection->setAttribute(Doctrine_Core::ATTR_USE_NATIVE_ENUM, true); $connection->setCharset($charset); } } /** * Initialise and return Doctrine manager * * @return Doctrine_Manager */ public function init() { $this->_initConnections(); return $this->getManager(); } } |
This class provides a reusable component to use in any ZF 1.8+ application. To enable the plugin, add the following to your application.ini file.
; Add the Doctrine and Tolerable namespaces to the autoloader autoloaderNamespaces[] = "Doctrine_" autoloaderNamespaces[] = "Tolerable_" ; Add our custom application resource plugin path to the plugin loader pluginPaths.Tolerable_Application_Resource = "Tolerable/Application/Resource" |
Configure the Doctrine query cache (if desired)
; Simple examples, no driver options resources.doctrine.cache = "Doctrine_Cache_Apc" ; or with options resources.doctrine.cache.driver = "Doctrine_Cache_Apc" resources.doctrine.cache.option = ... resources.doctrine.cache.option = ... resources.doctrine.cache.option = ... |
See here for drivers and options.
Configure the connections
; Simple connection strings resources.doctrine.connections[] = "mysql://user1:pass@localhost/db1" resources.doctrine.connections[] = "mysql://user2:pass@localhost/db2" ; or specify connection name and options resources.doctrine.connections.default.dsn = "mysql://user1:pass@localhost/db1" resources.doctrine.connections.default.charset = "utf8" ; or specify Doctrine connection parameters resources.doctrine.connections.default.scheme = "mysql" resources.doctrine.connections.default.user = "user1" resources.doctrine.connections.default.pass = "pass" resources.doctrine.connections.default.host = "localhost" resources.doctrine.connections.default.path = "db1" |
This is assuming that your custom (Tolerable in these examples) and Doctrine libraries are under your application’s “library” path. If not, simply add them to the application’s include path configuration, for example
includePaths.library = APPLICATION_PATH "/../library" includePaths.doctrine = "/path/to/doctrine/lib" includePaths.custom = "/path/to/custom/library" |
A lot of the code in the plugin has been taken from Matthew Weier O’Phinney’s blog post on Autoloading Doctrine and Doctrine entities from Zend Framework.
2009-11-19 Update
Some extra inspiration came from Juozas Kaziukenas’ post on Zend Framework and Doctrine. Part 2 as well as the twitter-verse and now the plugin handles multiple connections and caching.


November 18th, 2009 at 11:18 am
Consider this plugin to be about as simple as it gets. If you’re after total configurability, it would probably be best to follow this framework proposal – http://framework.zend.com/wiki/display/ZFPROP/Zend_Application_Resource_Doctrine+-+Matthew+Lurz