I have tried a few things to make this work, i have had success with a solution but it's not ideal as i can't replace the 'default' database connection.
I did notice the 'active' setting in the frameworks database config file, i tried using it to set 'global' as the default first, rather then default and i end up getting this error:
Database type not defined in "global" configuration or "global" configuration does not exist.
I am switching to the database early on in my code before any database calls are made, are session's enabled by default? The databases(s) i'm testing with are not setup to facilitate database-session data as they don't have the tables so i'm not sure if it's that. I'm also not loading any modules other then custom one's i've built for the purpose of testing things, and none of those do anything database related so i don't think it's those doing database stuff before i switch to the 'global database'. I am using the following code to do the switch to the 'global' database
\DBUtil::set_connection('global');
# Execute database query here
My Database config looks something like this:
return array(
'global' => array(
'connection' => array(
'dsn' => 'mysql:host=localhost;dbname=database_name_global',
'username' => 'username_here',
'password' => 'password_here',
'persistent' => false,
),
),
'default' => array(
'connection' => array(
'dsn' => 'mysql:host=localhost;dbname=database_name_global',
'username' => 'username_here',
'password' => 'password_here',
'persistent' => false,
),
),
);
I have both 'global' and 'default setup because if i remove default from the config, or leave it set to an empty array i get an error:
Fuel\Core\Database_Exception [ Error ]:
invalid data source name
It traces to the line of code where i try to execute a select statement, this is the line immediately after "\DBUtil::set_connection('global');" So i'm not sure if i'm doing this part right?
When i set the 'active' value in the database config this this i get the following error:
Database type not defined in "global" configuration or "global" configuration does not exist
This traces to the same line of code executing a select statement, right after "\DBUtil::set_connection('global');". This is how i'm setting 'active' in my database config
return array(
'global' => array(
'connection' => array(
'dsn' => 'mysql:host=localhost;dbname=database_name_global',
'username' => 'username_here',
'password' => 'password_here',
'persistent' => false,
),
),
'default' => array(
'connection' => array(
'dsn' => 'mysql:host=localhost;dbname=database_name_global',
'username' => 'username_here',
'password' => 'password_here',
'persistent' => false,
),
),
'active' => 'global',
);
I have also tried the above with the 'default' entry completely removed and get the same error about 'global' not existing in the config
So i have attempted to do it without the 'global' and 'default' connections, and instead just try to replace default during run-time and re-connect to the new database afterwards. The db.php config looks like this:
return array(
'default' => array(
'connection' => array(
'dsn' => 'mysql:host=localhost;dbname=database_name_global',
'username' => 'username_here',
'password' => 'password_here',
'persistent' => false,
),
)
);
The code i'm using looks something like this this:
$db_name = 'database_for_user_'.$site['site_slug'];
$db_pass = get_password_for_user($site); //this returns a string
$db_user = get_username_for_user($site); //this returns a string
$db_config = array(
'type'=>'pdo',
'identifier'=>'',
'table_prefix'=>'',
'charset'=>'utf8',
'collation'=>'',
'enable_cache'=>true,
'profiling'=>false,
'readonly'=>false,
'connection' => array(
'dsn' => 'mysql:host=localhost;dbname='.$db_name,
'username' => $db_user,
'password' => $db_pass,
'persistent' => false,
),
);
# Disconnect from the database, not sure if this line is right?
\Database_Connection::instance()->disconnect();
# Replace the 'default' database connection in the config
\Config::set('db.default',$db_config);
# Set the current database to active to reload settings, i think these two lines do the same thing?
\Config::set('db.active', 'default');
\DBUtil::set_connection(null);
# Execute query on 'user-specific' database
$test = \DB::select('*')->from('test')->as_assoc()->execute();
$test = $test->as_array();
print_r($test);
I then get the following error:
Fuel\Core\Database_Exception [ 1146 ]:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'database_name_global.test' doesn't exist with query: "SELECT * FROM `test`"
The error above traces to the line "$test = DB::select('*')->from('test')->as_assoc()->execute();"
I left the "'persistent' => false," line in the config files above in the hopes that it would help solve the error above, by needing to actually re-connect to the database server on the next query, rather then using the existing one, it makes no difference and i get the same error. If i change the above code to the following:
...
# Replace the 'default' database connection in the config
\Config::set('db.default_test',$db_config);
# Set the current database to active to reload settings, i think these two lines do the same thing?
\Config::set('db.active', 'default_test');
\DBUtil::set_connection('default_test');
...
Everything works fine, but it leaves the 'default' config in memory as a print_r of \Config::get('db'); show's, it also means i need to make sure i explicitly tell other modules to use the 'default_test' connection which seems more hastle then it needs to be when 'default' would be fine. The application does not need the 'global' connection to the database at any point after the switch-over too.
Doing a print_r of the database config shows the new connection settings have replaced the 'default' settings, but it seems as if the database module has a 'cached' version of these values that it holds, so when you change the config it's not reading the new settings and switching to the new database, because it's already been 'loaded' by the first database query.
I'm not sure if this is me doing something wrong or if it's a bug or something?
I did try the thing's you recommended and only had a partial success, using two different database connections 'default' and 'default_test' in my example worked but my goal was to replace the 'default' with the new database configuration, trying to do this using your examples did not work and still produced errors.
Replacing the 'default' configuration in the Config work's just fine, i can print_r the value of \Config::get('db.default'); before and after updating the 'default' database settings in the config and FuelPHP's config system registers the changes just fine
After looking through the Database_Connection and Database_PDO_Connection classes i've noticed that when constructed the class stores the config for it's database in the "protected $_config;" variable, this variable is set using
/**
* Stores the database configuration locally and name the instance.
*
* [!!] This method cannot be accessed directly, you must use [static::instance].
*
* @param string $name
* @param array $config
*/
protected function __construct($name, array $config)
{
// Set the instance name
$this->_instance = $name;
// Store the config locally
$this->_config = $config;
// Store the database instance
static::$instances[$name] = $this;
}
The problem is that when you issue a disconnect() and connect() on the default database instance, it will disconnect and reconnect fine, but because the config information is stored in the local $_config variable, the updated connection info for 'default' in the configs \Config::get('db.default') is not reloaded, instead the old values in $_config are used which is why it re-connects back to the old, now incorrect database rather then the new database settings i specified, it also explains why using 'default' and 'default_test' in my examples did work ok.
The connect() and disconnect() methods do not reload the database configuration from the fuelphp config system, they only destroy and re-create the PDO object, but use the 'cached' config that was declared at startup to re-connect, rather then using the one now specified in the FuelPHP config.
If $_config in the Database_Connection class could be re-loaded from the config after dis-connecting i think this would work just fine, $_config is not public though and from what i can see (please correct me if i missed it) there's no method i can use to reload the config so accessing and resetting it manually from outside the Database_Connection class instance is not possible?
I understand you can create multiple database connections like in your example but this was not what i was trying to do.
I have implemented a work-around that reloads the configuration for the database connection with one i can specify, this works a charm. However you mentioned that i should not do this, can i ask why and what problems it could cause? Even though my work-around seems to work fine, what areas am i likely to run into trouble with?
I put the following function inside the Database_PDO_Connection class in the core files and this allow's me to replace the 'cached' config for the database instance, then disconnect and reconnect to start talking to the new database. This works, and I can update the values in the config using \Config::set('db.default',$db_config); incase any modules from that point on in the code need to reference to the config and also removed it from memory too which is a bonus. The code i'm using to do this in the class is:
public function reload_config(array $config) {
$this->_config = $config;
$this->disconnect();
$this->connect();
return true;
}
And in my application i just use:
...
\Database_Connection::instance('default')->reload_config($db_config);
\Config::set('db.default',$db_config);
...
Not the cleanest solution but it does meet all of my fairly simple requirements, the only problem is i do not want to modify the core files, i have had a quick go at extending the core Database_PDO_Connection class with no luck, i do not want to replace it completely, just add the new reload_config() method.
I was reading the documentation on this and at the top of the page it says
Extending but not replacing the core class
These are the easiest and will work like any other class you create; just make them extend the core class in the global namespace:
class MyConfig extends Config {}
I have tried creating a class in app/classes/database/pdo/connection.php and extending it like:
class MyDatabase_PDO_Connection extends Database_PDO_Connection {
...
code here
...
}
But it does not work, the documentation says i need to use the auto-loader if i'm replacing classes entirely, do i also need to use the autoloader to just extend the core classes, without replacing them? The documentation isn't entirely clear on that and i'm not sure if i'm putting the connection.php file in the right folder within my 'classes' directory
Ah ok, i think i've figured it out, in my app/classes/database/pdo/connection.php file i have the following code:
class Database_PDO_Connection extends Fuel\Core\Database_PDO_Connection {
public function reload_config(array $config) {
$this->_config = $config;
$this->disconnect();
$this->connect();
return true;
}
}
And i have specified my replacement class using the autoloader in the bootstrap.php file
...
Autoloader::add_classes(array(
// Add classes you want to override here
'Database_PDO_Connection' => APPPATH.'classes/database/pdo/connection.php',
));
...
and removed my code from the core files, and everything works with no problems now, i'm guessing i can do a similar thing for the mysql and mysqli drivers too.
It looks like you're new here. If you want to get involved, click one of these buttons!