YII2 Ajax Multiple DB connection - yii2

I am working with YII2.0 Multiple DB connection using ajax,i having multiple database like account, customer_1,customer_2..customer_n
in account database having user table then each user in that table have the corresponding DB.
Based on the user_id i like to connect the DB using ajax.is there have any possibility to do this.
Thanks in advance for your idea and suggestion .

you can do something similar as below to create run time db connection. you need to get right dbname and other details from your main database to create below temp connection
//create temp db connection
$config_temp = [
'components' => [
'tempdb' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=HOSTNAME;dbname=DBNAME',
'username' => USERNAME,
'password' => PWD,
'charset' => 'utf8',
],
],
];
$odb = Yii::createObject($config_temp['components']['tempdb']);
//link user group for current org
$sql = "SQL STATEMENT";
$command_temp = $odb->createCommand($sql);

Related

cakephp + phpunit + gitlab continuous integration

I'm looking for help with my tests in cakephp + phpunit + gitlab-ci.
I defined my test/fixtures like this: public $import = ['model' => 'MyModel']; to avoid having to redefine the tables schema in the fixture, and have out of sync/wrong code.
I understand that what it does is to look for the live db and use that information to generate the tables in the test db, but what about if there is no live db?
I'm trying to automate my testing in gitlab / continuous integration environment, and there they provide you a mysql container with a single db to run your tests. If I have a single DB, i will not be able to have both a main connection and the testing db, right?
I was thinking on having a create-db-for-tests.sql and imprort that script BUT I understand that running a test with a fixture will remove the table, so I would need to create it again and again on every test.
I could not use the gitlab mysql service and install mysql in the testing container to have 2 databases, like in dev, but I would need to populate the other DB with some script too, and that's the same as defining the db structure in the fixtures.
How can I solve this problem?
Any help will be gladly appreciated.
Something came out from my mind after I read your question.
If you don't have live db, there might be two possibility which is
you may have staging db or your application don't have DB.
According to your second question related about If I have single DB, I would say No. Because, you could have two connections.
e.g
public $default = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'root',
'password' => 'root',
'database' => 'foge',
'prefix' => '',
'encoding' => 'utf8mb4',
);
public $test = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'root',
'password' => 'root',
'database' => 'test_foge',
'prefix' => '',
'encoding' => 'utf8mb4',
);
When creating a fixture you will mainly define two things: how the table is created (which fields are part of the table), and which records will be initially populated to the table.
I think, you can populate your script with this. Because this is mysql command. But, say honestly i haven't try it before.
mysql -u jenkins -pcakephp_jenkins -e 'DROP DATABASE IF EXISTS test_foge; CREATE DATABASE test_foge; CREATE TABLE users; CREATE Table posts';
And the last one is you can populate data before you run it and I guess you already knew it.
class ArticleFixture extends CakeTestFixture {
public $fields = array(
'id' => array('type' => 'integer', 'key' => 'primary'),
'title' => array('type' => 'string', 'length' => 255, 'null' => false),
'body' => 'text',
'published' => array('type' => 'integer', 'default' => '0', 'null' => false),
'created' => 'datetime',
'updated' => 'datetime'
);
public function init() {
$this->records = array(
array(
'id' => 1,
'title' => 'First Article',
'body' => 'First Article Body',
'published' => '1',
'created' => date('Y-m-d H:i:s'),
'updated' => date('Y-m-d H:i:s'),
),
);
parent::init();
}
}
As my personal perspective, good idea to drop and re-create the database before each build as well. This insulates you from chained failures, where one broken build causes others to fail.

CakePHP connections while testing

i am currently trying to unit test some of my code. I am executing some manually entered SQL statements like this:
$db = ConnectionManager::get('default');
...
$stmt = $db->prepare($sql);
$stmt->execute();
I assumed that whenever I run unit tests and request the default connection I will get the test connection instead. If it is not defined in my config it will throw an exception.
When I run a test which executes a statement against the database it is always executed against the default connection. The test connection is never used.
Any idea what I am doing wrong?
My database config is as follows:
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'dbname',
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
],
/**
* The test connection is used during the test suite.
*/
'test' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'root',
'password' => '',
'database' => 'dbname_test',
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
],
]
Thanks for any help!
Edit
I think the documentation is wrong:
By default CakePHP will alias each connection in your application. Each connection defined in your application’s bootstrap that does not start with test_ will have a test_ prefixed alias created. Aliasing connections ensures, you don’t accidentally use the wrong connection in test cases. Connection aliasing is transparent to the rest of your application. For example if you use the ‘default’ connection, instead you will get the test connection in test cases. If you use the ‘replica’ connection, the test suite will attempt to use ‘test_replica’.
Link
You can read there that CakePHP is aliasing the default connection automatically to test when running unit tests. To get that behaviour you have to define that alias yourself in your phpunit bootstrap.php like so:
\Cake\Datasource\ConnectionManager::alias('test', 'default');
You can read about that here ConnectionManager::alias The funny thing is that the documentation for alias explicitly states
For example, if you alias 'default' to 'test', fetching 'default' will always return the 'test' connection as long as the alias is defined.
We also had the same error, for some tables tests were getting default db instead of test db for no reason. In the end using code at the top of the setUp function (before parent::setUp()) solved the problem (we have a main test class from which we extend all tests, do some setting up. We put it there)
TableRegistry::clear();
The connection aliasing is done by default when you load the fixtures manager listener in our phpunit.xml config as it is distributed in the app template:
https://github.com/cakephp/app/blob/master/phpunit.xml.dist#L23-L31

