Динамические подключения к базе данных с помощью Zend

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

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

Это возможно? И если да, то как мне реализовать динамическое соединение с базой данных (скажем, в действии, которое проверяет их данные для входа).

Любая помощь будет принята с благодарностью.


person machinemessiah    schedule 12.10.2010    source источник


Ответы (2)


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

Например, получите имя вторичной базы данных для данного пользователя:

$db = Zend_Db::factory(...options...);
$secondary_db = $db->query("SELECT secondary_db 
    FROM user_data WHERE user = ?", $userid)
   ->fetchOne();

Затем запустите запрос, чтобы изменить схему. Обратите внимание, что оператор USE не может быть подготовленным оператором, поэтому вы должны выполнить его с помощью API драйвера:

$db->getConnection()->query("use $secondary_db");

Теперь, если вы ссылаетесь на таблицу без уточнения ее схемы, вы получите экземпляр таблицы во вторичной базе данных. Это включает в себя любой запрос, который вы запускаете через адаптер Zend_Db или классы таблиц и т. д.

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

person Bill Karwin    schedule 12.10.2010
comment
Спасибо, Билл, у меня есть пара вопросов относительно этого решения (потерпите, я не эксперт). 1. Могу ли я поместить свой USE-запрос в метод конструктора абстрактного класса, который расширяет Zend_Db_Table_Abstract, прямо перед тем, как я вызову функцию конструктора родителя, а затем все мои модели будут расширять абстрактный класс? - person machinemessiah; 12.10.2010
comment
2. Когда вы говорите Но оператор USE работает только в том случае, если ваши вторичные базы данных находятся в том же экземпляре базы данных, что и ваша первичная база данных с данными пользователя, можете ли вы уточнить, я не совсем уверен, что вы имеете в виду, и буду ли я удовлетворять это состояние. Еще раз спасибо! - person machinemessiah; 12.10.2010
comment
Он имеет в виду, что вам придется использовать один и тот же экземпляр сервера/dsn... например, все базы данных должны быть доступны с сервера mysql по адресу mysql://localhost, а не mysql://mysql.auth.local и mysql://mysql.userbase.local. - person prodigitalson; 12.10.2010
comment
@prodigitalson: Верно, но я использую термин «экземпляр», потому что теоретически у вас может быть более одного экземпляра MySQL, работающего на одном физическом сервере (хотя это необычно). - person Bill Karwin; 12.10.2010
comment
@machinemessiah: я бы не стал помещать USE-запрос в класс абстрактной таблицы, я бы сделал это сразу после аутентификации пользователя. Держите информацию (какой пользователь) близко к действию (ИСПОЛЬЗУЙТЕ БД этого пользователя). - person Bill Karwin; 12.10.2010
comment
Спасибо вам обоим, вы очень помогли! - person machinemessiah; 13.10.2010

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

public function loginAction()
{
   $request = $this->getRequest();
   $user = $request->getParam('username');
   $pass = $request->getParam('password');

   $auth = new My_Auth_Adapter($user, $pass);
   $authResult = Zend_Auth::getInstance()->authenticate($auth);

   if($authResult->isValid()){
      My_Db_Manager::connectForUser($authResult->getIdentity());
   }
}

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

person prodigitalson    schedule 12.10.2010