I have an issue. I need a database component available for all my application. I cannot use the database component in the config/main.php because the connection parameters are dynamic, they depend in what company i am logged in. Each company has his own database with his own users. In the login page i ask for credentials and in what company the user is going to log in. After the user provides credentials and company, in SiteController/actionLogin i do this:
\Yii::$container->set(‘dbSys’, [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname='.$company->data['name'],
'username' => $company->data['userDB'],
'password' => $company->data['pwdDB'],
'charset' => 'utf8'
]); //$company is a object that store the company information
And in the User model, i override getDB static function to use this component:
public static function getDb(){
if (\Yii::$container->has('dbSys')) //If i don't use this "if" i get a Reflection Error
$dbObject = \Yii::$container->get('dbSys');
else
$dbObject = Yii::$app->db; //default db
return $dbObject;
}
So far everything works as expected. Now, i need a new model Sucursal for table sucursal. I create this with Gii (using the default db component in config/main.php just for the purpose to use Gii) and the model is created fine and working, but i need override the getDb() as in the user model, but then i get an error that class ‘dbSys’ doesn’t exist. I believed that anything set in \Yii::$container is available across all the application.
But i don’t know what am i doing wrong. In the sucusal model i cannot retrieve my component. It said that class ‘dbSys’ doesn’t exist when i use get. Has something to do that i create the model and the CRUD using Gii and a static db Component? Or maybe that i am doing the set in the SiteController and i need to do it somewhere else? I tried to use ServiceLocator setComponent too and didn’t work either. Help!!!
Here is my code for the SiteController/actionLogin, User model getDb() and Sucursal model getDb()
public function actionLogin()
{
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()))
{
\Yii::$container->setSingleton('companydata', new Company(Compania::findOne($model->companiaId)));
$company = \Yii::$container->get('companydata'); //THIS WORKS CORRECTLY
\Yii::$container->set('dbSys', [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname='.$company->data['name'],
'username' => $company->data['userDB'],
'password' => $company->data['pwdDB'],
'charset' => 'utf8'
]);
if ($model->login()) { //THIS ALSO WORKS FINE, THE USER IS LOGGED IN THE COMPANY SELECTED
return $this->goHome();
} else {
return $this->render('login', [
'model' => $model
]);
}
}
else {
return $this->render('login', [
'model' => $model
]);
}
}
In my User model
public static function getDb(){
/* I NEED THIS IF BECAUSE MY APPLICATION ALWAYS SEND THE GUEST USERS
TO THE LOGIN PAGE. THE FIRST TIME AS THERE IS NOT YET A COMPONENT,
THROWS A REFLECTION ERROR
*/
if (\Yii::$container->has('dbSys'))
$dbObject = \Yii::$container->get('dbSys');
else
$dbObject = Yii::$app->db;
return $dbObject;
}
In the Sucursal Model (Generated with Gii)
public static function getDb(){
//THIS DOESN'T WORK. THE ERROR SAYS THAT CLASS 'dbSys' doesn't exist
$dbObject = \Yii::$container->get('dbSys');
return $dbObject;
}
Elsewhere, that is why i am trying to use \Yii::$container. In my understanding, setting a class there, it makes it available anywhere without the need of set it again.
Am i understanding wrong the concept of \Yii::$container?
You understand concept of container right but it seems you understand concept of PHP wrong. At the end of each request everything is being killed and initializes again in the next request so what you did on login doesn’t affect further requests (except if you modify any of the persistent storages such as database or cookies).
I get it now. But the db component of Yii, for example, is available everywhere without set it again. Is reconstructed anytime is required using the config/main.php information? Or is stored in session variable?
Thank you very much again for your invaluable help.
I resolved my issue, in this way. I know that it seems to be not the best or cleanest solution. But for now, i am going with this, i’ve already lost several hours with this part of my application.
I changed in the site controller where the database information is gonna be stored, using session instead a custom object:
//In SiteController/actionLogin
$modelCompany = Compania::findOne($model->companiaId); //Retrieve company selected in login form
$session = Yii::$app->session; //Use session to store the database information
$session['company'] = [
'name' => $modelCompany->nombre,
'uid' => $modelCompany->compania_uid,
'id' => $modelCompany->compania_id,
'userDB' => $modelCompany->database_user,
'pwdDB' => $modelCompany->database_password
];
//..................
In user model
public static function getDb(){
$session = Yii::$app->session;
if (isset($session['company']))
{
/*AppDbComponent is a sinlgeton which returns de yii\db\component instanciated with the session variables*/
$appDb = \frontend\components\AppDbComponent::instance();
$dbObject = $appDb->getComponent($session['company']['name'], 3307, $session['company']['userDB'], $session['company']
['pwdDB']);
}
else
$dbObject = ActiveRecord::getDb();
return $dbObject;
}