Как динамически использовать несколько баз данных для одной модели в CakePHP


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

Предупреждение: Не смешивайте базы данных с таблицами

Мотивация: Я разделил пользовательские данные на несколько баз данных по юридическим вопросам и вопросам производительности.

В настоящее время я работаю над CakePHP проект, который имеет несколько User, и каждый User имеет свою собственную базу данных с несколькими таблицами (cars является одной из таблиц ). Теперь мне нужно сначала кое-что объяснить:

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

  • [БАЗА ДАННЫХ] app (Это основная база данных приложения)
    • [ТАБЛИЦА] users
    • [ТАБЛИЦА] permissions ( Не имеет отношения к делу для этого вопроса)
  • [БАЗА ДАННЫХ] app_user1 (User.id 1 владеет всей этой базой данных )
    • [ТАБЛИЦА] cars (таблица полностью принадлежит User.id 1)
  • [БАЗА ДАННЫХ] app_user2 (User.id 2 владеет всей этой базой данных )
    • [ТАБЛИЦА] cars (таблица полностью принадлежит User.id 2)
  • и т.д....

Я сделал небольшой рисунок, который мог бы прояснить базу данных / таблица - определения и их связь с моделями:

How to use multiple databases dynamically for one model in CakePHP

В чем проблема!!!

Я не знаю, к какой базе данных подключиться, пока User не войдет в систему. User и их базы данных создаются динамически, поэтому я не могу использовать app/Config/database.php.

Поэтому в настоящее время я пишу расширение для классов Model и ConnectionManager, чтобы обойти базовое поведение базы данных CakePHP. Таким образом, модель Car знает, какую базу данных использовать. Но у меня просто такое чувство, что это можно было бы сделать проще!

Так что, я думаю, все сводится к одному вопросу:

Есть ли более простой способ сделать это?!

Спасибо всем, кто потратит время и усилия на чтение и понимание моей проблемы!

Author: Ariaan, 2012-11-05

5 answers

Этот джентльмен ( У Оливье) была та же проблема! (Год назад) Он написал небольшую адаптацию для Controllers! Он довольно маленький, и, оказывается, он работает в 1.3 и 2.x.

В любом случае, это мое окончательное решение, которое я вложил в app/Model/AppModel.php:

class AppModel extends Model
{
  /**
   * Connects to specified database
   *
   * @param String name of different database to connect with.
   * @param String name of existing datasource
   * @return boolean true on success, false on failure
   * @access public
   */
    public function setDatabase($database, $datasource = 'default')
    {
      $nds = $datasource . '_' . $database;      
      $db  = &ConnectionManager::getDataSource($datasource);

      $db->setConfig(array(
        'name'       => $nds,
        'database'   => $database,
        'persistent' => false
      ));

      if ( $ds = ConnectionManager::create($nds, $db->config) ) {
        $this->useDbConfig  = $nds;
        $this->cacheQueries = false;
        return true;
      }

      return false;
    }
}

И вот как я использовал его в своем app/Controller/CarsController.php:

class CarsController extends AppController
{
  public function index()
  {
    $this->Car->setDatabase('cake_sandbox_client3');

    $cars = $this->Car->find('all');

    $this->set('cars', $cars);
  }

}

Держу пари, я не первый и не последний, кто столкнулся с этой проблемой. Поэтому я действительно надеюсь, что эта информация найдет людей и Сообщество CakePHP.

 37
Author: Ariaan, 2017-05-23 11:54:51

Мне не нравится идея записывать фактическое имя базы данных в коде. Для нескольких баз данных у вас есть database.php файл, в котором вы можете установить столько баз данных, сколько вам нужно.

Если вы хотите "переключить" базу данных для определенной модели на лету , используйте метод setDataSource. (см. здесь)

Например, если у вас есть две базы данных, вы можете определить их в database.php файл как "по умолчанию" и "песочница", как пример.

Затем в вашем коде:

$this->Car->setDataSource('sandbox');

Изолированная среда - это имя конфигурации, а фактическое имя базы данных записывается только один раз в database.php файл.

 9
Author: noamicko, 2013-01-31 09:47:47

Вы всегда можете запросить любые базы данных, используя полную нотацию в mysql. F.например:

SELECT * FROM my_schema_name.table_name;

Способ приготовления торта:

$db = $this->getDataSource();
$query = array(
    'fields' => array('*'),
    'table' => 'my_schema_name.table_name'
);
$stmt = $db->buildStatement($query, $this);
$result = $db->execute($stmt);
 1
Author: bancer, 2014-05-05 08:11:40

В вашем database.php

public $mongo = array(
    'datasource' => 'Mongodb.MongodbSource',
    'database' => 'database_name_mongo',
    'host' => 'localhost',
    'port' => 27017,
);

В вашем контроллере вы можете использовать

$this->Organisation->setDataSource('mongo');

Затем примените запрос, подобный

this->Organisation->find('all');
 1
Author: teju c, 2017-05-09 07:17:56

Это народ принятого ответа. Это предотвратит ошибку, если новый источник данных уже существовал:

public function setDatabase($database, $datasource = 'default')
{
    $newDatasource = $datasource . '_' . $database;
    try {
        // return the new datasource if it's already existed
        $db = ConnectionManager::getDataSource($newDatasource);
        $this->useDbConfig  = $newDatasource;
        $this->cacheQueries = false;
        return true;
    } catch (Exception $e) {
        // debug($e->getMessage());
    }

    $db  = ConnectionManager::getDataSource($datasource);
    $db->setConfig(array(
        'name'       => $newDatasource,
        'database'   => $database,
        'persistent' => false
    ));

    if ( $ds = ConnectionManager::create($newDatasource, $db->config) ) {
        $this->useDbConfig  = $newDatasource;
        $this->cacheQueries = false;
        return true;
    }

    return false;
}
 0
Author: ktran, 2018-02-27 10:30:51