CodeIgniter with Multiple Database Support

** UPDATED on 2010-09-06 **

Over the last few months I have been using the CodeIgniter framework for several projects. So far, I have been very pleased with its flexibility and even more so with its extensibility.

On one my projects, I needed to connect to multiple databases at the same time. CI easily supports this via configuration settings, however the built in profiler only supports the default database. No problem, let’s extend it!

Step 1: Edit database.php and use descriptive group names.

In this tutorial, I am connecting to 2 separate databases. So far, this is nothing new, however your settings need to be correct.

Example:

$active_group = "default";
$active_record = TRUE;

$db['default']['hostname'] = "";
$db['default']['username'] = "";
$db['default']['password'] = "";
$db['default']['database'] = "";
$db['default']['dbdriver'] = "mysql";
$db['default']['dbprefix'] = "";
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = FALSE;
$db['default']['cachedir'] = "";
$db['default']['char_set'] = "utf8";
$db['default']['dbcollat'] = "utf8_general_ci";

// add alternate database settings by gotphp.com

$db['alternate']['hostname'] = "";
$db['alternate']['username'] = "";
$db['alternate']['password'] = "";
$db['alternate']['database'] = "";
$db['alternate']['dbdriver'] = "mysql";
$db['alternate']['dbprefix'] = "";
$db['alternate']['pconnect'] = TRUE;
$db['alternate']['db_debug'] = TRUE;
$db['alternate']['cache_on'] = FALSE;
$db['alternate']['cachedir'] = "";
$db['alternate']['char_set'] = "utf8";
$db['alternate']['dbcollat'] = "utf8_general_ci";

Step 2: Edit autoload.php and autoload ALL models.

This is needed so the profiler is aware of the other databases and can iterate accordingly.

IMPORTANT: If you ONLY load your models on demand, that’s OK too. You still want to follow this step, but simply comment out the $autoload variable when you are NOT in debug mode. :)

Example:

$autoload['model'] = array(
	'alternate_model', 	// loaded by gotphp.com
	'default_model', 	// loaded by gotphp.com
);

Step 3: In your models, use the actual database group names for your db connection by defining $db_group_name.

In other words, stop using $this->db and start using $this->[group], etc.

IMPORTANT: Be sure to establish a connection to the database group in the model’s constructor AND add a new method to get the database group for this mode. THIS IS REQUIRED.

Example:

class Default_model extends Model {

	/**
	 */
	var $db_group_name = "default";

	// --------------------------------------------------------------------

	/**
	 * 	Constructor -- Loads parent class
	 */
	function __construct()
	{
		parent::__construct();

		$this->{$this->db_group_name} = $this->load->database($this->db_group_name, TRUE);

	}

	// --------------------------------------------------------------------

	/**
	 * 	Required method to get the database group for THIS model
	 */
	function get_database_group() {
		return $this->db_group_name;
	}

	// --------------------------------------------------------------------

}

Now in EACH method in THIS model, use $this->{$this->db_group_name}.

Example:

class Default_model extends Model {

	// --------------------------------------------------------------------

	function get_example_data()
	{
		$query = $this->{$this->db_group_name}->get('default_example');
		return $query->result_array();
	}

	// --------------------------------------------------------------------

}

Step 4: Extend CI’s profiler class to include all databases in the debug output

In your config.php file, take note of your subclass_prefix setting. You will need to use this in order to extend CI’s core classes automatically.

Example:

$config['subclass_prefix'] = 'MY_';

Now, create a new file in your application’s libraries directory called MY_Profiler.php.

IMPORTANT: If you changed your subclass_prefix, replace “MY_” in the rest of this tutorial with your custom setting.

In this new file, you will be extending the CI_Profiler, defining your own run method to account for multiple database groups, and adding a new display method that shows the database group AND model for each query!

Example:

class MY_Profiler extends CI_Profiler {

	/**
	 * Compile Multiple Database Queries
	 * @return	string
	 */
	function _compile_multi_db_queries($database, $model)
	{
		... too much to copy here ... download file to review ...
	}

	// --------------------------------------------------------------------

