I have two databases. The second database changes dynamically, i.e. each client has its own database so the database name and password are different but the architecture is the same for all clients. So I have two model groups, the first for the first database and the second for the second database. Indeed, the second model group must be able to make queries to the client database and not to the default database
so I want to set the default database connection dynamically.Config::Set() will do it for one request only. I want it for every subsequent request.
I use the Laravel Framework, you know of a clean solution that might solve my problem and help others interested
thanks to everyone for your help
Create two entries in config/database.php:
'connections' => array(
# Connection one
'mysql_1' => array(
'driver' => 'mysql_1',
'host' => 'host_1',
'database' => 'db_1',
'username' => 'username_1',
'password' => 'password_1'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
# Connection two
'mysql_2' => array(
'driver' => 'mysql_2',
'host' => 'host_2',
'database' => 'db_2',
'username' => 'username_2',
'password' => 'password_2'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
),
Create a base model or a Trait for each group of models which sets the connection at the model level. Change all your models to extends from their respective base model.
Base Models
class BaseGroupOneModel extends Model
{
protected $connection = 'mysql_1';
}
class BaseGroupTwoModel extends Model
{
protected $connection = 'mysql_2';
}
Traits
trait GroupOneTrait
{
protected $connection = 'mysql_1';
}
trait GroupTwoTrait
{
protected $connection = 'mysql_2';
}
class GroupOneModel extends Model
{
use app/Models/Traits/GroupOneTrait;
}
class GroupTwoModel extends Model
{
use app/Models/Traits/GroupTwoTrait;
}
Related
I want to change databases connection string and its credentials
on runtime.
I Have master database and many children databases.
And want to switch databses string and its credentials stored in master DB.
not like this Yii::$app->db, Yii::$app->db2, .. connections name
I found the solution to switch DB
Yii provides to set or override component by Yii::$app->set() function.
So we can override it any where within application.
In case of globally change the database, we can override it in on beforeRequest accrding to condition
In config/main.php
'components'=>[
...
],
'on beforeRequest' => function() {
$model = app\models\MainFY::findOne(Yii::$app->session->get('activeSession'));
Yii::$app->set('db', [
'class' => 'yii\db\Connection',
'dsn' => $model->db_string,
'username' => $model->db_username,
'password' => $model->db_password,
'charset' => 'utf8',
'enableSchemaCache' => !YII_DEBUG,
]);
},
in model app\models\MainFY , I am using main DB connection
public static function getDb() {
return Yii::$app->dbMain;
}
I have a task which is described like "Creating a new database with Yii2 migration, and use it by default". But I have some collusion: I have to set up at lest one default database in my main-local.php file to start migration. But also I have to create this database with initial migration.
return [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=default_base',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
];
How can I deal with it? To create a database with migration and set up as default one.
When I execute my migration (there is code from my migration file):
public function safeUp()
{
$this->execute("CREATE DATABASE default_base");
}
I have an exception:
General error: 1007 Can't create database 'default_base'; database exists
I realize that is because I have already created default_base in phpmyadmin (click button "created database"), and connected it with app in my main-local.php file.
But I need this base to be created only when I execute yii migrate.
UPD
I have tried the way rob006 recommended but I get connection error
Exception 'yii\db\Exception' with message 'SQLSTATE[HY000] [1049] Unknown database 'default_base''
My main-local.php looks like the way exactly rob006 recommends, but I still can`t migrate. It works only if I set:
'preinstallDb' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=already_exists_db',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
With the already exists database. What do I do wrong again?
You can define DSN without database name:
'dsn' => 'mysql:host=localhost',
And use this connection to create database.
Yii::$app->preinstallDb->createCommand('CREATE DATABASE default_base')->execute();
However you can't really create database in migration - MigrateController needs database for migration table to save migrations history. You would need to create database before MigrateController will try to access migration table. You can do this by overriding MigrateController::getMigrationHistory():
class MigrateController extends \yii\console\controllers\MigrateController {
protected function getMigrationHistory($limit) {
Yii::$app->preinstallDb->createCommand('CREATE DATABASE IF NOT EXISTS default_base')->execute();
return parent::getMigrationHistory($limit);
}
}
And use your controller in console app config:
'controllerMap' => [
'migrate' => [
'class' => MigrateController::class,
],
],
But honestly, it is ugly solution with a lot of hardcoding, it may be better to create some setup utility which will perform database creation outside of main app. Also usually for security reasons DB user used by application should not even have privileges to create database, so you may reconsider your use case - do you really need to create database by app?
I find the only way make it work for me. Just overriding init() in MigrateController.
First I added controllerMap in main-local.php file:
'controllerMap' => [
'migrate' => [
'class' => 'console\controllers\MigrateController',]]
Then put new controller in console\controllers:
namespace console\controllers;
use yii\console\controllers\MigrateController as BasicMigrateController;
use Yii;
class MigrateController extends BasicMigrateController
{
public function init()
{
Yii::$app->preinstallDb->createCommand('CREATE DATABASE IF NOT EXISTS default_base')->execute();
parent::init();
}
}
I'm trying to change the database connection used in cakephp 3 on the fly. Every answer to this question that I found refers to cakephp 2 (These three for instance).
This guy found a solution for cakephp 3 having a finite number of databases, and specifically defining which Database would be used by which Table file.
The thing is that I want to create a new database for every new user, and change to his database when he logs in. I can't know in advance all the databases that will exist, to write it in the config/app.php file.
And I can't set the default database in each /src/Model/Table file, because the tables are the same in every database.
Use the ConnectionManager::config() function to create connections on the fly and the ConnnectionManager::alias() method to make all your Table classes use it by default.
There is a very good article describing the process here:
http://mark-story.com/posts/view/using-cakephp-and-a-horizontally-sharded-database
The only difference is that you can create the connection config on the fly instead of declaring the shards manually as it was shown in that article.
Change database connection for one model:
In app.php :
'test' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => MySQL_HOST,
//'port' => 'nonstandard_port_number',
'port' => MySQL_PORT,
'username' => MySQL_USER,
'password' => MySQL_PASS,
'database' => 'test',
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
'log' => false,
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
]
In Controller :
$conn = ConnectionManager::get('test');
$_model = TableRegistry::get('your_alias', ['table' => 'your_table', 'connection' => $conn]);
Configuring table connections
namespace App\Model\Table;
use Cake\ORM\Table;
class ArticlesTable extends Table
{
public static function defaultConnectionName() {
return 'replica_db';
}
}
I want to connect to another database sometimes.
I created a config.php with the database connection data.
But how can i tell laravel to connect to this database insted of using the config/database.php?
For example when using the Schema class.
Since no one seems to understand what i want.
I DON'T want to use the config/database.php, i want to use a different config file on a different location.
It sounds like you figured this out. Here's how I'd accomplish it anyway for other people coming in, or in case something useful is here for you.
First, Add a second connection in app/config/database.php. Note: That file path may change depending on your environment.
<?php
return array(
'connections' => array(
'mysql' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database1',
'username' => 'user1',
'password' => 'pass1'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
'mysql2' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database2',
'username' => 'user2',
'password' => 'pass2'
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
),
);
Second, in your code, you can use (as mentioned) the 2nd connection where you would like:
Schema::connection('mysql2')->create('users', function($table) {})
There's more documentation on this - see Accessing Connections.
Eloquent ORM
You can define the variable for "connection" in an eloquent class to set which connection is used. That's noted in the Basic Usage section.
See that variable on here on Github and the method which you can set to set the connection dynamically here.
Edit
The OP has made it clear that they do not wish to use the config/database.php file for config.
However without explaining further, I can't comment. I'm happy to help - sounds like it would be useful to know why the config/database.php file can't/shouldn't be used, as this can help us ascertain the problem and create a useful solution.
I believe you want to implement some kind of logical sharding where databases would be dynamically created.
In such scenario in laravel you can dynamically add a database config, like below
$conn = array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'DATABASE',
'username' => 'USERNAME',
'password' => 'SOME_PASSWORD',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
);
Config::set('database.connections.DB_CONFIG_NAME', $conn);
Now to connect via eloquent
MODEL::on('DB_CONFIG_NAME')->WHAT_EVER('1');
Incase of Query Builder you can do
$DB = DB::connection('DB_CONFIG_NAME');
use $DB->select() for querying now.
Hope this would help devs looking for a possible solution for this question
Remember that Laravel 4 is actually a collection of components, and you can use these components solo.
https://github.com/illuminate/database
There is an example here that shows off how interacting with the Capsule class works:
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule;
$capsule->addConnection([
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'database',
'username' => 'root',
'password' => 'password',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
]);
// Set the event dispatcher used by Eloquent models... (optional)
use Illuminate\Events\Dispatcher;
use Illuminate\Container\Container;
$capsule->setEventDispatcher(new Dispatcher(new Container));
// Set the cache manager instance used by connections... (optional)
$capsule->setCacheManager(...);
// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();
// Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher())
$capsule->bootEloquent();
This is a bunch of bootstrapping that you'll need to run, so tuck it away somewhere in a function or method.
But, its absolutely possible.
There is a simpler solution. If you are using Larave 4 there is an option that worked for me. Recently they added $table variable that you can specify in your model. Refer to this link.
class User extends Eloquent {
protected $table = 'my_users';
}
If you are using MySQL, you can do the following:
class User extends Eloquent {
protected $table = 'mydbname.my_users';
}
If you are using SQL Server, you can do this:
class User extends Eloquent {
protected $table = 'mydatabase..my_users';
}
My Config file had DB1 specified but I created a model which wants to access DB2 in the same MySQL host. So this was a quick and dirty way to accomplish this.
Now I don't fully leverage Eloquent ORM all the time so this "hack" may not work with Many to Many or one to Many Eloquent methods.
One another idea I had but I didn't actually try was creating a stored procedure (routine) in DB1 and inside of that routine I can access DB2 tables by querying link this:
SELECT * from db2.mytable where id = 1;
To use a config file in another location, say src/config:
use Config;
$this->dbConfig = Config::get('appname::dbInfo.connections.test');
$this->database = $this->dbConfig['database'];
$this->username= $this->dbConfig['username'];
$this->password= $this->dbConfig['password'];
Where dbInfo is a simple php file in your app's src/config directory returning an array containing the element connections which is an array of database properties.
You can tell Laravel to use an external config file using:
Config::set("database.connections.test", $this->dbConfig);
DB::connection("test");
Edit bootstrap/start.php file and add your machine name (open terminal: hostname).
Add your machine to $env,
$env = $app->detectEnvironment(array(
'mymachine' => array('mymachine.local'),
));
Create a new path at 'app/config/mymachine'
Add a copy of database.php with new config params.
I'm following along in the Yii book and am on CH5 (page 101). In our unit tests, it has us define an array that specifies which fixture(s) to use:
class ProjectTest extends CDbTestCase {
}
public $fixtures=array (
'projects'=>'Project', );
But, the fixtures file is created in 'protected/tests/fixtures/tbl_project.php' and clearly isn't named 'projects'. How does Yii infer this? Note: my DB table is named tbl_project.
Thanks :)
you need to define table prefix for your db and then create the models again.
This is how your 'db' definition would look like if you are using mysql (in config > main.php under 'components')
'db'=>array(
'connectionString' => 'mysql:host=localhost;dbname=test',
'emulatePrepare' => true,
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'tablePrefix'=>'tbl_',
),
Once you have the prefix in place, yii should be able to name your models excluding the prefix.