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

时间:2021-11-04 12:49:10

Currently i have a application that hosts multiple tenants written in CodeIgniter. But i am really loving Laravel 4 and i would like to start migrating the application to Laravel.

目前,我有一个应用程序,它托管使用CodeIgniter编写的多个租户。但是我真的很喜欢Laravel 4,我想把这个应用程序移植到Laravel。

Here is the current setup:

以下是当前的设置:

  • Each tenant has it's own database.
  • 每个租户都有自己的数据库。
  • There is just one set of application files.
  • 只有一组应用程序文件。
  • When we create a new tenant a new database is created and an install script is run and the database is seeded with some initial information.
  • 当我们创建一个新的承租者时,将创建一个新的数据库,并运行一个安装脚本,并向数据库播种一些初始信息。
  • Each tenant also has it's own subdomain. That is how we can detect which database to use.
  • 每个租户也有自己的子域。这就是我们可以检测使用哪个数据库的方法。
  • There is a main database that holds tenant information and users and some other general tables.
  • 有一个主数据库保存租户信息、用户和其他一些通用表。
  • When a schema update is needed we just create an update script that will run for each tenant. This happens via a specially coded CLI script for Codeigniter
  • 当需要模式更新时,我们只需创建一个更新脚本,该脚本将为每个租户运行。这是通过为Codeigniter编写的特殊CLI脚本实现的

In Codeigniter it's relatively easy to start and end new database connections.

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

With Laravel i have the following issues/questions.

我有以下的问题/问题。

  • How would you start/end database connections on the fly?
  • 如何动态启动/结束数据库连接?
  • I would like to use Migrations but i would like to run them for each tenant. Migrations currently only run on the "main" database connection. And it only runs once.
  • 我希望使用迁移,但我希望为每个租户运行它们。迁移目前只在“主”数据库连接上运行。它只运行一次。
  • Same goes for seeding..
  • 同样适用于播种。

These are my main issues, i have some other minor stuff but those can be worked around.

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

Hopefully someone can shed some light..

希望有人能给我们一些启示。

5 个解决方案

#1


23  

I'm just taking a stab at this, so be warned :) The DatabaseManager class, which is used whenever you call DB, has and extend method. Here's the link to the source. The DB::connection() method should return an instance of Illuminate\Database\Connection. From all this, I would create a new user connection as follows:

我只是想尝试一下,所以请注意:)DatabaseManager类具有和扩展方法,无论何时调用DB都使用它。这是到源代码的链接。方法应该返回一个实例,说明数据库\连接。由此,我将创建一个新的用户连接,如下所示:

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

Personally, I would add a new method to each user, User::databaseConnection(), and call that when I extend the DatabaseManager.

就我个人而言,我将向每个用户user:::databaseConnection()添加一个新方法,并在扩展DatabaseManager时调用该方法。

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

Through out your application you should be able to call a registered user's connection via:

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

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

Update

更新

Depending on how often and when you'd be calling the tenant connection, you may want to use the IOC container.

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

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

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

I forgot about migrations and seeding. For migrations, you can set the file path

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

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

So if you use the Config class to set the default database or DB::setDefaultConnection($username), I'd assume all migrations and seeding will be done for the current connection. When that process if complete you can switch back to you main database.

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

Update 2

更新2

The laravel developers are amazing and I should have definitely got the urge to check this out sooner than later. You can do migrations and seed on any database connection you've created.

laravel的开发人员非常棒,我应该尽快检查一下。您可以在创建的任何数据库连接上进行迁移和种子。

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

Looking at Barry's answer, that is probably a good deal simpler than extending the DatabaseManager.

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

If you want to see all the options for these commands just run:

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

artisan help migrate
artisan help db:seed

#2


6  

You can create 1 database with the tenant database credentials, and dynamically set them in your app:

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

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

This will require to create 2 connections in your database.php file. (for instance app and tenant) and specify in your model which database to use (1 for the storing of tenants, 1 for the tenant specific database)

这将需要在数据库中创建两个连接。php文件。(例如app和租户)并在模型中指定使用哪个数据库(1用于存储租户,1用于特定租户数据库)

And probably create a route/script to create/update the tables. Not sure about migrations with multiple databases.

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

#3


4  

You can create dynamic DB connections in laravel with following syntax

您可以使用以下语法创建动态数据库连接。

Config::set('database.connections.key', array(
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'dbname',
    'username'  => 'dbuser',
    'password'  => 'dbpass',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
));

With that DB::connection('key'); would just work.

DB::连接(“关键”);只会工作。

#4


0  

I've recently encountered a similar problem, had to use different Databases for several models.

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

I've found the following to do the trick.

我找到了下面的方法。

  1. In app/config/database.php add a new connection MY_NEW_CONNECTION
  2. 在app / config /数据库。php添加一个新的连接MY_NEW_CONNECTION
  3. For the new connection, set the database name to whatever
  4. 对于新连接,将数据库名称设置为任意。
  5. In your filters.php or routes.php or controller's __construct method add the following:

    在你的过滤器。php或路线。php或controller的__construct方法添加如下内容:

    $db = 'get your database name'; Config::set('database.connections.MY_NEW_CONNECTION.database',$db); DB::setDefaultConnection('MY_NEW_CONNECTION');

    $db = '获取数据库名称';配置:设置(database.connections.MY_NEW_CONNECTION.database,$ db);DB:setDefaultConnection(“MY_NEW_CONNECTION”);

