Search code examples
phpdatabasecakephpmodelcakephp-2.x

CakePHP: Change database connection for all models globally based on Configure value


I've 3 copies of my code - on development workstation, a test server and a production server.

Accordingly, I have 3 separate DB configs in the database.php file named dev, test & production.

I'm trying to figure out a way to switch the connection based on a value written to the Configure class. The way I'm trying to accomplish this out is to require a file called instance.php in the last line of bootstrap.php.

require( APP . 'Config/instance.php' );

My instance.php looks like:

<?php
// Configure instance type
Configure::write( 'InstanceType', 'Development' );
//Configure::write( 'InstanceType', 'Test' );
//Configure::write( 'InstanceType', 'Production' );

On the development workstation, the first line will be uncommented. Likewise on Test and Production the 2nd and 3rd lines will remain uncommented.

What I need is a method (perhaps in AppModel) that'll get executed before any other Model loads and will set the correct DB config. using the following code:

    // Set DB Config
    switch( Configure::read( 'InstanceType' ) ) {
        case 'Development':
            //default:
            $this->useDbConfig = 'default';
            break;
        case 'Test':
            $this->useDbConfig = 'test';
            break;
        case 'Production':
            $this->useDbConfig = 'production';
            break;
    }

OR (condensed version)

$this->useDbConfig = Configure::read( 'InstanceType' ) == 'Development' ? 'default' : strtolower( Configure::read( 'InstanceType' ) );

I tried to put this into a __construct() method inside AppModel but that started throwing a bunch of errors about missing arguments to __construct.

The outcome is to have:

  1. All models utilize the given DB connection.
  2. Not mess around with the DB specifier individually in each model.
  3. Not having to maintain 3 different copies of database.php on the 3 platforms.

How can I make this work?

Thank you.


Solution

  • You are on the right track. However, the code can't be placed in the construct for AppController.php.

    Instead, add it to class DATABASE_CONFIG in /app/Config/database.php:

    public function __construct() {
        // Set DB Config
        switch( Configure::read( 'InstanceType' ) ) {
            case 'Development':
                //default:
                //do nothing, as $this->default holds the right config
                break;
            case 'Test':
                $this->default = $this->test;
                break;
            case 'Production':
                $this->default = $this->production;
                break;
        }
    }
    

    Option 2: Symlinks

    A different approach is to create 3 different versions of your database.php file, each holding the right database config for each server, which you maintain with the rest of your code.

    /app/Config/database-development.php
    /app/Config/database-test.php 
    /app/Config/database-production.php 
    

    These three files are copied over to all of your servers when you update the repositories.

    You then create a symbolic link on each server pointing to the right config file:

    // Development Server
    ln -s app/Config/database-development.php app/Config/database.php 
    
    // Test Server
    ln -s app/Config/database-test.php app/Config/database.php 
    
    // Production Server
    ln -s app/Config/database-production.php app/Config/database.php 
    

    Make sure this symlink is ignored in .gitignore, so it won't be overwritten (default CakePHP behaviour).

    You still have to maintain 3 different database config files, but you do it locally. You can also get rid of Config/instance.php.