Amazium bvba, your online partner
Zend_Application: Multiple DB Loading
  • Share post with Twitter
  • Share post with StumbleUpon
  • Share post with Delicious
  • Share post with Digg
  • Share post with Technorati
  • Share post with Blinklist
2009-04-23 15:44

Zend_Application: Multiple DB Loading

zend_application_resource, zend_application, zend framework

With addition of Zend_Application in Zend Framework version 1.8, Zend is providing us with a number of classes to make building application easier. In the past I had several classes responsible for setting up my application, initializing database, setting the config, etc...

(NOTE: from ZF 1.10 onwards a MultiDb resource is available in the library: Zend_Application_Resource_Multidb)

It worked fine, but with the new classes looming on the horizon, I decided to try it out.

I managed to setup an application quite quickly. Although I encountered a few bugs, there were no major blocking issues. As a DBA, I often use different databases from a single application. So I need to be able to initiate them in a simple and easy way.

With the Zend_Application, came code for a database resource as well. You basically put your database config in your ini file and bootstrap the database resource. It works like a charm, until you need multiple databases. You can go ahead and extend the database resource for every database you own, but that just doesn't cut it for me. I want a system where I put different databases in my config, and the resource handler takes care of it.

So, I decided to write my first application resource to take care of this. I played around a bit with names and had Multidb at first, but settled for dbs in the end (short for databases).

I had to add following lines to my config file:

# Add my class namespace for the autoloader

autoloadernamespaces.amz = "Amz_"

# Add my resource path to the plugin path
pluginpaths.Amz_Application_Resource = "Amz/Application/Resource"

# DB 1
resources.dbs.db1.adapter = PDO_MYSQL
resources.dbs.db1.params.dbname = db1
resources.dbs.db1.params.username = user1
resources.dbs.db1.params.password = ******
resources.dbs.db1.params.hostname = localhost
resources.dbs.db1.isDefaultTableAdapter = false

# DB 2
resources.dbs.db2.adapter = PDO_MYSQL
resources.dbs.db2.params.dbname = db2
resources.dbs.db2.params.username = user2
resources.dbs.db2.params.password = ******
resources.dbs.db2.params.hostname = localhost
resources.dbs.db2.isDefaultTableAdapter = false

My new resource class looks like this:

<?php
/**
 * Amazium Library
 *
 * @category   Amz
 * @package    Amz_Application
 * @subpackage Resource
 * @copyright  Copyright (c) 2009 Amazium (http://www.amazium.be)
 */

/**
 * Resource for creating multiple database adapters
 *
 * @uses       Zend_Application_Resource_Base
 * @category   Amz
 * @package    Amz_Application
 * @subpackage Resource
 * @copyright  Copyright (c) 2009 Amazium (http://www.amazium.be)
 */
class Amz_Application_Resource_Dbs extends Zend_Application_Resource_ResourceAbstract
{
    
    
/**
     * Adapter to use
     *
     * @var array
     */
    
protected $_db = array();
    
    
/**
     * Default adapter
     *
     * @var boolean
     */
    
protected $_defaultDb null;

    
/**
     * Adapter type to use
     * 
     * @return string
     */
    
public function getAdapter($db)
    {
        
$db $this->isValidDb($db);
        if (isset(
$this->_options[$db]['adapter'])) {
            return 
$this->_options[$db]['adapter'];
        }
        return 
null
    }

    
/**
     * Adapter parameters
     * 
     * @return array
     */
    
public function getParams($db)
    {
        
$db $this->isValidDb($db);
        if (isset(
$this->_options[$db]['params'])) {
            return 
$this->_options[$db]['params'];
        }
        return array();
    }

    
/**
     * Is this adapter the default table adapter?
     * 
     * @return void
     */
    
public function isDefaultTableAdapter($db)
    {
        
$db $this->isValidDb($db);
        if (isset(
$this->_options[$db]['isDefaultTableAdapter'])) {
            return 
$this->_options[$db]['isDefaultTableAdapter'];
        }
        return 
false;
    }

    
/**
     * Retrieve initialized DB connection
     * 
     * @return null|Zend_Db_Adapter_Interface
     */
    
public function getDbAdapter($db null)
    {
        
// check if the DB is valid
        
$db $this->isValidDb($dbtrue);
        if (
is_null($db) && is_null($db $this->_defaultDb)) {
            return 
null;
        }
        
        if ((!isset(
$this->_db[$db]) || (null === $this->_db[$db])) 
            && (
null !== ($adapter $this->getAdapter($db)))
        ) {
            
$this->_db[$db] = Zend_Db::factory($adapter$this->getParams($db));
        }
        return 
$this->_db[$db];
    }
    
    
/**
     * Defined by Zend_Application_Resource_IResource
     *
     * @return void
     */
    
public function init()
    {
        if (
is_null($this->_defaultDb)) {
            
$options $this->getOptions();
            
$defaultDb null;
            foreach (
$options as $db=>$dbOptions) {
                if (
null !== ($adapter $this->getDbAdapter($db))) {
                    if (
$this->isDefaultTableAdapter($db) || is_null($defaultDb)) {
                        
$defaultDb $db;
                    }
                }
            }
            if (!
is_null($defaultDb)) {
                
$this->_defaultDb $defaultDb;
                
Zend_Db_Table::setDefaultAdapter($this->getDbAdapter($defaultDb));
            }
        }
    }
    
    
/**
     * Check if a database key is valid
     *
     * @param string $db
     * @param boolean $revertToDefaultDb
     * @return string
     */
    
public function isValidDb($db$revertToDefaultDb false)
    {
        
$db strtolower(trim($db));
        if (!
in_array($dbarray_keys($this->_options))) {
            if (!
$revertToDefaultDb) {
                
$db $this->_defaultDb;
            } else {
                throw new 
Zend_Application_Resource_Exception('Invalid database specified');
            }
        }
        return 
$db;
    }

}

And last but not least, here's my Bootstrap file for loading and using the database:

class Bootstrap extends Zend_Application_Bootstrap_Base
{

    public function 
run()
    {
        
$this->bootstrap('dbs');
        
$dbs $this->getPluginResource('dbs');
        
Zend_Registry::set('db1'$dbs->getDbAdapter('db1'));
        
Zend_Registry::set('db2'$dbs->getDbAdapter('db2'));
        
        
$this->bootstrap('frontController');
        
        
$this->frontController->dispatch();
    }
}

Enjoy!

Comments and Feedback
How to implement these functions and switch connections in my code?
How to implement these functions and switch connections in my code(MODEL)?
Thanks Jeroen - big help. To answer the questions - after implementing the steps given:

I created an extended abstract class for my models to extend from:

abstract class Model_DbTable_Abstract extends Zend_Db_Table_Abstract{
// Containing this function
public function Model_DbTable_Abstract ($config = null)
{
if (isset(
$this->_use_adapter)) {
$config = Zend_Registry::get($this->_use_adapter);
}
return
parent::__construct($config);
}
}
And then My Model:

class Model_DbTable_User extends Model_DbTable_Abstract
{
protected
$_name = 'user';
protected
$_use_adapter = 'db1';

//......
}
Hope this helps -

You can view more of my tutorials at http://blog.routydesign.com

Add a Comment

Your email is never published or shared. Required fields are marked*