Yii2 dynamic connection to second database - php

I have a simple select in my View code. It represents list of cities and on my server there're several databases which are responsible for each city. I have my Model code and it takes city_id. Depends on it I want to connect to database and seek for needed data in it. I've added second database to my components like:
'db' => require(__DIR__ . '/db.php'),
'db2' => require(__DIR__ . '/db_login.php'),
and two files which returns database connection.
File 1:
'class' => 'yii\db\Connection',
'dsn' => $dsn,
'username' => $username,
'password' => $password,
'charset' => 'utf8',
File 2:
'class' => 'yii\db\Connection',
'dsn' => $dsn,
'username' => $username,
'password' => $password,
'charset' => 'utf8',
I want to change my database name somehow dynamically right after users' choice.

You can do a call for dbconnection
$actual_dsn = 'your_dns_actual_value'
$yourConnection = new \yii\db\Connection([
'dsn' => $actual_dsn,
'username' => $username,
'password' => $password,
]);
$yourConnection->open();
eventually close the previous open connection
You can do this in your db_login.php depending of the application's needs

Maybe :
if (choice =='a') {
'db' => require(__DIR__ . '/db.php')
}
else {
'db2' => require(__DIR__ . '/db_login.php')
}

Related

Yii2 set db connection at runtime

In my Yii2 (basic application) web.php I configure a NULL db connection as 2nd database connection.
This needs to be filled with valid parameters which are coming from a record on the main db connection:
'db' => require(__DIR__ . '/db.php'),
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => NULL,
'username' => NULL,
'password' => NULL,
'charset' => 'utf8',
],
After initializing the app() i need to fill out the NULL parameters with values that i retrieve from another database to further use it in models.
How can i achieve this in Yii2?
No problem, it is supported
\Yii::$app->db2->close(); // make sure it clean
\Yii::$app->db2->dsn= 'yourdsn';
\Yii::$app->db2->username = 'username';
\Yii::$app->db2->password = 'password';
Done, now you can use it
Yii::$app->db2->...
Another way:
$connection = new \yii\db\Connection([
'dsn' => $dsn,
'username' => $username,
'password' => $password,
]);
$connection->open();
$command = $connection->createCommand('SELECT * FROM post')->....;
Refer: http://www.yiiframework.com/doc-2.0/yii-db-connection.html

Multi-tenant SaaS built in Yii2

I am working in a multi-tenant software (SaaS) built with yii2 on the Advanced Template, but I am not having the desired result about the tenants database connection.
I am trying to set the Database Connection as next in my config file for the frontend:
$defaultAdminDB = [
'class' => 'yii\db\Connection',
'dsn' => 'pgsql:host=localhost;dbname=untitled',
'username' => 'postgres',
'password' => 'myPass',
'charset' => 'utf8',
];
$config = [
'components' => [
'db' => function(){
if (Yii::$app->session->get('login', false)){
return [
'class' => 'yii\db\Connection',
'dsn' => Yii::$app->session->get('client_connection.dns'),
'username' => Yii::$app->session->get('client_connection.username'),
'password' => Yii::$app->session->get('client_connection.password'),
'charset' => 'utf8',
];
}
return [
'class' => 'yii\db\Connection',
'dsn' => 'pgsql:host=localhost;dbname=untitled',
'username' => 'postgres',
'password' => 'myPass',
'charset' => 'utf8',
];
},
'dbAdmin' => $defaultAdminDB
]
];
Then I have a two steps log in, where the first asks for the login (tenant id) and the next provides the user and password. On the first controller I do the next with:
$account = \frontend\models\AdminAccounts::findOne(['login'=>$this->login]);
if (!$account){
$this->addError('login', Yii::t('app', 'Account data not found.'));
return false;
}
$dns = sprintf('pgsql:host=%s;dbname=%s', $account->getAttribute('db_host'), $account->getAttribute('db'));
Yii::$app->session->set('login', $this->login);
Yii::$app->session->set('client_connection.dns', $dns);
Yii::$app->session->set('client_connection.username', $account->getAttribute('db_user'));
Yii::$app->session->set('client_connection.password', $account->getAttribute('db_pass'));
I get successfully the account (tenant) data and store it in session, but I guess my error is on instantiating the yii\db\Connection on the model's getDb() method.
Hope can help me.
Regards!
If you are changing the db connection info of an existing db connection then you should close the existing connection (Yii::$app->db->close()), change the connection info, and then open the new connection (Yii::$app->db->open()).
You can try
Yii::$app->db = new \yii\db\Connection([
'dsn' => Yii::$app->session->get('client_connection.dsn'),
'username' => Yii::$app->session->get('client_connection.username'),
'password' => Yii::$app->session->get('client_connection.password'),
]);

Yii 2.0 : 2 database connection

I read this question yii 2.0 multiple database connection, and use the answer of #Ali MasudianPour.
I follow the first step:
First you need to configure your databases like below:
return [
'components' => [
'db1' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=database1',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=database2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
],
]; ?>
But in my configuration in my db it gives me this error:
The configuration for the "db" component must contain a "class"
element.
This is because db component is main and required and you simply omitted its declaration.
Rename db1 and db2 for example to db and db1 accordingly:
return [
'components' => [
// Main connection
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=database1',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
// Another connection
'db1' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=database2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
],
]; ?>
Update:
Note that for the basic application db is configured in separate file config/db.php and then required in main config config/web.php like so:
'db' => require(__DIR__ . '/db.php'),
So you can configure main connection in db.php and add additional below as db1.
Simply you just have to create separate file for each database .
config/db ->
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=database1',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
To access another db create file in config named db1.php add add another db configuration.
config/db1 ->
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=database2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
In config->web.php add
'db' => require(__DIR__ . '/db.php'),
'db1' => require(__DIR__ . '/db1.php'),
To access the Model:
public static function getDb() {
return Yii::$app->db1;
}

