Yii with multiple production and test databases

I am using Yii to build a migrate-on-demand application to migrate users from one database to another.

I am telling Yii about the destination database via the usual main.php configuration file.

The source models inherit from a SourceActiveRecord class that extends CActiveRecord. I get the source models to use the source database by the SourceActiveRecord::getDbConnection() method.

This is fine until I want to create some unit tests for the migration. I can easily define a test destination database by telling Yii to use a different configuration file for the tests (e.g. protected/config/test.php).

However, I’m not sure what’s the best way to get the source models to use a different test database. I could dynamically change SourceActiveRecord::db in my unit test bootstrap script, but that seems awkward. Anyone needing to maintain this code in the future would have a hard time guessing where I am telling Yii about the test source database. This ideally would be in a configuration file.

Any recommendations?

You may see this.

Maybe is a way to set at main.php the testdb connection and change at controllers (maybe or at index.php) the connection string.

My index.php looks like this:


<?php


// change the following paths if necessary

$yii=dirname(__FILE__).'/../yii109/framework/yii.php';

$all=dirname(__FILE__).'/protected/config/main.php';




$servername = $_SERVER["SERVER_NAME"];

switch ($servername) {

    // development

    case "localhost":

        $type=dirname(__FILE__).'/protected/config/dev.php';

        $debug=true;

        break;

 

    // production

    case "mywebspace.com":

        $type=dirname(__FILE__).'/protected/config/prod.php';

        $debug=false;

        break;

    default:

      echo "Access denied";

    exit;

}

defined('YII_DEBUG') or define('YII_DEBUG',$debug);


require_once($yii);

$config=CMap::mergeArray(require($all), require($type));


Yii::beginProfile('Application');

Yii::createWebApplication($config)->run();

Yii::endProfile('Application');



dev.php and prod.php:


<?php


return array(

    'components'=>array(        

        'db'=>array(

              'class'=>'CDbConnection',

              'connectionString'=>'mysql:host=localhost;dbname=database', 

              'username'=>'user', 

              'password'=>'password',

              'charset'=>'utf8'

        ),

  ),

);

Now the application takes different databases, depending on the servername. If want to have only one config file: http://blog.mbischof…dene-umgebungen. It is in german, but I think the code is self-explaining.

Hi guys,

Thanks for taking the time to reply. This is what my application is doing:

[Source production db]—Migrate User—>[Destination production db]

But I also want to be able to do this:

[Source test db]—Migrate User—>[Destination test db]

Since I have defined my destination DSN using Yii’s usual config files, I can easily switch between [Destination production db] and [Destination test db] by doing something along the lines of what you have described. This part is fine.

However, I can’t switch between [Source production db] and [Source test db] in the same way. My source DSN is defined in a class called SourceActiveRecord, which extends CActiveRecord. All my source models extend SourceActiveRecord.

For reference, this is what the cookbook has to say regarding working with multiple databases:

I’ve chosen to tell Yii about my destination database in the config files, and to tell Yii about my source databse in the SourceActiveRecord class. It seems that I will have to use SourceActiveRecord::db to get Yii to use [Source test db] for my unit tests.

Maybe this could help you:

http://www.yiiframew…ection-solution

I didn’t test it, but with this code it seems to be possible to define both DSN in the config file. So it should be possible to switch source and destination DSN with array_merge. Important: Qiangs reply seems to be needed for working.

UPDATE:

I have tested it with my own application and 4 databases (2dev/2prod) and it seems to work. My files:

dev.php/prod.php


<?php


return array(

    'components'=>array(        

        'db'=>array(

              'class'=>'CDbConnection',

              'connectionString'=>'mysql:host=localhost;dbname=database', 

              'username'=>'user', 

              'password'=>'password',

              'charset'=>'utf8'

        ),

        'db_source'=>array(

              'class'=>'CDbConnection',

              'connectionString'=>'mysql:host=localhost;dbname=database2', 

              'username'=>'user', 

              'password'=>'password',

              'charset'=>'utf8'

        ),

  ),

);

HActiveRecord.php


<?php


class HActiveRecord extends CActiveRecord


{


   public static $Test_db;


   public function getDbConnection()


   {


      if(self::$Test_db!==null)


         return self::$Test_db;


      else


      {


         self::$Test_db=Yii::app()->db_source;


                 //echo self::$Test_db->connectionString;


                 


         if(self::$Test_db instanceof CDbConnection)


         {


            self::$Test_db->setActive(true);


            return self::$Test_db;


         }


         else


            throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.'));


      }


   }





}


?>



[b]

YourSourceTable.php[/b]


<?php


class YourSourceTable extends HActiveRecord

{

...


}

Thanks Anticon. That worked well :slight_smile: