質問

I'm just starting to learn Laravel and I managed to use the Auth class for a simple login.

Now, what is required for my application is the following:

I have a global database called 'global' which has some tables, including 'sysadmins' and 'tenants'. I also have a database for each tenant, called 'tenant_{id}' where {id} is the id of the tenant. Also, in each 'tenant_{id}' database there is a 'users' table.

So, when the users logs in, he should give his email (or username), password AND the id of the tenant he belongs to (some might suggest that I identify through subdomains, well that's not the issue for now). So, the user would input [john], [* * * *], [5].

Now he should be authenticated against the 'tenant_5'.'users' table and it should be defined globally that the database for his session is the 'tenant_5' database. So, when he a model like Car::all();, the database that is used is, you guessed it, 'tenant_5'.

I've spent the entire day searching for a solution and experimenting but I don't understand enough of the framework to tweak it too much.

役に立ちましたか?

解決

I've solved this myself:

First of all, we create a route group to the subdomain, excluding 'www' with a pattern:

Route::pattern('id', '[0-9]+');

Route::group(array('domain' => '{subdomain}.mysite.com', 'before' => 'switchDB'), function() {
    // Publicly accessible routes under the subdomain
    Route::group(array('before' => 'guest'), function() {
        // login routes (get and post)
    });

    // Routes under the subdomain that require authentication
    Route::group(array('before' => 'auth'), function() {
    });
});

// Publicly accessible routes in the main domain
Route::get('/', array('uses' => 'PublicController@showHome'));

Then the filter, where we get the subdomain and check in our default database (global database) what account has that domain. We also check if that database exists.

Route::filter('switchDB', function($route, $request) {
    $parts = explode('.', $request->getHost());
    $subdomain = $parts[0];

    $account = Account::where('subdomain', '=', $subdomain)->first();
    if($account == null) {
        App::abort(404);
    }

    $res = DB::select("SHOW DATABASES LIKE '" . $account->db_name . "'");
    if(count($res) == 0) {
        App::abort(404);
    }

    Config::set('database.connections.mysql.database', $account->db_name);
    DB::reconnect();
    Session::put('subdomain', $subdomain);
});

The DB::reconnect() seems to be a key player in all of this.

他のヒント

This is how you would set the config at runtime:

Config::set('database.connections.mysql.database', 'tenant_5');

Then you could put the database name in the session with:

Session::put('db_used', 'tenant_5');

And then in your start/global.php file you could do a check:

if(Session::has('db_used'))
{
    Config::set('database.connections.mysql.database', Session::get('db_used'));
}

Not tested but you should be able to do it this way.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top