Laravel changing Database - php

I'm rather new to Laravel 4. What I have is a bunch of sports statistics information and for organization purposes I have a database for every sport (NFL, MLB, etc...). What I want to do is change the DB easily in queries and mimic the functionality of $myslqi->select_db() but aside from setting up a bunch of database connections in the config file, I can't find a way to do what I'm looking for. It's all the same connection and same user, I just want to be able to switch the DB without having to insert a variable into SQL in order to point to the right database.

You will need to define the connections in the config/database like so:
'nba' => array(
'driver' => 'mysql',
...
),
'nfl' => array(
'driver' => 'mysql',
...
),
And then use these in models schema or queries
class NbaPlayers extends Eloquent {
protected $connection = 'nba';
//other stuff on your model
}
$nflplayers = DB::connection('nfl')->whatever
If you define the connection in the model, you will use model::all() or whatever without having to define the connection everytime

Related

Laravel ORM: Query without table prefix

I'm working on a project where I have to integrate with some tables form wordpress and other systems. To setup the database for my Laravel project I chose to use table a prefix and for my project tables it's working fine.
My problem is when I have to work with tables from other systems using Laravel. For example, the query below adds my project's table prefix to it:
$item = DB::table('cnp_item')
->where('code', $row[1])
->first();
Instead of querying the cnp_item table it's querying laravel_cnp_item table, which does not exist.
I know it makes sense since I configured a table prefix. My question is if there is anything I could do in some queries to make it ignore my table prefix.
Thanks for any help
You could define a different a different connection in config/database.php that omits the prefix setting:
'connections' => [
'mysql' => [
...
'prefix' => 'laravel',
...
], 'alternate' => [
...
'prefix' => '',
...
]
],
Then, if you want to query a table that doesn't have that connection, switch to it on the fly using DB::connection():
$item = DB::connection('alternate')->table('cnp_item')->where('code', $row[1])->first();
Or, if you use a Model, you should be able to define the connection and table, so you'd simply have to do:
class CNPItem extends Model {
protected $connection = 'alternate';
protected $table = 'cnp_items';
...
}
Then you'd simply query like so:
$item = CNPItem::where('code', $row[1])->first();

CakePHP 3 dynamic database connection

