Hola Colisteros,
Estoy armando una aplicación Yii2 advanced con MySQL; lo que quiero es que los usuarios del Frontend al momento de ingresar su usuario y contraseña se defina la base de datos que le corresponde, de tal forma que cada empresa tenga su propia base de datos.
Resolví esto de la siguiente manera:
Creé una base de datos de administración "app_admin"; en esa base de datos tengo dos tablas "user" y "accounts"; la tabla "user" controla el acceso de los usuarios y si es correcto su usr y psw obtengo sus datos de cuenta donde entre otros tengo "accounts.dsn", "accounts.dbusr" y "accounts.dbpsw" que son los datos de acceso a la base de datos de la cuenta que le corresponde a ese usuario que está ingresando.
Tengo otra(s) base(s) de dato(s) para cada una de las cuentas "app_xxxx", "app_yyyy", etcétera.
Y en los códigos de esta forma:
"frontend/index.php"
...
$application = new yii\web\Application($config);
// is there a user logged?
if (!Yii::$app->user->isGuest) {
// dynamic configuration for 'db' from user->account
Yii::$app->db->dsn = Yii::$app->user->identity->account->dsn; //'mysql:host=localhost;dbname=app_xxxx';
Yii::$app->db->username = Yii::$app->user->identity->account->dbusr; //'root';
Yii::$app->db->password = Yii::$app->user->identity->account->dbpsw; //'';
Yii::$app->db->charset = 'utf8mb4';
}
$application->run();
"common/config/main-local.php"
<?php
return [
'components' => [
'db' => [
'class' => 'yii\db\Connection',
],
'db_admin' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=app_admin',
'username' => 'root',
'password' => '',
'charset' => 'utf8mb4',
],
...
"common/models/user.php"
...
class User extends ActiveRecord implements IdentityInterface
{
...
public static function getDb()
{
// use the "db_admin" application component
return \Yii::$app->db_admin;
}
public function getAccount()
{
return $this->hasOne(Accounts::className(), ['pin' => 'account_pin']);
}
...
"backend/models/accounts.php"
...
class Accounts extends \yii\db\ActiveRecord
{
...
public static function getDb()
{
// use the "db_admin" application component
return \Yii::$app->db_admin;
}
...
"common/models/LoginForm.php"
class LoginForm extends Model
{
...
public function login()
{
if ( ($this->validate() ... ) ) {
// dynamic configuration for 'db' from user->account
Yii::$app->db->dsn = $this->getUser()->account->dsn; //'mysql:host=localhost;dbname=app_xxxx';
Yii::$app->db->username = $this->getUser()->account->dbusr; //'root';
Yii::$app->db->password = $this->getUser()->account->dbpsw; //'';
Yii::$app->db->charset = 'utf8mb4';
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0);
} else {
$this->addError('username', Yii::t('app', 'No tiene acceso a esta sección.'));
return false;
}
}
...
Al iniciar la aplicación el usuario es un invitado y es mandado al login, el modelo de user y accounts están en la base de datos app_admin; si las credenciales del usuario son correctas se obtienen los datos de su cuenta para definir la base de datos que le corresponde por ejemplo "app_xxxx"; el resto de las consultas se hacen en esa base de datos.
Mis dudadas son:
¿Estoy haciendo lo correcto?
¿Es segura esta solución?
¿Hay alguna mejor forma de hacerlo?
Por otro lado; tengo algunas tablas que dependen de "user"; por ejemplo, tengo una relación muchos a muchos con una "junction table" entre usuarios y sucursales: user -> user_subsidiaries -> subsidiaries; Como ya quedamos; la tabla "user" está en la base de datos "app_admin" y la tabla "subsidiaries" está en cada una de las base de datos de cada cuenta.
¿Cómo se resuelven este tipo de relaciones?
Perdón por alargarme tanto y muchas gracias por su atención,
Saludos.