	/**
	 * Run the Profiler
	 *
	 * @access	private
	 * @return	string
	 */
	function run()
	{
		$output = "
"; if ($this->CI->config->item('show_uri_string')) { $output .= $this->_compile_uri_string(); } if ($this->CI->config->item('show_controller_info')) { $output .= $this->_compile_controller_info(); } if ($this->CI->config->item('show_memory_usage')) { $output .= $this->_compile_memory_usage(); } if ($this->CI->config->item('show_benchmarks')) { $output .= $this->_compile_benchmarks(); } if ($this->CI->config->item('show_cookies')) { $output .= $this->_compile_variables('cookie_vars'); } if ($this->CI->config->item('show_get_vars')) { $output .= $this->_compile_variables('get_vars'); } if ($this->CI->config->item('show_post_vars')) { $output .= $this->_compile_variables('post_vars'); } if ($this->CI->config->item('show_uri_vars')) { $output .= $this->_compile_variables('uri_vars'); } if ($this->CI->config->item('show_tpl_vars')) { $output .= $this->_compile_variables('tpl_vars'); } if ($this->CI->config->item('show_session_userdata')) { $output .= $this->_compile_variables('session_userdata'); } if ($this->CI->config->item('show_db_multi_queries')) { // Include the autoload config to access the array of models in this app. include(APPPATH.'config/autoload'.EXT); // Loop through each model to set the database object foreach($autoload['model'] as $model) { // Define the database object name $database = $this->CI->$model->get_database_group(); // Compile the output $output .= $this->_compile_multi_db_queries($database, $model); } } else { $output .= $this->_compile_queries(); } $output .= '
'; return $output; } // -------------------------------------------------------------------- }

Step 5: You will need to enable the built in profiler in one of your controllers and set the new configuration paramaters in a profile.php config file.

Example (enable profiler):

// Load the profile.php config file if it exists
$this->config->load('profiler', false, true);
if ($this->config->config['enable_profiler']) {
	$this->output->enable_profiler(TRUE);
}

Example (profiler.php file):

$config['enable_profiler'] 			= 1;
$config['show_uri_string'] 			= 1;
$config['show_controller_info']		= 1;
$config['show_memory_usage'] 		= 1;
$config['show_benchmarks'] 			= 1;
$config['show_cookies'] 			= 1;
$config['show_get_vars'] 			= 1;
$config['show_post_vars'] 			= 1;
$config['show_uri_vars'] 			= 1;
$config['show_tpl_vars'] 			= 1;
$config['show_session_userdata']	= 1;
$config['show_db_multi_queries'] 	= 1; // Only enable if you need to show more than one database in the profiler

If you have followed the steps above in order, your CodeIgniter application can now connect to multiple databases at the same time and each connections’ queries will display in the profiler like this:

Profiler Example Multi DB

If you found this article useful, please share your comments below.

Tags: , , , ,

  • http://armanadhitama.web.id Arman

    Great article! Looking for these for weeks.

  • Shermie

    Thanks a lot buddy you're a genius!!

  • http://mvclogic.com Yash

    Just read user guide this is all there :)

    This is just collection of those. Only one good thing …this guys summarize all this.

  • At!

    Like your post.

    Might need it in the near future.

  • http://haureal.com Haurealws

