如何在CakePHP中为一个模型动态使用多个数据库

时间:2012-11-04 23:11:11

标签: php mysql cakephp model multiple-databases

好的,我的第一个问题被修改了很多次,我选择删除它并重新构建我的问题。我已经创建了一个具有不同模型名称的小型测试用例项目,以便为我的问题找到合适的解决方案。

警告:请勿将数据库表格混合

动机:我将用户数据分为多个数据库以用于法律和表现问题。

目前我正在开发一个 CakePHP 项目,该项目有多个User,每个User都有自己的数据库,其中有多个< strong>表格(cars表格之一)。现在,我需要先解释一下:

每个User都有自己的数据库(不是表格,数据库),因此数据库名称如下所示。

  • [DATABASE] app(这是应用的主数据库)
    • [TABLE] users
    • [TABLE] permissions与此问题无关
  • [数据库] app_user1User.id 1拥有整个数据库
    • [TABLE] cars完全归User.id所有)1)
  • [数据库] app_user2User.id 2拥有整个数据库
    • [TABLE] cars完全归User.id所有} 2)
  • 等...

我做了一个小图,可能会澄清数据库 / - 定义及其与模型的关系:

How to use multiple databases dynamically for one model in CakePHP

问题!!!

我不知道连接到哪个数据库,直到User登录。User并且他们的数据库是动态创建的,所以我不能使用app/Config/database.php

所以我正在编写ModelConnectionManager类的扩展,以绕过CakePHP的基本数据库行为。因此Car模型知道要使用哪个数据库。但我只是觉得这可以更轻松!

所以我猜这一切归结为一个问题:

有更简单的方法吗?

感谢任何愿意花时间和精力阅读和理解我的问题的人!

5 个答案:

答案 0 :(得分:37)

This gentlemanOlivier)遇到了同样的问题! (一年前)He wrote Controller的一个小改编!它非常小,事实证明,它适用于 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社区。

答案 1 :(得分:9)

我不喜欢在代码中写下数据库的实际名称。 对于多个数据库,您有database.php文件,您可以根据需要设置任意数量的数据库。

如果要“动态”“切换”特定型号的数据库,请使用 setDataSource 方法。 (见here

例如,如果您有两个数据库,则可以在database.php文件中将它们定义为“default”和“sandbox”,作为示例。

然后,在您的代码中:

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

沙箱是配置的名称,数据库的实际名称只在database.php文件中写入一次。

答案 2 :(得分:1)

您始终可以使用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);

答案 3 :(得分:1)

在您的database.php

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

在您的控制器中,您可以使用

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

然后应用像

这样的查询
this->Organisation->find('all');

答案 4 :(得分:0)

这是一个被接受的答案的人。如果新数据源已经存在,这将防止错误:

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