Cakephp 3.0 ConnectionManager, getDataSource in Controller

In CakePHP 3.0, what's the equivalent of calling getDataSource() from inside a controller (like $this->ModelName->getDataSource()in cakephp 2.x)?
I have tried this:
use Cake\Datasource\ConnectionManager;
$conn = ConnectionManager::get('my_connection');
Since this connection is connected already, why do I need to provide 'my_connection'?
How can I can get the DataSource from inside a Controller in CakePHP 3.0?
Thanks
Database\ConnectionManager::get() has been added. It replaces getDataSource()
CakePHP Cookbook 3
Begin, commit and rollback are now functions on the connection, not the data source. Use $conn = ConnectionManager::get($connectionName) and then use $conn->begin(), $conn->commit() and $conn->rollback().
http://book.cakephp.org/3.0/en/orm/database-basics.html#using-transactions
And use $this->Table->defaultConnectionName() to get the connection name to pass to get.
"my_connection" should be defined in cakephp 3 config
.go to cakephp/config/app.php
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
/**
* CakePHP will use the default DB port based on the driver selected
* MySQL on MAMP uses port 8889, MAMP users will want to uncomment
* the following line and set the port accordingly
*/
//'port' => 'non_standard_port_number',
'username' => 'root',
'password' => '',
'database' => 'cake',
'encoding' => 'utf8',
'timezone' => 'UTC',
'flags' => [],
'cacheMetadata' => true,
'log' => false,
connection name is "default" for this case.
Each Model that used in controller have one Connection.
You can get connection in controller from model by this method.
$model=TableRegistry::get('table_name');
$connection = $model->connection();

Site Resilient MediaWiki Install

I am trying to set up a MediaWiki site at work. I want it to be resilient across multiple sites, so what I am planning is 1 master database to take writes, and then a local slave database for each web install. This will mean I will have:
Server 1: MySQL Master
Server 2: MySQL Slave, Apache + MW
Server 3: MySQL Slave, Apache + MW
...
Server N: MySQL Slave, Apache + MW
What I want to happen, is if a site "goes dark", they will still have a local copy of the MW running in Read-Only mode, until it is able to contact the Master MySQL server again. I have set up the below configuration file on 1 of the slave hosts, which works fine. However, once I turn off the Master MySQL server to simulate a loss of connection, MW comes up with a DB error instead of just becoming Read-Only.
$wgDBservers = array(
array('host' => "10.10.10.10",
'dbname' => "db",
'user' => "####",
'password' => "####",
'type' => "mysql",
'flags' => DBO_DEFAULT,
'load' => 0),
array('host' => "localhost",
'dbname' => "db",
'user' => "####",
'password' => "####",
'type' => "mysql",
'flags' => DBO_DEFAULT,
'load' => 1)
);
Have I missed something from the configuration and this is something that I am able to do, or does it not work because it is not intended to work that way? Any help is appreciated.
This is not in any way "best practice" but in lieu of any other answer, I am posting it for anyone needing a quick work-around.
It is a PHP script that sits directly in the LocalSettings.php file and checks the status of the Master Database. The "proper" way to do it would probably be with an extension, but I don't have time to learn how to make one. You need to ensure that the user account that you are using to connect to MySQL, has Read-Only access to the slave database.
$wgDBSite_Master = array('host' => "<master ip>", 'dbname' => "<database>", 'user' => "<user>", 'password' => "<pass>", 'type' => "mysql", 'flags' => DBO_DEFAULT, 'load' => 0);
$Site_MasterTest = mysql_connect($wgDBSite_Master['host'], $wgDBSite_Master['user'], $wgDBSite_Master['password']);
if (!$Site_MasterTest) {
$wgReadOnly = 'Wiki failed to contact the Master server. Your site is currently running Dark. No edits will be saved.<br>Last Error: '.mysql_error();
$wgSiteNotice = $wgReadOnly;
$wgDBservers = array();
}
else {
$wgSiteNotice = 'Everything running normally, Captain';
$wgDBservers = array( $wgDBSite_Master );
}
$wgDBservers[] = array('host' => "localhost", 'dbname' => "<database>", 'user' => '<user>', 'password' => "<pass>", 'type' => "mysql", 'flags' => DBO_DEFAULT, 'load' => 1);

How to PASS your own mysql connection to Zend_DB?

I have my own mysql_connect ...etc until i wanted to use ZEND framework in particular with Zend_DB .How do I pass my connection to be used as an adapter to ZEND?
$myconn = mysql_connect('...blab',blah etc...)
eg. Zend_DB_table::setAdapter($myconn);
Don't connect to DB on your own, rather use the factory
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test'
));
This way you can connect to DB, but it will connect only once you need the connection and thus optimize for performance...