0

Using CodeIgniter 3, I autoload my database config, now how do I change the database connected dynamically ? I was thinking like using session to pass the database value, but session cannot be used in the database config file.

I know I can manually load database and change it, but then I have to call and load the database in every controller and I have tons of the controller, therefore I would like to avoid setting the database manually.

11
  • Can you clarify I was thinking like using session to pass the database value? What is your use case? Where do the necessary data for your condition come from? Commented Jan 5, 2018 at 14:54
  • Do you ever use more than one database at a time? Commented Jan 5, 2018 at 14:54
  • @DFriend yes my application need to keep changing database Commented Jan 5, 2018 at 14:56
  • @PhilippMaurer I meant I was thinking of setting session value with the db name that I want to connect, then somehow pass the value to the config database file and autoload the database with the currently changed db throughout my app Commented Jan 5, 2018 at 14:58
  • So, some controllers require two database connections? Commented Jan 5, 2018 at 14:58

1 Answer 1

1

There is probably more than one way to do what you want. The solution shown here uses CodeIgniter’s "Hooks" feature. Specifically, it uses the "post_controller_constructor" hook to match the name of a controller with a specific database configuration defined in database.php.

After the hook does its work the application can make calls to the database in the typical CI way using $this->db->. For example...

$query = $this->db->get('mytable');

This solution is based on the assumption that only one database connection is need for any given controller. This means that all methods in that controller (or any models loaded by the controller) use the same connection.

Here's how it is done.

In application/config/config.php

$config['enable_hooks'] = TRUE;

In application/config/hooks.php

$hook['post_controller_constructor'][] = array(
  'class' => '',
  'function' => 'set_db_connection',
  'filename' => 'post_controller_hook.php',
  'filepath' => 'hooks'
);

The file post_controller_hook.php is where the work gets done. It uses lists of controller names to determine which database config is to be loaded.

The list ($controller_lists) contains sub-arrays which group controller names by the db configuration needed. A search is done through each sub-array to find the matching controller name. When a controller name is found the key of that sub-array is the db config to be loaded. If no match is found the 'default' config is used.

The $controller_lists array is hard-coded here but it could easily be loaded from a config file instead. A config file might make maintaining the lists easier.

file application/config/post_controller_hook.php

function set_db_connection()
{
    $CI = get_instance();
    $controller = $CI->router->class;
    $loadConfig = 'default';  //if nothing found in lists we're still good

    $controller_lists = array(
        'config2' => ['profile'],
        'config3' => ['discusion', 'home'],
        'config4' => ['suppliers', 'customers', 'inventory', 'orders']
    );

    foreach($controller_lists as $config_name => $list)
    {
        if(in_array($controller, $list))
        {
            $loadConfig = $config_name;
            break;
        }
    }

    $CI->load->database($loadConfig);
}

The ability to not load a database for controllers that don't need one could be added if that was desirable. But I'm not going there.

As stated earlier, this solution uses the assumption that only one database configuration (connection) is used for any given controller. If certain methods of a controller need to use a different db configuration this solution becomes more complicated.

Adding the method to the search is easy. The first few lines of set_db_connection() would look like this.

function set_db_connection()
{
    $CI          = get_instance();
    $controller  = $CI->router->class;
    $method      = $CI->router->method;

    if($method !== 'index')
    {
        $controller .= '/'.$method; //append method name
    }
    $loadConfig = 'default';  //if nothing found in lists we're still good

So now $controller will hold either 'controller/method', or just 'controller' if index() is to being called.

Consider a controller called Viewstate with three methods

class Viewstate extends CI_Controller
{
    public function index(){
        //uses db 'config4' 
    }
    public function report(){
        //uses db 'Config2'
    }
    public function process(){
        //uses db 'Config3' 
    }
}

We have to include each 'viewstate/method' in the sub-arrays like this.

    $controller_lists = array(
        'config2' => ['profile', 'viewstate/report'],
        'config3' => ['disscusion', 'home', 'viewstate/process'],
        'config4' => ['viewstate', 'customers', 'inventory', 'orders']
    );

    //the rest of the function is as shown earlier

Any 'viewstate/method' not in the search lists it will be assigned the 'default' db config. So it's easy to sort the various needs of viewstate.

The problem is that every 'controller/method' in the site must now be included in the search lists. If the Profile controller has ten methods every combination must now be in the config2 sub-array. So if there are lots of controllers and controller/methods this solution is a poor choice. There might be an elegant way around this problem but that's probably a topic for a new question.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the solutions, still looking into it, how do I use it in my controllers and change manipulate to change the db config ?
@Charas, I have edited my answer to address your question.
Very great solution, learned a lot about hooks while experimenting with your answer, it does work but yes i have more than ten methods in about almost 50 controllers, I tried to remove the if statement to compare the controller/method name and tried to set the $loadConfig using session but it doesn't work. In the end I load the db manually in every controller's constructor and set it using session. Thanks for all the helps :)
I feel I must say it one more time: If all your controllers only use one connection specific to that controller, then searching for controller name only will work. It only gets complicated when controllers need to chose between more than one connection.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.