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

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

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

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

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

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

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

  • [DATABASE] app (Это основная база данных приложения)
    • [TABLE] users
    • [TABLE] permissions (Не относится к этому вопросу)
  • [DATABASE] app_user1 (User.id1 владеет всей этой базой данных)
    • [TABLE] cars (a таблица, полностью принадлежащая User.id 1)
  • [DATABASE] app_user2 (User.id2 владеет всей этой базой данных)
    • [TABLE] cars (a таблица полностью принадлежит User.id 2)
  • и т.д...

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

How to use multiple databases dynamically for one model in CakePHP

Проблема!!!

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

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

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

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

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

4b9b3361

Ответ 1

Этот джентльмен (Olivier) имел ту же проблему! (Год назад) Он написал небольшую адаптацию для Controller s! Он довольно маленький, и получается, он работает в 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.

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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);

Ответ 4

В вашем database.php

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

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

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

затем примените запрос типа

this->Organisation->find('all');

Ответ 5

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

public function setDatabase($database, $datasource = 'default')
{
    $newDatasource = $datasource . '_' . $database;
    try {
        // return the new datasource if it 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;
}