Yii动态数据库连接根据用户?

时间:2012-03-13 12:49:21

标签: yii

我的项目是基于多租户的。

我有多个客户(公司),每个客户都有多个用户。

每个客户端都有自己的数据库,因此在用户身份验证期间,我会发现该用户的关联数据库的名称。

每个数据库的结构相同......只有数据不同。

这样我们就可以为不同的公司保留不同的数据库,而不会混淆数据库中的数据。

编写应用程序时,未知客户端数量(以及数据库数量),因此无法在引导脚本中包含所有连接。

现在,我想要做的是,动态地改变引导程序中的数据库连接,或者能够为登录的用户动态创建新连接。在Yii中是否有一个简单的解决方案,仍然使用AR,查询构建器?

同样的问题在yii论坛上被问到仍未得到明确答复,.... 你可以在Yii dynamic dabatabase connection

找到这个问题

5 个答案:

答案 0 :(得分:7)

我和论坛上发布的qiang一样。您需要一个数据库连接列表以及Yii::app()->user处登录用户的属性,该属性告诉您要使用哪个连接(我为其示例命名为connectionId)。 然后,您在ActiveRecord基类中覆盖getDbConnection()

public function getDbConnection()
{
    if(self::$db!==null)
        return self::$db;
    else
    {
        // list of connections is an array of CDbConnection configurations indexed by connectionId
        $listOfConnections=/* to be loaded somehow */;
        // create DB connection based on your spec here:
        self::$db=new CDbConnection($listOfConnections[Yii::app()->user->connectionId]);
        self::$db->active=true;
        return self::$db;
    }
}

答案 1 :(得分:3)

感谢您的宝贵帮助,

对于我的应用程序,我需要多个数据库,

a)主数据库,其中包含有关公司的所有信息,称其为'projectmaster'

b)公司sa'company1'的数据库

所以,我在yii \ framework \ db \ ar \ CActiveRecord.php中修改了代码,如下所示,

self::$db=Yii::app()->getDb();
if(self::$db instanceof CDbConnection)
{
    $db=Yii::app()->db;
    $constring=array();
    $constring=$db->createCommand()
        ->select('dbname,host,dbusername,dbpassword')
        ->from('projectmaster')
        ->where('company_name =company1')
        ->queryRow();
    self::$db=new CDbConnection('mysql:host='.$constring['host'].';dbname='.$constring['dbname'],$constring['dbusername'],$constring['dbpassword']);

self::$db->active=true;
return self::$db;

}

这里我使用现有连接创建新的连接对象'self :: $ db', 这是覆盖旧连接还是创建新连接

当我必须使用'createCommand()'来获取某些数据时,我没有使用活动记录类,

所以我的连接对象是时间,

$连接= Yii的::应用程序() - >分贝; $命令= $连接 - > createCommand($ SQL);

这里我正在设置由yii创建的旧连接'$ connection'.... 但对于应用程序,它应该使用新连接,以便从“company1”数据库获取数据。

所以我想创建应该可重用的连接。是否可以更改yiii连接,或者每当我们想要使用自定义查询时,我们都必须重新连接。

答案 2 :(得分:3)

我不确定@Jurish的回答是否及时,但几天前我遇到了完全相同的问题,here就是我解决问题的方法。

简而言之,您应该扩展 CActiveRecord 类,不仅要覆盖 getDbConnection(),还要覆盖类构造函数和 model()函数。

class SuperRecord extends CActiveRecord {

public static $host;
public static $port;
public static $user;
public static $pass;

public static $connection = null;

function __construct($dbName = null, $scenario='insert') {
    if ($tenant != null) {
         Yii::app()->params['activeDb'] = $dbName;
    }
    self::$host = Yii::app()->params['defaultDbHost'];
    self::$port = Yii::app()->params['defaultDbPort'];
    self::$user = Yii::app()->params['superDbUser'];
    self::$pass = Yii::app()->params['suPassword'];
    parent::__construct($scenario);
    Yii::app()->params['activeDb'] = ''; //destruct sensitive data after using
}

public function getDbConnection() {
    if(self::$connection!==null)
        return self::$connection;
    else
    {
        $connectionString = 'mysql:host='.self::$host.';port='.self::$port.';dbname='.Yii::app()->params['activeDb'];
        self::$connection=new CDbConnection($connectionString, self::$user, self::$pass);
        self::$connection->emulatePrepare = true;
        self::$connection->charset = 'utf8';
        self::$connection->active=true;
        if(self::$connection instanceof CDbConnection)
            return self::$connection;
        else
            throw new CDbException(Yii::t('yii','Active Record requires a "db" CDbConnection application component.'));
    }
}

public static function superModel($dbName, $className=__CLASS__) {
    Yii::app()->params['activeDb'] = $dbName;
    return self::model($className);
}

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

之后,您将能够创建连接到数据库的任何模型,您将发送给构造函数的名称,如下所示:

$messagesModel = new UserMessages($databaseName);

或那:

$messages = UserMessages::superModel($databaseName)->findAll();

查看article,我试图尽可能清楚地解释它。

答案 3 :(得分:2)

的Yii ::应用程序() - > DB-> SETACTIVE(假);

Yii :: app() - > db-> connectionString ='mysql:host = localhost; dbname ='。trim($ databasename);

的Yii ::应用程序() - > DB-> SETACTIVE(真);

答案 4 :(得分:0)

搞定了

首先,我有一个名为companyMainDb的主Db,它拥有所有用户信息以及他们的公司ID

每家公司都有不同的数据库,名为 company_company_id

第1步:

      Go to web/index.php

第2步:

像这样改变

require(__DIR__ . '/../vendor/autoload.php');
Dotenv::load(__DIR__ . '/../');

// comment out the following two lines when deployed to production
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', getenv('YII_ENV'));

require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');

$config = require(__DIR__ . '/../config/web.php');
  

new yii \ web \ Application($ config);

     

的Yii :: $ APP-&GT;用户&GT; isGuest $ DBNAME = 'companyMainDb':?$ DBNAME = '公司_' 的Yii :: $ APP-&GT;用户&GT; identity-&GT; COMPANY_ID; < / p>      

$ config ['components'] ['db'] = ['class'=&gt; 'yii \ db \ Connection','dsn'   =&GT; 'mysql:host ='。 GETENV( 'DB_HOST')。 '; dbname ='。$ dbName,'username'=&gt; getenv('DB_USER'),'password'=&gt; getenv('DB_PASSWORD'),'charset'=&gt; 'utf8',];

(new yii\web\Application($config))->run();