Yii Динамическое соединение с БД в соответствии с пользователем? - PullRequest
8 голосов
/ 13 марта 2012

Мой проект на основе мультитенанта.

У меня есть несколько клиентов (компаний), и у каждого клиента есть несколько пользователей.

Каждый клиент имеет свою собственную базу данных, поэтому во время аутентификации пользователя я обнаруживаю имя связанной базы данных для этого пользователя.

Структура каждой базы данных идентична ... отличаются только данные.

Чтобы мы могли хранить разные базы данных для разных компаний, которые не будут смешивать данные в базе данных.

Количество клиентов (и, следовательно, количество баз данных) неизвестно при написании приложения, поэтому невозможно включить все соединения в сценарий начальной загрузки.

Теперь я хочу динамически изменить соединение с БД, которое находится в начальной загрузке, или иметь возможность динамически создавать новое соединение для входа пользователя. Существует ли простое решение для этого в Yii и по-прежнему используется AR, построитель запросов?

Тот же вопрос был задан на форуме yii, на который до сих пор нет четкого ответа .... Вы можете найти этот вопрос здесь Соединение с динамической базой данных Yii

Ответы [ 5 ]

7 голосов
/ 13 марта 2012

Я бы сделал то же самое, что и Цян, опубликованный на форуме.Вам нужен список подключений к базе данных и свойство зарегистрированного пользователя по адресу Yii::app()->user, в котором указано, какое соединение использовать (для моего примера я назову его connectionId).Затем вы переопределяете getDbConnection() в базовом классе ActiveRecord:

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;
    }
}
3 голосов
/ 21 марта 2014

Не уверен, что мой ответ пришел вовремя для @Gaurish, но у меня была точно такая же проблема несколько дней назад, и здесь - это то, как я ее решил.

Вкратце, вы должны расширить 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();

Ознакомьтесь с статьей , я попытался объяснить это как можно более четко.

3 голосов
/ 18 апреля 2012

Спасибо за вашу ценную помощь,

Для моего приложения мне нужно несколько баз данных,

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 :: приложение () -> дб; $ Команда = $ connection-> CreateCommand ($ SQL);

здесь я получаю старое соединение '$ connection', созданное yii .... Но для приложения он должен использовать новое соединение, чтобы получать данные из базы данных «company1».

Итак, я хочу создать соединение, которое следует использовать повторно. Можно ли изменить соединение yiii или нам нужно создавать новое соединение каждый раз, когда мы хотим использовать пользовательский запрос.

2 голосов
/ 19 октября 2015

Yii :: app () -> db-> setActive (false);

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

Yii :: app () -> db-> setActive (true);

0 голосов
/ 20 сентября 2016

Понял

Прежде всего, у меня есть основной Db, называемый companyMainDb, в котором есть вся пользовательская информация вместе с идентификатором их компании

У каждой компании разные базы данных, названные 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-> user-> isGuest $ DbName = 'companyMainDb': $ DbName = 'Компания _' Yii :: $ app-> user-> использованием личных данных> company_id;

.

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

(new yii\web\Application($config))->run();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...