    Nice job Michael! Really useful for my project. Thank u! :)

  • http://www.icpep.org Techie Talks

    This looks like one good code. This will surely help a lot of coders out there.

  • http://best-avatars.com Djordje Zeljic

    Hi Michael,

    very helpful post, thank you.

  • Zoran

    Thank you for this nice tip

  • Pingback: Two or more MySQL Connections PHP | Albertux~# ./Blog

  • http://www.facebook.com/judywong j4dy

    Nice and neat! Just a note that MY_Profiler.zip need to be updated though – or one could just need to copy and past the run() from current version adn modify.

    Great job Michael!

  • http://www.gotphp.com Michael

    Thanks for all of the comments guys. I have updated the MY_Profiler.php file with some new functionality. Check it out here: http://www.gotphp.com/codeigniter-profiler-extend…

    Enjoy!

  • http://harshadewa.com Harshadewa

    Is it possible in CodeIgniter to connect to multiple databases and include tables from 2 or more databases in one query in this way?

    Ex:
    SELECT E_Name FROM Employees_Norway
    UNION ALL
    SELECT E_Name FROM Employees_USA

    • Michael

      It's been a while since I have joined two databases in a single query, but yes it's possible.

      First, you will need to make sure that both databases are accessible on the same server with the same mysql user.

      Second, you will need to explicitly use the database name in your query….

      SELECT database.table.column FROM database.table
      UNION ALL
      SELECT database2.table2.column2 FROM database2.table2

      …etc…

    • http://seangates.com Sean Gates

      Yes, I've done that. Michael is correct that you need to use the explicit table names. Also, you won't be able to use the active records.

      From Phil Sturgeon (http://stackoverflow.com/questions/2040655/union-with-codeigniters-active-record): "To explain, CodeIgniter's ActiveRecord only supports SQL features that are compatible with all its supported SQL types (or implements them in its own way). The idea of ActiveRecord is to abstract the database type to be database independant and let people move from MySQL to MSSQL or whatever else without major issue. If they tried to add unison it would screw with other database types."

      • Michael

        Good point on the ActiveRecord issue, I didn't think of that. Thanks!

  • http://kudada.com Roi

    Michael hi,
    I tried to use your instructions, then downloaded your code, but it didn't work. I changed the database.php to look like this:

    $db['default']['hostname'] = "localhost";
    $db['default']['username'] = "tab_user";
    $db['default']['password'] = "chucha152";
    $db['default']['database'] = "try_tables";
    $db['default']['dbdriver'] = "mysql";
    $db['default']['dbprefix'] = "";
    $db['default']['pconnect'] = TRUE;
    $db['default']['db_debug'] = TRUE;
    $db['default']['cache_on'] = FALSE;
    $db['default']['cachedir'] = "";
    $db['default']['char_set'] = "utf8";
    $db['default']['dbcollat'] = "utf8_general_ci";

    // add alternate database settings by gotphp.com

    $db['alternate']['hostname'] = "localhost";
    $db['alternate']['username'] = "tab_user";
    $db['alternate']['password'] = "chucha152";
    $db['alternate']['database'] = "guymen_blogkudada";
    $db['alternate']['dbdriver'] = "mysql";
    $db['alternate']['dbprefix'] = "";
    $db['alternate']['pconnect'] = TRUE;
    $db['alternate']['db_debug'] = TRUE;
    $db['alternate']['cache_on'] = FALSE;
    $db['alternate']['cachedir'] = "";
    $db['alternate']['char_set'] = "utf8";
    $db['alternate']['dbcollat'] = "utf8_general_ci";

    which brought this output (including the debugs you added to the code, in red)

    [0]["product_id"] = 1
    [0]["product_name"] = cucumbers
    [0]["quantity"] = 2
    [0]["unit_price"] = 9
    [1]["product_id"] = 3
    [1]["product_name"] = batata
    [1]["quantity"] = 1
    [1]["unit_price"] = 8
    [2]["product_id"] = 4
    [2]["product_name"] = avocado
    [2]["quantity"] = 4
    [2]["unit_price"] = 15
    [3]["product_id"] = 5
    [3]["product_name"] = banana
    [3]["quantity"] = 12
    [3]["unit_price"] = 3

    A Database Error Occurred
    Error Number: 1146

    Table 'try_tables.wp-comments' doesn't exist

    SELECT * FROM (`wp-comments`)

    while this is totally wrong: i queried wp-comments table from the alternate model, not the default one!

    If i swap the order of the models loading in autoload.php to be like this:

    $autoload['model'] = array(
    'default_model', // loaded by gotphp.com
    'alternate_model', // loaded by gotphp.com
    );

    the error is different:
    A Database Error Occurred
    Error Number: 1146

    Table 'guymen_blogkudada.shopping' doesn't exist

    SELECT * FROM (`shopping`)

    but again this is wrong: i tried the 'shopping' table from the try_tables database which is the "default". I know the database is ok because before the change to autoload.php i got the correct data in the debug output (shopping list)

    thanks a lot

    Roi

    • Michael

      Hello Roi,

      Without actually looking at the changes you made, it would be hard for me to isolate the issue for you. Zip it up and send it to me with a dump of the DBs and I'll check it out. gotphp@gmail.com

      Thanks!

      - Michael

  • http://www.whysnatur.com snatur

    Thank you for this nice tip

  • leth

    Hi. I followed all your steps but when I tried using it, it says “An Error Was Encountered, You have specified an invalid database connection group”

    • Anonymous

      Hi! Did you setup two databases and update the database.php file with the new credentials?

      • leth

        I forgot I tinkered with the database.php and commented the second database group. Haha. I fixed it already. How should I use the function for getting data (in the alternate_model) in a controller? Would I just directly use $this->Alternate_Model->myFunction()?

      • leth

        I encountered another problem. It says ”
        Table ‘ticketingsystem.employee’ doesn’t exist”. tTicketingsystem is my default database while the employee table is in my second database, which is employee_db. I accessed the employee table in my alternate model using the second database. The accessing was all messed up. :(

  • Noah Spirakus

    Have you played with this functionality in codeigniter v2+? It doesnt seem to work the same way and seems to hang on to las db used, even if you assign them as different variables.

  • Noah Spirakus

    Have you played with this functionality in codeigniter v2+? It doesnt seem to work the same way and seems to hang on to las db used, even if you assign them as different variables.

  • VCL

    Hello there, is there anyway to fill in the alternate username and password from 2 POST variables? I have to do so and I’m having tones of errors. thanks

  • Matthew Davis

    An alternate approach that worked for me (not sure if it will work for all configurations) – extend profiler class and override _compile_queries method (modify first foreach loop with code below). 

    // Let’s determine which databases are currently connected to foreach (get_object_vars($this->CI) as $CI_object) { if (is_object($CI_object) && is_subclass_of(get_class($CI_object), ‘CI_DB’) ) { $dbs[] = $CI_object; }            if (is_object($CI_object) && is_subclass_of(get_class($CI_object), $this->CI->config->config['subclass_prefix'] . ‘Model’) ) {                foreach (get_object_vars($CI_object) as $CI_sub_object)                {                    if (is_object($CI_sub_object) && is_subclass_of(get_class($CI_sub_object), ‘CI_DB’) )                    {                        $dbs[] = $CI_sub_object;                    }                }            } }