0

This is for Kohana v3.2

How can I dynamically choose the database an ORM model connects to? Specifically, I am trying to change an ORM model to work with databases in my local dev, staging and production environments.

The Kohana Guide tells me I can set the database connection by setting a protected property on the ORM model like this:

class Model_Customer extends ORM
{
    protected $_db_group = 'local_db';
    protected $_table_name = 'customer';

This works fine when developing locally, but what about when I move to stage and then production? I'd rather not have to change the _db_group each time I change environments. I can check server vars to determine environment, but I haven't been able to figure out a way to dynamically set the db_group property to match the environment since I can't do any logic in a class definition.

There's probably a better way to approach this problem that I'm hoping someone will be able to suggest. Thanks.

eysikal
  • 579
  • 1
  • 6
  • 13

3 Answers3

1

In my opinion, check the connection in your database.php config file.

return array
(
    'default' => array
    (
        'type'       => 'MySQL',
        'connection' => array(
            /**
             * The following options are available for MySQL:
             *
             * string   hostname     server hostname, or socket
             * string   database     database name
             * string   username     database username
             * string   password     database password
             * boolean  persistent   use persistent connections?
             * array    variables    system variables as "key => value" pairs
             *
             * Ports and sockets may be appended to the hostname.
             */
            'hostname'   => 'localhost',
            'database'   => (Kohana::$environment == Kohana::DEVELOPMENT) ? 'local_db' : 'kohana',
            'username'   => FALSE,
            'password'   => FALSE,
            'persistent' => FALSE,
        ),
        'table_prefix' => '',
        'charset'      => 'utf8',
        'caching'      => FALSE,
    ),
); 
kero
  • 10,647
  • 5
  • 41
  • 51
mobal
  • 342
  • 2
  • 10
  • I highly doubt that a configuration file is the correct place for logic. However, it should be easy to create an `ORM` child that in it's constructor chooses the correct db connection (and future models extend that child). – kero Jul 21 '14 at 13:46
  • It is the easiest way. There is no framework solution to separate develop and production environment in Kohana (imo). – mobal Jul 21 '14 at 13:51
  • I meant setting `$_db_group` based on the logic you present here. But you showed how it can be done, so I'm removing the -1 – kero Jul 21 '14 at 13:57
  • @kingkero, can you elaborate a little on your idea? I will look at mobal's solution too. – eysikal Jul 21 '14 at 14:33
0

As I said in the comment to mobal's answer, I'd take a slightly different approach while using the same logic.

You can see in the documentation that it is possible to have multiple db configs. In this case it could look like this

return array(
    'default' => array( /* regular connection */ ),
    Kohana::DEVELOPMENT => array( /* connection for development */ )
);

Now the question is: Where should the logic be put that decides which connection is used? First I thought the ORM class would be a good place - but actually I doubt that. A model shouldn't concern, which connection is used.

However, Database::instance() looks right. This is the method that determins which configuration will be used. And so changing it here will effect everything that uses a database - so the perfect place.

Since Kohana uses wrapper classes, you can create a file APPPATH/classes/Database.php and add your changes there like this

class Database extends Kohana_Database {

    public static function instance($name = NULL, $config = NULL) {
        if ($name === NULL && Kohana::$environment == Kohana::DEVELOPMENT) {
            $name = Kohana::DEVELOPMENT;
        }
        return parent::instance($name, $config);
    }

}

Now whenever you try to get the default instance (which is the case in ORM if no _db_group is set) and are in the development environment, the development config will be used for connecting to your database.

Community
  • 1
  • 1
kero
  • 10,647
  • 5
  • 41
  • 51
-1

Thanks all for the ideas.

My use case involves working with a database config file which references 6 different databases (2 databases times 3 environments for each of those).

For my specific case, this was the simplest solution I could come with without worry of possibly fouling up DB connections in other areas of the app

Pseudo code:

public function __construct()
{
    if ($_SERVER['HTTP_HOST'] == 'staging.acme.com')
    {
        $this->_db_group = 'db1_stage';
    }
    else if ($_SERVER['KOHANA_ENV'] == 'development')
    {
        $this->_db_group = 'db1_local';
    }
    else
    {
        $this->_db_group = 'db1_production';
    }

    parent::__construct();
}

This sets the $_db_group property before calling parent::construct() which initializes the database connection for the ORM using the DB I need.

eysikal
  • 579
  • 1
  • 6
  • 13
  • May I ask why you decided to use this and not the solution I provided? – kero Jul 21 '14 at 21:23
  • Yes, mainly because I wasn't confident enough to implement that change and not worry that I would break something elsewhere in the app. – eysikal Jul 22 '14 at 21:44
  • this solution move config outside config... Better make this `in config/database.php` (if($_SERVER['HTTP_HOST'] == 'staging.acme.com') return Array(...)). Or not add `in config/database.php` to project. Add `in config/database.default.php`, and on any env set right values. – bato3 Oct 03 '17 at 14:30