3

I'm working on a project where multiple websites will be run from one Yii installation. Each website will have his own database though, so the database connection must be dynamically.

What i did, i created a BeginRequestBehavior which will be launched 'onBeginRequest'. Here i will check which url has been called and determine the matching database (not in my code yet) and create (or overwrite) the 'db' component.

<?php
class BeginRequestBehavior extends CBehavior
{

    /**
     * Attaches the behavior object to the component.
     * @param CComponent the component that this behavior is to be attached to
     * @return void
     */

    public function attach($owner)
    {

        $owner->attachEventHandler('onBeginRequest', array($this, 'switchDatabase'));

    }

    /**
     * Change database based on current url, each website has his own database.
     * Config component 'db' is overwritten with this value
     * @param $event event that is called
     * @return void
     */

    public function switchDatabase($event)
    {
        // Here some logic to check which url has been called..

        $db = Yii::createComponent(array(
            'class' => 'CDbConnection',
            'connectionString' => 'mysql:host=localhost;dbname=test',
            'emulatePrepare' => true,
            'username' => 'secret',
            'password' => 'verysecret',
            'charset' => 'utf8',
            'enableProfiling' => true,
            'enableParamLogging' => true
        ));

        Yii::app()->setComponent('db', $db);

    }
}

It's working fine, but is this the correct approach? In other approaches i see people creating their own 'MyActiveRecord' (extending CActiveRecord) for their models and putting the db component in a property. Why do they do it? I'm afraid the database connection will be made too many times than necessary this way.

2 Answers 2

5

I use a model function for define her DB connection:

public static $conection; // Model attribute

public function getDbConnection(){

    if(self::$conection!==null)
        return self::$conection;

    else{
        self::$conection = Yii::app()->db2; // main.php - DB config name

        if(self::$conection instanceof CDbConnection){
            self::$conection->setActive(true);
            return self::$conection;
        }
        else
            throw new CDbException(Yii::t('yii',"Active Record requires a '$conection' CDbConnection application component."));
    }
}

main.php :

 'db'=>array( 
    'connectionString' => 'mysql:host=192.168.1.*;dbname=database1',
    'emulatePrepare' => true,
    'username' => 'root',
    'password' => 'password',
    'charset' => 'utf8',
    'enableProfiling'=>true,
    'enableParamLogging' => true,
),
'db2'=>array(
    'class'=>'CDbConnection',
    'connectionString' => 'mysql:host=192.168.1.*;dbname=database2',
    'emulatePrepare' => true,
    'username' => 'root',
    'password' => 'password',
    'charset' => 'utf8',
),
Sign up to request clarification or add additional context in comments.

1 Comment

I don't need multiple databases, just one, which changes depending on the url you are on. What is the reason you're putting the db component in the $conection property?
0

A much cooler way to use multiple db connection when using yii:

In other words, you need 1 main db to store user profile and a db connection;

For the other slave dbs, you need a single setting; You will switch the db connection when needed. I switch it in my eg using the user id.

I have generated using gii the model for a slave db table, and i think that all your slave db have the same table structure, and on top of that model, i use another class, as shown here;

    'db' => array(
        'class' => 'PortalDbConnection',
        'connectionString' => 'mysql:host=localhost;dbname=mydb',
        'username' => 'dev',
        'password' => '123456',
        'tablePrefix' => '',
        'emulatePrepare' => true,
        'enableParamLogging' => true,
        'enableProfiling' => true,
        'charset' => 'utf8',
    ),
    'dbx' => array(
        'connectionString' => 'mysql:host=localhost;dbname=mydb1',
        'username' => 'dev',
        'password' => '123456',
        'charset' => 'utf8',
        'tablePrefix' => '',
        'autoConnect' => false,
        'class' => 'CDbConnection', //this may be the reason you get errors! always set this
    ),

and now, the php code for your model:

<?php

class DomainSlaveM extends Domain {

    public static function model($className = __CLASS__) {
        return parent::model($className);
    }

    public static $server_id = 1;
    public static $slave_db;

public function getDbConnection() {
    self::$slave_db = Yii::app()->dbx;
    if (self::$slave_db instanceof CDbConnection) {
        self::$slave_db->active = false;
        $config = require(Yii::app()->getBasePath() . '/config/location/flavius.php');
        $connectionString = $config['components']['dbx']['connectionString'];
        self::$slave_db->connectionString = sprintf($connectionString, self::$server_id);
        self::$slave_db->setActive(true);
        return self::$slave_db;
    }
    else
        throw new CDbException(Yii::t('yii', 'Active Record requires a "db" CDbConnection application component.'));
}

    }

and use it like this:

    public function createDomainSlaveM($model) {
//switch the db connection; $server_id gets values, from 1 to N
            DomainSlaveM::$server_id = $model->user_id;
            $model_domain_slave_m = new DomainSlaveM();
            $model_domain_slave_m->attributes = $model->attributes;
            if ($model_domain_slave_m->validate() && $model_domain_slave_m->save()) {
                //ok
            } else {
                //bad
            }
        }

1 Comment

I know i can do it like this, but in my case i don't need multiple databases, just one, which changes depending on the url you are.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.