October 29, 2007 15

Easy Dynamic Database Connection in CakePHP

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.

15 Responses to “Easy Dynamic Database Connection in CakePHP”

  1. Olivier says:

    Nice one, I’m glad Google found you.

  2. abhisek says:

    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 says:

    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. 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 says:

    Thanks, exactly what I was looking for.

  6. nick says:

    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 says:

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

  8. bornplaydie says:

    Nice! Works like a charm!

  9. Barak says:

    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 says:

    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!

  11. dude – love the code, love the site. thanks for being so generous. peace!

  12. Brett Wilton says:

    Thanks for the article, been wanting to find a solution to this for a while now.

  13. Suryya says:

    Hey thanx for the help.. nice work. i was searching in the net for some kinda stuff which would help me to modify/create a new database. n u know. u just did…… : )
    Appreciate Your Effort !!
    Keep Helping..

  14. Samurai says:

    Thanks from Ukraine for the article!

  15. Traian says:

    Thanks a lot, you made my day!