Easy Dynamic Database Connection in CakePHP

If you’re like me, you’re strikingly handsome you create Cake applications on your computer, then upload them for testing (and usage) to a server. It’s annoying to have to change the /app/config/database.php file for each new testing environment, especially if the same Cake application is being used on multiple machines.

Thankfully there’s a really simple way around this crap.

Simply replace Cake’s /app/config/database.php file with the following:

<?php
class DATABASE_CONFIG {
	#localhost
	var $local = array('driver' => 'mysql',
		'connect' => 'mysql_connect',
		'host' => 'localhost',
		'login' => 'root',
		'password' => '',
		'database' => 'local',
		'prefix' => '');

	#dev server
	var $dev = array('driver' => 'mysql',
		'connect' => 'mysql_connect',
		'host' => 'mysql.dev.com',
		'login' => 'dev',
		'password' => 'password',
		'database' => 'dev',
		'prefix' => '');

	#live server
	var $live = array('driver' => 'mysql',
		'connect' => 'mysql_connect',
		'host' => 'mysql.live.com',
		'login' => 'live',
		'password' => 'password',
		'database' => 'live',
		'prefix' => '');

	#switch between configs
	var $default = array();
	var $test = array();
	function __construct() {

		#wildcard the subdomains
		$host_r = explode('.', $_SERVER['SERVER_NAME']);
		if(count($host_r)>2) while(count($host_r)>2)array_shift($host_r);
		$mainhost = implode('.', $host_r);

		#switch between servers
		switch(strtolower($mainhost)) {
			case 'localhost':
				$this->default = $this->local;
				break;
			case 'dev.com':
				$this->default = $this->dev;
				break;
			case 'live.com':
				$this->default = $this->live;
				break;
			default:
				$this->default = $this->local;
		}
	}

	#php 4 compatibility
	function DATABASE_CONFIG() {
		$this->__construct();
	}
}
?>

The highlighted code beginning with var $local = array('driver' => 'mysql', corresponds with the case 'localhost': at the bottom.

A Quick Example

So let’s say you have a Cake application running locally on localhost and remotely at mydomain.com, you’re database.php file would look something like this:

<?php
class DATABASE_CONFIG {
	#localhost
	var $local = array('driver' => 'mysql',
		'connect' => 'mysql_connect',
		'host' => 'localhost',
		'login' => 'root',
		'password' => '',
		'database' => 'local',
		'prefix' => '');

	#live server
	var $live = array('driver' => 'mysql',
		'connect' => 'mysql_connect',
		'host' => 'mysql.mydomain.com',
		'login' => 'live',
		'password' => 'password',
		'database' => 'live',
		'prefix' => '');

	#switch between configs
	var $default = array();
	var $test = array();
	function __construct() {

		#wildcard the subdomains
		$host_r = explode('.', $_SERVER['SERVER_NAME']);
		if(count($host_r)>2) while(count($host_r)>2)array_shift($host_r);
		$mainhost = implode('.', $host_r);

		#switch between servers
		switch(strtolower($mainhost)) {
			case 'localhost':
				$this->default = $this->local;
				break;
			case 'mydomain.com':
				$this->default = $this->live;
				break;
			default:
				$this->default = $this->local;
		}
	}

	#php 4 compatibility
	function DATABASE_CONFIG() {
		$this->__construct();
	}
}
?>

Now when you upload your CakePHP application from your localhost directory to mydomain.com, you won’t have to fiddle with the database.php file. It’ll recognize that Cake’s running on mydomain.com and will adjust the MySQL connection accordingly.

Rock on roll.

10 Comments so far

  1. Olivier on November 4th, 2007

    Nice one, I’m glad Google found you.

  2. abhisek on November 12th, 2007

    i have a database in my server and i want to retreive it using cake php. pls send me the way to do it … i did it in php by using mysql_connect() and two more functions pls tell me how to do in cake php

  3. Koa on November 14th, 2007

    abhisek, it sounds like you don’t yet understand the basics of CakePHP. Reading the
    official Cake manual regarding configuration should help you out.

  4. Gabriel Braila on March 28th, 2008

    Just I have searcged for….
    now I can switch beetween 2 mysql conts with different powers depending of validation

    part of code bellow

    
    	function __construct() {
    		$this->default = $this->visitor;
    		App::import('Component', 'Security');
    		$sec = new SecurityComponent();
    		$authorized = $sec->loginCredentials('basic');
    		if($authorized) $this->default = $this->admin;
    		unset($sec);
    	}
    
  5. Marc Mauger on April 5th, 2008

    Thanks, exactly what I was looking for.

  6. nick on June 8th, 2008

    thank you so much for this code. i’ve spent days trying to figure out how to do this. I was able to successfully get the above code working in 30 seconds.

  7. Koa on June 8th, 2008

    Marc & Nick, glad you found this useful. :}

  8. bornplaydie on August 10th, 2008

    Nice! Works like a charm!

  9. Barak on August 13th, 2008

    Thank you; I was trying to do a require_once() for this purpose but PHP doesn’t like that inside database.php for whatever reason. Your solution was great… almost perfect. :)

    I made a couple of additions, to support my situation of having the dev server running on a high port, not the standard port 80, and to also accommodate my work style, which includes local and public dev servers in addition to the client’s live/production server.

    
    #automatically switch database configuration based on calling server
    switch(strtolower($_SERVER['SERVER_NAME'].'_'.$_SERVER['SERVER_PORT']) {
            case 'localhost_1080':
            case '127.0.0.1_1080':
                    $this->default = $this->local_cfg;
                    break;
            case 'publicexample.net_80':
            case 'www.publicexample.net_80':
                    $this->default = $this->pub_cfg;
                    break;
            case 'live.com_80':
            case 'www.live.com_80':
                    $this->default = $this->live_cfg;
                    break;
            default:
                    $this->default = $this->local;
    }
    

    BTW, I also use this same type of switch/case in the core.php, so as to set DEBUG to 0 on the live server, 1 on the public dev server, and 2 or 3 on the local dev server.

  10. demi on August 18th, 2008

    Hello! I’ve just simplified you conception. I’ve add mapping in the top of the DATABASE_CONFIG:

    
    var $map = array(
    	'example.localhost'	=>	'local',
    	'dev.example.com'	=>	'dev',
    	'test.example.com'	=>	'test',
    	'example.com'		=>	'live'
    );
    

    And intstead of your constructor write own:

    
    function __construct() {
    	$this->default = $this->{$this->map[$_SERVER['SERVER_NAME']]};
    }
    

    So, it is unneeded to change code in constructor, also for me it’s very usefull to place dev/test servers on subdomains.

    Thank you!

Leave a Reply