How to setup an SSL encrypted MySQL connection with Doctrine2 in PHP (not Symfony, not Doctrine1)

I am having a hard time finding documentation / examples of how to setup an SSL encrypted connection with Doctrine2 to MySQL. I'm not using Symfony, so looking for the pure PHP path.
What I'm stuck on is basically how to convey the MYSQL_CLIENT_SSL (or MYSQLI_CLIENT_SSL) flag, and the path to the ca certificate. I can live with not verifying the certificate, but I can't live with not encrypting the connection for this task.
On the command line this would be done similar to this:
mysql --ssl-verify-server-cert --ssl-ca=/mysql-ssl-certs/ca-cert.pem --ssl -h host [etc]
In pure php using the mysql extension I think it would look something like:
$conn = mysql_connect($host, $user, $pass, false, MYSQL_CLIENT_SSL);
With mysqli (i think) it would be something like this:
$db = mysqli_init();
$db->ssl_set(null, null, $cert, null, null);
$db->real_connect($host, $user, $pass, $dbname);
The question is, how do I do this with Doctrine2? Is it even possible? How do I modify the initialization for Doctrine2 to do this?
$DOCTRINE2_DB = array(
'driver' => 'pdo_mysql',
'host' => $host,
'user' => $user,
'password' => $pass,
'dbname' => $dbname,
'unix_socket' => $sockpath,
);
$DOCTRINE2_EM = \Doctrine\ORM\EntityManager::create($DOCTRINE2_DB, $DOCTRINE2_CONFIG);
$EM =& $DOCTRINE2_EM; // for brevity & sanity
You should be able to add an additional parameter driverOptions and set the appropiate SSL configuration for PDO
http://es1.php.net/manual/es/ref.pdo-mysql.php#pdo-mysql.constants
$DOCTRINE2_DB = array(
'driver' => 'pdo_mysql',
'host' => $host,
'user' => $user,
'password' => $pass,
'dbname' => $dbname,
'unix_socket' => $sockpath,
'driverOptions' => array(
PDO::MYSQL_ATTR_SSL_CA => '...',
PDO::MYSQL_ATTR_SSL_CERT => '...',
PDO::MYSQL_ATTR_SSL_KEY => '...'
)
);
I can't test it but looking at the code here I think it should work
[EDIT BY ASKER:]
Here is how it worked for me:
$DOCTRINE2_DB = array(
'driver' => 'pdo_mysql',
'host' => $host,
'user' => $user,
'password' => $pass,
'dbname' => $dbname,
'unix_socket' => $sockpath,
'driverOptions' => array(
PDO::MYSQL_ATTR_SSL_CA => '/file/path/to/ca_cert.pem',
)
);

Add connection to DBAL dynamically in Silex

I am writing a PHP application using the Silex framework. I'm using the Doctrine Service Provider, and I can open a connection normally as this:
$app->register(new Silex\Provider\DoctrineServiceProvider(), array(
'dbs.options' => array (
'localhost' => array(
'driver' => 'pdo_mysql',
'host' => 'localhost',
'dbname' => 'test',
'user' => 'root',
'password' => 'root',
'charset' => 'utf8',
)
),
));
That works perfectly. What I want now is to add another database connection afterwards in my code. I know I can do it adding another element to dbs.options, but I want to do it afterwards, in the controllers (as different controllers will use different database connections).
Is that possible? I guess I could use something like DriverManager::getConnection($options, $config, $manager); but there's probably a better way to do it.
Thanks!
$conn = DriverManager::getConnection($params, $config);
this is original code to generate new connection, so what you wrote is ok
Link: http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html
You can configure multiple db connections using the DoctrineServiceProvider bundled with Silex.
Replace the db.options with an array of configurations where keys are connection names and values configuration options.
$app->register(new Silex\Provider\DoctrineServiceProvider(), array(
'dbs.options' => array (
'mysql_read' => array(
'driver' => 'pdo_mysql',
'host' => 'mysql_read.someplace.tld',
'dbname' => 'my_database',
'user' => 'my_username',
'password' => 'my_password',
'charset' => 'utf8',
),
'mysql_write' => array(
'driver' => 'pdo_mysql',
'host' => 'mysql_write.someplace.tld',
'dbname' => 'my_database',
'user' => 'my_username',
'password' => 'my_password',
'charset' => 'utf8',
),
),
));
Access multiple connections in your controllers:
$app->get('/blog/{id}', function ($id) use ($app) {
$sql = "SELECT * FROM posts WHERE id = ?";
$post = $app['dbs']['mysql_read']->fetchAssoc($sql, array((int) $id));
$sql = "UPDATE posts SET value = ? WHERE id = ?";
$app['dbs']['mysql_write']->executeUpdate($sql, array('newValue', (int) $id));
return "<h1>{$post['title']}</h1>".
"<p>{$post['body']}</p>";
});
Source: http://silex.sensiolabs.org/doc/providers/doctrine.html

Categories