Laravel 4:多租户应用程序,每个租户拥有自己的数据库和一个全局数据库

时间:2013-01-25 14:48:25

标签: php laravel laravel-4

目前我有一个托管CodeIgniter编写的多个租户的应用程序。 但我真的很喜欢Laravel 4,我想开始将应用程序迁移到Laravel。

以下是当前设置:

  • 每个租户都拥有自己的数据库。
  • 只有一组应用程序文件。
  • 当我们创建新租户时,会创建一个新数据库并运行安装脚本,并为数据库添加一些初始信息。
  • 每个租户也拥有自己的子域名。这就是我们如何检测使用哪个数据库。
  • 有一个主数据库,用于保存租户信息和用户以及其他一些通用表。
  • 当需要架构更新时,我们只需创建一个将为每个租户运行的更新脚本。这通过Codeigniter
  • 的特殊编码CLI脚本实现

在Codeigniter中,启动和结束新的数据库连接相对容易。

使用Laravel我有以下问题/问题。

  • 如何动态启动/结束数据库连接?
  • 我想使用迁移,但我想为每个租户运行它们。迁移目前仅在" main"数据库连接。它只运行一次。
  • 同样适合种子..

这些是我的主要问题,我还有其他一些小问题,但可以解决这些问题。

希望有人能说清楚......

5 个答案:

答案 0 :(得分:23)

我只是在捅这个,所以要警告:) 每当调用DB时使用的DatabaseManager类都具有和extend方法。这是link to the source。 DB :: connection()方法应该返回Illuminate\Database\Connection的实例。从这一切,我将创建一个新的用户连接如下:

$user = Auth::user();
DB::extend($user->username, function() use ($user) {
   // $pdo = new PDO(); set this up how you see fit
    return new Illuminate\Database\Connection($pdo, $user->databaseName, $tablePrefix);
});

就个人而言,我会为每个用户添加一个新方法,User :: databaseConnection(),并在扩展DatabaseManager时调用它。

DB::extend($user->username, function() use ($user) {
    return $user->databaseConnection();
});

通过您的应用程序,您应该能够通过以下方式呼叫注册用户的连接:

DB::connection(Auth::user()->username);

<强>更新

根据您调用租户连接的频率和时间,您可能希望使用IOC容器。

App::bind('tenantDB', function()
{
     return DB::connection(Auth::user()->username);
});

App::make('tenantDB')->insert(...);

我忘记了迁移和播种。对于迁移,您可以设置文件路径

php artisan migrate:make foo --path=app/migrations

因此,如果您使用Config类设置默认数据库或DB :: setDefaultConnection($ username),我假设将为当前连接完成所有迁移和种子设定。如果该过程完成,您可以切换回主数据库。

更新2

laravel的开发人员非常惊人,我应该肯定有这样的冲动,要早点检查出来。您可以在已创建的任何数据库连接上进行迁移和种子设定。

artisan migrate --database='userConnectionName' 
artisan db:seed --database='userConnectionName'

看看Barry的回答,这可能比扩展DatabaseManager更简单。

如果您想查看这些命令的所有选项,请运行:

artisan help migrate
artisan help db:seed

答案 1 :(得分:6)

您可以使用租户数据库凭据创建1个数据库,并在您的应用中动态设置它们:

$tenant = Tenant::where('username', '=', $username)->first();
Config::set('database.connections.tenant.username', $tenant->db_username);
Config::set('database.connections.tenant.password', $tenant->db_password);
Config::set('database.connections.tenant.database', $tenant->db_database);

这将需要在database.php文件中创建2个连接。 (例如app和tenant)并在模型中指定要使用的数据库(1表示存储租户,1表示租户特定数据库)

并且可能创建一个路径/脚本来创建/更新表。不确定有多个数据库的迁移。

答案 2 :(得分:4)

您可以使用以下语法

在laravel中创建动态数据库连接
Config::set('database.connections.key', array(
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'dbname',
    'username'  => 'dbuser',
    'password'  => 'dbpass',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
));

使用DB::connection('key'); would just work.

答案 3 :(得分:0)

我最近遇到了类似的问题,不得不为多个模型使用不同的数据库。

我已经找到以下方法来做这个伎俩。

  1. 在app / config / database.php中添加新连接MY_NEW_CONNECTION
  2. 对于新连接,请将数据库名称设置为
  3. 在您的filters.php或routes.php或控制器的__construct方法中添加以下内容:

    $ db =&#39;获取您的数据库名称&#39 ;; 配置::设置(&#39; database.connections.MY_NEW_CONNECTION.database&#39;,$分贝); DB :: setDefaultConnection(&#39; MY_NEW_CONNECTION&#39);

答案 4 :(得分:-3)

1)您可以在database.php配置文件中定义多个命名连接

'connections' => array(
    'tenant1' => array(
     ...
    ),
    'tenant2' => array(
     ...
    ),

然后你可以选择使用这样的东西。

$something = DB::connection('tenant1')->select(...);

2)这不是一个完整的解决方案,因为我认为它需要对核心进行一些黑客攻击,但您可以选择运行迁移的连接。也许你可以遍历你的租户列表并在所有租户上运行。

Schema::connection('tenant1')->create('users', function($table)

3)不幸的是,我不认为播种支持多个连接。您可能必须推出自己的播种功能。