Dynamic datasources and global in Cakephp 3? - php

I have an application that will be used by many databases. To choose the database with the application data I have a database with the connections parameters (host, username, pass, database...)
The problem is that this dynamically created datasource does not work for the rest of the application.
Controller Code
$data = $this->request->data;
$connection = ConnectionManager::get("default");
$query = "SELECT * FROM clients WHERE client_id = ".$data['codigo'];
$result = $connection->execute($query)->fetchAll('assoc');
ConnectionManager::drop('default');
$config = ConnectionManager::config('connection', [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => $result[0]['host'],
'username' => $result[0]['username'],
'password' => $result[0]['password'],
'database' => $result[0]['database'],
'encoding' => 'utf8',
'timezone' => 'UTC',
'flags' => [],
'cacheMetadata' => true,
'log' => false,
'quoteIdentifiers' => false,
'url' => env('DATABASE_URL', null),
]);
$connection = ConnectionManager::get('connection');
ConnectionManager::alias('connection', 'default');
return $this->redirect(['controller' => 'Mains', 'action' => 'index']);
After this redirect, apparently the other controllers do not have this datasource.

It's certainly a bit unusual to be swapping databases based on contents inside request data - but generally database connection just needs to be done earlier on in Cake's initial setup, as each Controller's connection resource is already set to the default.
If you're only swapping the one time, you could manage this inside config/bootstrap.php (where Cake normally sets up it's ConnectionManager) instead.
You won't have access to $this->request, but could just grab it from $_REQUEST instead, for example:
In config/bootstrap.php, change these lines:
Cache::config(Configure::consume('Cache'));
ConnectionManager::config(Configure::consume('Datasources'));
Email::configTransport(Configure::consume('EmailTransport'));
To this:
Cache::config(Configure::consume('Cache'));
ConnectionManager::config(Configure::consume('Datasources'));
$connection = ConnectionManager::get("default");
$client = TableRegistry::get('Clients')->find()
->where(['client_id'=> $_REQUEST['client_id']])->firstOrFail();
ConnectionManager::drop('default');
$config = ConnectionManager::config('connection', [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => $client->host,
'username' => $client->username,
'password' => $client->password,
'database' => $client->database,
'encoding' => 'utf8',
'timezone' => 'UTC',
'flags' => [],
'cacheMetadata' => true,
'log' => false,
'quoteIdentifiers' => false,
'url' => env('DATABASE_URL', null),
]);
ConnectionManager::get('connection');
Email::configTransport(Configure::consume('EmailTransport'));
Edited: Switched from your raw SQL to a Table::find()

Related

CakePHP on AWS Bitnami LAMP server can't connect to database

I am just getting into PHP and I'm trying to get a server started and go through CakePHP's CMS tutorial. However I cannot get a database connection. I get the error: CakePHP is NOT able to connect to the database.
Connection to database could not be established: SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client
I have been trying to edit my app/config/app.php file. This is what I have:
'Datasources' => [
'default' => [
'className' => Connection::class,
'driver' => Mysql::class,
'persistent' => false,
'host' => 'localhost',
'port' => '3306',
'username' => 'root',
'password' => 'THE DEFAULT PASSWORD I USED TO GET INTO phpMyAdmin',
'database' => 'cake_cms',
'unix_socket' => '/opt/bitnami/mysql/tmp/mysql.sock',
//'encoding' => 'utf8mb4',
'timezone' => 'UTC',
'flags' => [],
'cacheMetadata' => true,
'log' => false,
'quoteIdentifiers' => false,
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
'url' => env('DATABASE_URL', null),
],
'test' => [
'className' => Connection::class,
'driver' => Mysql::class,
'persistent' => false,
'host' => 'localhost',
'port' => '3306',
'username' => 'root',
'password' => 'THE DEFAULT PASSWORD I USED TO GET INTO phpMyAdmin',
'database' => 'cake_cms',
'unix_socket' => '/opt/bitnami/mysql/tmp/mysql.sock',
//'encoding' => 'utf8mb4',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
'log' => false,
//'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'],
'url' => env('DATABASE_TEST_URL', null),
],
],
Thanks in advance. I'm super new, so maybe I need to provide more information.

