Php 如何在运行时连接到不同的数据库?
我正在制作一个多租户多数据库应用程序,它有一个中央数据库和多个子数据库 该应用程序在中央数据库中创建一个组织的实例,并为每个组织创建一个包含不同表的子数据库 为了实现这一点,我制作了一个classPhp 如何在运行时连接到不同的数据库?,php,mysql,database,laravel-5,multi-tenant,Php,Mysql,Database,Laravel 5,Multi Tenant,我正在制作一个多租户多数据库应用程序,它有一个中央数据库和多个子数据库 该应用程序在中央数据库中创建一个组织的实例,并为每个组织创建一个包含不同表的子数据库 为了实现这一点,我制作了一个classSetup 创建组织 创建其数据库 配置与该数据库的连接并连接到该数据库 运行到它的正确迁移 所有这些都封装在一个构造函数中,因此在校准Setup::create时,所有这些都可以正常运行 大多数数据库配置和连接都是从中得到启发的 为了测试我的逻辑是否符合要求,我通过以下方式与我的应用程序交互: 修补匠
Setup
Setup::create时,所有这些都可以正常运行
大多数数据库配置和连接都是从中得到启发的
为了测试我的逻辑是否符合要求,我通过以下方式与我的应用程序交互:
修补匠
网络浏览器
令我惊讶的是,在这两种情况下,结果都不一样,而且就连接到另一个数据库而言,结果从来都不是人们想要的
与tinker的互动:
创建并调用我的设置::create
并让输出告诉我一切正常后,我尝试自己检查我现在使用的是什么数据库:
DB::connection()->getDatabaseName()
它输出我们刚刚为组织创建并连接到的子数据库名称,这是符合逻辑的,并且是相应的
但是,我尝试通过为另一个数据库创建一个新配置,然后使用我提供的DB
方法连接到另一个数据库,但它不起作用,我仍然在我所在的子数据库上
与浏览器交互:
这次,将我的设置::create
正确地包装在控制器的代码中,我尝试再次测试所有内容,我还在布局中画了一行,以输出当前数据库:
<?php echo DB::connection()->getDatabaseName() ?>
起初,当我仍然在中央数据库上时,它的名称出现了,但是在调用Setup::create
后,它切换到子数据库-这是预期的-但是,在一次刷新后,我又在中央数据库上了-这完全出乎意料-
那么,这里发生了什么?我怎样才能连接到我所有的不同数据库?我希望什么时候我希望什么
额外:
在tinker中进行测试时,我已经注释掉了迁移代码,留下了数据库的创建以及与数据库的连接。
令我惊讶的是,它没有连接到数据库。
所以我开始认为迁移代码与连接到数据库有关,或者tinker有我完全关注的不同行为
重要:
- 我遇到过提到使用QueryBuilder的解决方案的线程
- 请不要提供这样的答案,因为我的目标是完全切换数据库,这样我就可以毫无问题地使用雄辩模型的事件。
- 我的意思是,在连接到数据库之后,我希望能够使用
Model::create
,而不是DB::connection()->..
技术细节:
我正在Ubuntu机器上使用Laravel5和mysql服务器。我偶然发现了这一点,它给出了我的答案
我创建了一个名为数据库连接的类:
class DatabaseConnection extends Model
{
static $instances=array();
protected $database;
protected $connection;
public function __construct($options = null)
{
// Set the database
$database = $options['database'];
$this->database = $database;
// Figure out the driver and get the default configuration for the driver
$driver = isset($options['driver']) ? $options['driver'] : Config::get("database.default");
$default = Config::get("database.connections.$driver");
// Loop through our default array and update options if we have non-defaults
foreach($default as $item => $value)
{
$default[$item] = isset($options[$item]) ? $options[$item] : $default[$item];
}
$capsule = new Capsule;
$capsule->addConnection($default);
$capsule->setEventDispatcher(new Dispatcher(new Container));
$capsule->setAsGlobal();
$capsule->bootEloquent();
// Create the connection
$this->connection = $capsule->getConnection();
DatabaseConnection::$instances[] = $capsule;
return $this->connection;
}
}
因此,每当我在一个操纵子数据库表的控制器中时,我都会这样做:
public function RandomActionInMyController()
{
$db_connection = new DatabaseConnection(['database' => 'name_of_db']);
$someModel = new Model/Model::find()..// Basically anything
return myreturnstuff;
}
额外奖金:
在我的数据库连接中使用静态属性$instances
归结起来就是检索我的最新数据库连接以便于使用
例如,如果我想要检索它,它将被包装在一个函数中,例如
function CurrentOrLatestDbConnection()
{
if( !empty(DatabaseConnection::$instances) )
{
return end(DatabaseConnection::$instances)->getConnection()->getDatabaseName();
}
}
注:
如果遇到诸如未知类“容器”
或胶囊
之类的错误,请确保检查我提供的问题链接,并正确使用使用
语句
关于即将到来的答案:
在我看来,这个数据库连接位于控制器操作的括号内,因此当我继续执行另一个未指定连接的操作时,它会自动返回到中央数据库
这让我想到,必须有一种方法,以“全局”的方式将数据库连接设置到子数据库,以实现整个功能,例如中间件或其他功能
我希望看到一个答案,实现这样的事情
更新:
我想出了一个更整洁的方法
我假设你和我站在同一个立场上,希望根据每个控制器有条件地更改数据库。。。比如说,每个控制器都需要一个不同的数据库,只是为了参数
我们将使用“中间件”来解决这个问题
首先,解释一下我们将要做什么
我们将检查控制器的名称(甚至操作),然后设置我们希望设置的适当数据库
转到命令行,键入:
php artisan make:中间件SetDatabaseConnectionMiddleware
使用现成的样板创建中间件
或者,如果您非常喜欢,请转到您的app_name/app/Http/Middleware并手动创建一个
转到你的助手方法文件(如果你已经有了一个,如果没有,就做一个!)
这将向您返回一个包含操作名和控制器名的数组,如果您只想限制性地返回控制器名,请随意从代码中删除'action'=>$action
在中间件内部,它的外观如下:
4.现在,您已经正确创建了中间件,让我们告诉您的应用程序在哪里可以找到它以及它的名称
转到你的app_name/app/Http/Kernel.php
在$routeMiddleware
变量中,添加此行
“设置正确的数据”
function getControllerAndActionName()
{
$action = app('request')->route()->getAction();
$controller = class_basename($action['controller']);
list($controller, $action) = explode('@', $controller);
return ['action' => $action, 'controller' => $controller];
}
namespace App\Http\Middleware;
use Closure;
use DatabaseConnection;
class SetProperDatabase
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$database_name = '';
$controllerAndActionName = getControllerAndActionName();
$controller_name = $controllerAndActionName['controller'];
$action_name = $controllerAndActionName['action'];
if($controller_name == 'my_controller_nameController')
{
$database_name = 'your_proper_database_name';
}
else
{
$database_name = 'other_db';
}
$database_connection = new DatabaseConnection(['database' => $database_name']);
return $next($request);
}
}