#5


-3  

1) You can define multiple named connections in your database.php config file

1)可以在数据库中定义多个命名连接。php配置文件

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

Then you can choose which one to use with something like this.

然后你可以选择用哪一个像这样的东西。

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

2) This isn't a full solution as I think it will require some hacking on the core, but you can choose which connection to run a migration on. Maybe you could iterate through your list of tenants and run it on all of them.

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

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

3) Unfortunately, I don't think seeding supports multiple connections yet. You might have to roll your own seeding functionality.

不幸的是,我认为播种还不支持多种连接。您可能需要滚动自己的播种功能。

#1


23  

I'm just taking a stab at this, so be warned :) The DatabaseManager class, which is used whenever you call DB, has and extend method. Here's the link to the source. The DB::connection() method should return an instance of Illuminate\Database\Connection. From all this, I would create a new user connection as follows:

我只是想尝试一下,所以请注意:)DatabaseManager类具有和扩展方法,无论何时调用DB都使用它。这是到源代码的链接。方法应该返回一个实例,说明数据库\连接。由此,我将创建一个新的用户连接,如下所示:

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

Personally, I would add a new method to each user, User::databaseConnection(), and call that when I extend the DatabaseManager.

就我个人而言,我将向每个用户user:::databaseConnection()添加一个新方法,并在扩展DatabaseManager时调用该方法。

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

Through out your application you should be able to call a registered user's connection via:

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

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

Update

更新

Depending on how often and when you'd be calling the tenant connection, you may want to use the IOC container.

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

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

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

I forgot about migrations and seeding. For migrations, you can set the file path

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

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

So if you use the Config class to set the default database or DB::setDefaultConnection($username), I'd assume all migrations and seeding will be done for the current connection. When that process if complete you can switch back to you main database.

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

Update 2

更新2

The laravel developers are amazing and I should have definitely got the urge to check this out sooner than later. You can do migrations and seed on any database connection you've created.

laravel的开发人员非常棒,我应该尽快检查一下。您可以在创建的任何数据库连接上进行迁移和种子。

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

Looking at Barry's answer, that is probably a good deal simpler than extending the DatabaseManager.

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

If you want to see all the options for these commands just run:

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

artisan help migrate
artisan help db:seed

#2


6  

You can create 1 database with the tenant database credentials, and dynamically set them in your app:

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

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

This will require to create 2 connections in your database.php file. (for instance app and tenant) and specify in your model which database to use (1 for the storing of tenants, 1 for the tenant specific database)

这将需要在数据库中创建两个连接。php文件。(例如app和租户)并在模型中指定使用哪个数据库(1用于存储租户,1用于特定租户数据库)

And probably create a route/script to create/update the tables. Not sure about migrations with multiple databases.

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

#3


4  

You can create dynamic DB connections in laravel with following syntax

您可以使用以下语法创建动态数据库连接。

Config::set('database.connections.key', array(
    'driver'    => 'mysql',
    'host'      => 'localhost',
    'database'  => 'dbname',
    'username'  => 'dbuser',
    'password'  => 'dbpass',
    'charset'   => 'utf8',
    'collation' => 'utf8_unicode_ci',
    'prefix'    => '',
));

With that DB::connection('key'); would just work.

DB::连接(“关键”);只会工作。

#4


0  

I've recently encountered a similar problem, had to use different Databases for several models.

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

I've found the following to do the trick.

我找到了下面的方法。

  1. In app/config/database.php add a new connection MY_NEW_CONNECTION
  2. 在app / config /数据库。php添加一个新的连接MY_NEW_CONNECTION
  3. For the new connection, set the database name to whatever
  4. 对于新连接,将数据库名称设置为任意。
  5. In your filters.php or routes.php or controller's __construct method add the following:

    在你的过滤器。php或路线。php或controller的__construct方法添加如下内容:

    $db = 'get your database name'; Config::set('database.connections.MY_NEW_CONNECTION.database',$db); DB::setDefaultConnection('MY_NEW_CONNECTION');

    $db = '获取数据库名称';配置:设置(database.connections.MY_NEW_CONNECTION.database,$ db);DB:setDefaultConnection(“MY_NEW_CONNECTION”);

#5


-3  

1) You can define multiple named connections in your database.php config file

1)可以在数据库中定义多个命名连接。php配置文件

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

Then you can choose which one to use with something like this.

然后你可以选择用哪一个像这样的东西。

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

2) This isn't a full solution as I think it will require some hacking on the core, but you can choose which connection to run a migration on. Maybe you could iterate through your list of tenants and run it on all of them.

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

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

3) Unfortunately, I don't think seeding supports multiple connections yet. You might have to roll your own seeding functionality.

不幸的是,我认为播种还不支持多种连接。您可能需要滚动自己的播种功能。