How does DataSource test in cakephp 2

We have custom DataSource and want to test that verifies the data after find method execute equals to one not customized.As I thought it, it would be possible if we can change Datasource in test code.I try many case, but I couldn't make it work.
public $default = [
'datasource' => 'CustomPostgres',
'persistent' => false,
'host' => 'localhost',
'port' => '5432',
'login' => 'hoge',
'password' => 'hogehoge',
'database' => 'prod',
'schema' => 'public',
'prefix' => '',
'encoding' => 'utf8'
];
public $test = [
'datasource' => 'CustomPostgres',
'persistent' => false,
'host' => 'localhost',
'port' => '5432',
'login' => 'hoge',
'password' => 'hogehoge',
'database' => 'test_prod',
'schema' => 'public',
'prefix' => '',
'encoding' => 'utf8'
];
public $old = [
'datasource' => 'Database/Postgres',
'persistent' => false,
'host' => 'localhost',
'port' => '5432',
'login' => 'hoge',
'password' => 'hogehoge',
'database' => 'dev',
'schema' => 'public',
'prefix' => '',
'encoding' => 'utf8'
];
public $test_old = [
'datasource' => 'Database/Postgres',
'persistent' => false,
'host' => 'localhost',
'port' => '5432',
'login' => 'hoge',
'password' => 'hogehoge',
'database' => 'test_dev',
'schema' => 'public',
'prefix' => '',
'encoding' => 'utf8'
];
//try1
$this->Model->setDataSource('test_old');
//try2
ConnectionManage::create('test_old',///);
//try3
////in fixture File and ClassRegistry:Init("Model")
$useDbConfig = "old";
////inner start::up
ClassRegistry:Init("Model");
//try4 extends model
ModelForOldSetting extends Model{
$useDbConfig = "old";
}
Above codes didn't work and it always emit error says
MissingConnectionException: Database connection "Postgres" is missing, or could not be created ,when running test however it works fine when setting default datasource Database/Postgres running local browser without test.
So, I'm really confused why Database connection "Postgres" is missing.Any idea makes me appreciate to them.
I finally found irritating and stupid irritating code by outer database.php file overrides datasources' setting.Following code works fine after appropriate settings.
ModelForOldSetting extends Model{
$useDbConfig = "dev";
$useTables = "models";
}
ClassRegistry:Init("ModelForOldSetting");
$model = $this->getMockForModel('ModelForOldSetting');

Avoid hard coded databases credentials in combination with shell - Cakephp 3

I have written a Cakephp 3 shell application which uses models and behaviors to generate thumbnails. Since I populated the database credentials through the $_SERVER super global I need to manually insert the credentials. However, when I try the following snippet of code this results in an error saying that I can't overwrite the connection:
public main($host, $username, $password, $db){
ConnectionManager::config('default', [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => $host,
'username' => $username,
'password' => $secret,
'database' => $db,
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
]);
........
}
Moreover, it first tries to load my default settings in config/app.php which aren't populated and throws notices and errors:
if (isset($_SERVER['RDS_HOSTNAME']) && isset($_SERVER['RDS_USERNAME']) && isset($_SERVER['RDS_PASSWORD']) && isset($_SERVER['RDS_DB_NAME']) ) {
define('RDS_HOSTNAME', $_SERVER['RDS_HOSTNAME']);
define('RDS_USERNAME', $_SERVER['RDS_USERNAME']);
define('RDS_PASSWORD', $_SERVER['RDS_PASSWORD']);
define('RDS_DB_NAME', $_SERVER['RDS_DB_NAME']);
}
return [
.......
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => RDS_HOSTNAME,
/**
* 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' => RDS_USERNAME,
'password' => RDS_PASSWORD,
'database' => RDS_DB_NAME,
'encoding' => 'utf8',
'timezone' => 'UTC',
Is there any way to avoid hard coding of the database credentials in this way?

Kohana 3.3 Database::instance('name') not working

I have an issue with Kohana 3.3 and using different database configurations.
I have a config/database.php with 'default' config and 'other' like this:
return array
(
'default' => array
(
'type' => 'MySQL',
'connection' => array(
'hostname' => 'localhost',
'database' => 'database-one',
'username' => 'root',
'password' => 'password',
'persistent' => FALSE,
),
'table_prefix' => '',
'charset' => 'utf8',
'caching' => FALSE,
),
'other' => array
(
'type' => 'MySQL',
'connection' => array(
'hostname' => 'localhost',
'database' => 'database-two',
'username' => 'root',
'password' => 'password',
'persistent' => FALSE,
),
'table_prefix' => '',
'charset' => 'utf8',
'caching' => FALSE,
));
But in a Controller or Model when trying to use:
Database::instance('other');
Kohana will still use the 'default' configuration. What am I doing wrong?
Thanks!
If you would like to change currently used connection by kohana try this:
Database::$default = 'other';
From this line your code will use 'other' connection till you will switch it again to 'default' using same way.
You can also use another DB configuration once when executing the query in simple way:
DB::...->execute('other');
Or if you store your DB instance earlier:
$other = Database::instance('other');
DB::...->execute($other);
By ... I mean your query.
You need to store the connection in a variable, or the default connection will be used.
Documentation

FuelPHP can't setup database to work

I'm using FuelPHP and I can't set up my database so it would work. I know that i'm using right information but i'm not sure if I put it in right place.
<?php
return array(
'default' => array(
'connection' => array(
'dsn' => 'mysql:host=modernt#moderntalking.lt;dbname=modernt',
'username' => 'modernt',
'password' => 'pass',
),
),
);
This is my db.php in APP/config/db.php
Environment configurations are merged, and the environment wins.
So if you have ./app/config/db.php containing return array('a'); and you'll have ./app/config/development/db.php containing return array('b');, then after reading your config, you'll end up with "b".
So if you use environment based config (like DB does by default), only add configuration to the global file that is truely global, otherwise it gets overwritten in the merge.
Check this
'dsn' => 'mysql:host=moderntalking.lt;dbname=modernt',
// a MySQL driver configuration
'development' => array(
'type' => 'mysqli',
'connection' => array(
'hostname' => 'localhost',
'port' => '3306',
'database' => 'fuel_db',
'username' => 'your_username',
'password' => 'y0uR_p#ssW0rd',
'persistent' => false,
'compress' => false,
),
'identifier' => '`',
'table_prefix' => '',
'charset' => 'utf8',
'enable_cache' => true,
'profiling' => false,
'readonly' => false,
),
// a PDO driver configuration, using PostgreSQL
'production' => array(
'type' => 'pdo',
'connection' => array(
'dsn' => 'pgsql:host=localhost;dbname=fuel_db',
'username' => 'your_username',
'password' => 'y0uR_p#ssW0rd',
'persistent' => false,
'compress' => false,
),
'identifier' => '"',
'table_prefix' => '',
'charset' => 'utf8',
'enable_cache' => true,
'profiling' => false,
'readonly' => array('slave1', 'slave2', 'slave3'),
),
'slave1' => array(
// configuration of the first production readonly slave db
),
'slave2' => array(
// configuration of the second production readonly slave db
),
'slave3' => array(
// configuration of the third production readonly slave db
),
Basic procedure of setup FuelPHP..may be its help you .Thank you
First, check your environment configuration in app/bootstrap.php:
/**
* Your environment. Can be set to any of the following:
*
* Fuel::DEVELOPMENT
* Fuel::TEST
* Fuel::STAGING
* Fuel::PRODUCTION
*/
Fuel::$env = (isset($_SERVER['FUEL_ENV']) ? $_SERVER['FUEL_ENV'] : Fuel::DEVELOPMENT);
Then modify the db.php file accordingly (app/development/db.php, app/production/db.php, app/staging/db.php, app/test/db.php)

Categories