eaj
eaj

Reputation: 2606

CakePHP - select database config based on route or url?

I'm working on a small CakePHP application that is subject to the following constraint (awkward but out of my control): I need it to work on either of two identical databases, with the choice being based on URL. For example:

http://www.example.com/myapp/foo/action/param
http://www.example.com/myapp/bar/action/param

The first obvious solution is to have two identical CakePHP applications at myapp/foo and myapp/bar with different database configurations. This has a kludgy feel to it, though, so I'm trying to find an elegant way of creating a single application.

The approach I'm considering is this: Define routes such that myapp/foo and myapp/bar will be associated with the same controller. Then give my DATABASE_CONFIG class a constructor:

function __construct() {
  $pathParts = explode('/', $_SERVER['REQUEST_URI']);
  if (array_search('foo', $pathParts)) {
    $this->default = $this->fooConfig;
  } else if (array_search('bar', $pathParts)) {
    $this->default = $this->barConfig;
  }
}

(Where of course I've defined fooConfig and barConfig for the two databases.) I do have control over the URL, so I can be confident that there won't be extraneous occurrences of foo or bar in the URL.

My question is this: Is there a simpler, more elegant way of handling this odd situation? Maybe something in AppModel and/or AppController? Although I'm getting rid of duplicated code, I can't shake the feeling that I'm replacing one code smell with another.

Upvotes: 1

Views: 1013

Answers (2)

David Kullmann
David Kullmann

Reputation: 918

There are a few ways to do this, here is one.

Write a sweet custom route in which you always match:

Router::connect('/:ds/*', array(), array('routeClass' => 'SweetDbRoute'));

Then have SweetDbRoutes set a class variable you can use everywhere, including in your model constructors. Then it should fail so you don't actually adjust the request.

App::import('SweetDbClass', array('file' => '/path/to/your/sweet_db_class.php'));
class SweetDbRoute extends CakeRoute {
    // put your failing route code here, but use your SweetDbClass to track datasource ...
    // see http://book.cakephp.org/view/1634/Custom-Route-classes
}

Then in your AppModel:

App::import('SweetDbClass', array('file' => '/path/to/your/sweet_db_class.php'));
    class AppModel extends Model {
    public function __construct($id = false, $table = null, $ds = null) {
        $ds = SweetDbClass::$ds;
        parent::__construct($id, $table, $ds);
    }
}

Upvotes: 1

Anh Pham
Anh Pham

Reputation: 5481

So for example, after you perform an insert in one database, the two won't be "identical", right? Are these 2 DB somehow synced with each other? I don't know what do you need to do on those DB, but it's probably easier just to do 2 separate apps.

Yes, you can specify the DB configuration in the model: http://book.cakephp.org/view/922/Database-Configuration but you can't change it on-the-fly though (the models are not expected to change association to another table, I suppose). What you do is probably the only way.

I do have control over the URL, so I can be confident that there won't be extraneous occurrences of foo or bar in the URL

Yes, there can be "extraneous occurrences of foo or bar in the URL" :)) But it won't break your app.

Upvotes: 0

Related Questions