In the controller I want to change my default database connection, such that I can access a different database. It used to work, I created a function in the AppController, calling it in each controller when needed, containing the following:
ConnectionManager::config('database', [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => $username,
'password' => $password,
'database' => $database,
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
]);
ConnectionManager::alias('database', 'default');
I created a new database connection, calling it 'database', and aliased default to this connection, such that instead of the default connection, this connection will be used. However, when I print
$this->{$modelName}->connection()->config();
It still gives the default connection. And an error saying the table doesn't exist, confirms I am not in the new connection's database.
Aliases are only picked up at table instantiation time
Alising connections on the fly generally works fine, but models / table classes only pick up connections up on their own once when they are being instantiated.
So if it doesn't work for a specific table, this is most probably because it has already been instantiated and picked up the default connection (the table registry only instantiates a table class once per alias).
So, either make sure that the tables are being instanted afterwards, which may require clearing (TableRegistry::clear()) / removing from (TableRegistry::remove()) the registry if the alias needs to be created late in the request cycle (which however could cause other problems, as you'd loose possibly applied dynamic configuration), or set the connection on the involved table(s) manually:
\Cake\Datasource\ConnectionManager::alias('database', 'default');
$connection = \Cake\Datasource\ConnectionManager::get('default');
$this->{$modelName}->setConnection($connection); // connection() before CakePHP 3.4
Apply connections dynamically in a more automated fashion
If you need this on multiple, or maybe all tables, or if you just want to shift away the responsibility from the controller (it most probably shouldn't be overly involved in configuring the model layer), then maybe dispatch an event when creating the alias, and use a base table class or a behavior that listens to the event, or maybe even use a "service" that knows about the tables and updates the tables connections accordingly.
\Cake\Datasource\ConnectionManager::alias('database', 'default');
$connection = \Cake\Datasource\ConnectionManager::get('default');
$event = new \Cake\Event\Event('Connection.aliased', $connection, ['source' => 'default']);
\Cake\Event\EventManager::instance()->dispatch($event);
For example in a table you could then do something like this, applying the new connection in case the table is configured to use the connection that has been aliased, ie if defaultConnectionName() === 'default', then pick up the new connection:
\Cake\Event\EventManager::instance()->on(
'Connection.aliased',
function (\Cake\Event\Event $event) {
// data() before CakePHP 3.4
if ($event->getData('source') === static::defaultConnectionName()) {
$this->setConnection($event->getSubject()); // subject() before CakePHP 3.4
}
}
);
See also
Cookbook > Events
Cookbook > Database Access & ORM > Behaviors
I built a sample project with dynamic connections based on the session variable.
I hope somebody find it useful:
https://github.com/jszoja/cakephp3-multidb
I documented it there.

CakePHP 3 - use multiple database connections *without ORM*

I have a CakePHP 3.4.6 web application. Due to the fact it's working with legacy (not written in Cake convention) database tables, we have opted to hand-code all of our SQL queries rather than trying to set up Table and Entity classes. I realise some people will disagree with this, but that's not the point of the question.
I have 3 databases: app_db, users_db, extra_db.
I've configured connections to each one in config/app.php such that:
'Datasources' => [
'default' => [], // 'app_db' credentials
'users_db' => [], // 'users_db' credentials
'extra_db' => [], // 'extra_db' credentials
];
I have a custom Model file located at src/Model/MyModel.php. An example of it being used to do a query on one of the databases (app_db) works like this:
namespace App\Model;
use Cake\Datasource\ConnectionManager;
class MyModel
{
protected $connection;
public function __construct()
{
$this->connection = ConnectionManager::get('default');
}
public function getData()
{
$sql = ''; // some SQL query
$stmt = $this->connection->prepare($sql);
$stmt->execute();
return $stmt->fetchAll('assoc');
}
}
This works because it gets the connection for default which maps to app_db.
But, I now want to run a query which needs to get data from app_db and JOIN with data from users_db.
How do I configure this in the Model so that the SQL will communicate with the other databases?
Simple way would be, to have another method, which will change connection.
public function switchConnection($connection=''){
$this->connection = ConnectionManager::get(connection);
}
end call it for change connection
MyModel->switchConnection('app_db');
next time you run getData, it will communicate with app_db instead of default.

Yii2 change active database based on controller

I need to change yii2 active database in controller.
What I have so far:
Yii::$app->db = new yii\db\Connection([
'dsn' => 'dblib:host='.$company->host.';port=1433;dbname=Interface',
'username' => $company->db_user,
'password' => $company->db_password,
]);
Yii::$app->db->open();
$users = User::find()->all();
Can I change active database like that and then start using models in new database and how?
You can define multiple databases in the config file with both databases referring to different objects. Use the object with the respective database you want to use.
For example:
If you have two databases defined in the config file db and db1.
Then you can just use db1 instead of db wherever you need.

Get database credentials from master database, then connect to different database

I have an instanced web application that uses different databases for every instance but uses the same files.
What I want my application to do on boot:
Get database credentials from master instance table. This instance table is in the default 'mysql' connection that I have defined in app/config/database.php.
Connect to the instance database from that point on (I don't need the master instance database anymore)
I have tried to do this in my App:before() event, but that won't work as I don't have a sessions table in my master database. If I do it before the return array() in database.php it obviously can't connect because it doesn't have the correct master database credentials yet.
Where am I supposed to do this? Should I just disable sessions and do it in my App::before() and then enable sessions after?
Don't think its possible, But here is a possibility.
Read / Write Connections
Sometimes you may wish to use one database connection for SELECT statements, and another for INSERT, UPDATE, and DELETE statements. Laravel makes this a breeze, and the proper connections will always be used whether you are using raw queries, the query builder, or the Eloquent ORM.
To see how read / write connections should be configured, let's look at this example:
'mysql' => array(
'read' => array(
'host' => '192.168.1.1',
),
'write' => array(
'host' => '196.168.1.2'
),
'driver' => 'mysql',
'database' => 'database',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
),
Note that two keys have been added to the configuration array: read and write. Both of these keys have array values containing a single key: host. The rest of the database options for the read and write connections will be merged from the main mysql array. So, we only need to place items in the read and write arrays if we wish to override the values in the main array. So, in this case, 192.168.1.1 will be used as the "read" connection, while 192.168.1.2 will be used as the "write" connection. The database credentials, prefix, character set, and all other options in the main mysql array will be shared across both connections.
After some hours of experimenting and trying I have found out that the best option really is to create a PDO instance manually in the /app/config/database.php file and get the database credentials that way:
// Get instance row
if (!App::runningInConsole() && !array_key_exists('instance_found', $_ENV)) {
$conn = new PDO('mysql:dbname=instances;host=127.0.0.1', 'root', 'password');
$stmt = $conn->prepare('SELECT * FROM instances WHERE http_host=?');
$stmt->bindParam(1, $_SERVER['HTTP_HOST']);
$stmt->execute();
$instance = $stmt->fetch(PDO::FETCH_OBJ);
$conn = null;
if (!$instance) {
return Response::make('Whoops!', 404);
} else {
$_ENV['instance_found'] = true;
$database = $instance->mysql_database;
$username = $instance->mysql_username;
$password = $instance->mysql_password;
}
}

Categories