We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

changing the parameters of a database service already created

Hi all,

I'm trying to change the database connection based on a variable for several of my models. This variable will be based on user input (initially) and stored in the session after they are logged in.

I know that I need to set the connection service in the initialize function of the model - that works fine. The problem is I will have many databases (large datasets for multiple clients) and defining them all in the services container beforehand seems inefficient. I can create a new db service within the model using getDI() and set-> and that works - but it seems like the wrong way to do it to me.

Can anyone provide syntax on how to change the database name (will be variable) in a db service already initialized - rather than creating a new service within the model every time? I tried messing around with setParameter but couldn't get it.

So that ideally I can set a db service in the initial service container - and then just change the dbname parameter based on a variable whenever I initialize certain models?

Thanks!

-Matt



2.6k

A model gets it connection from the model manager. The modelManager can only set different connections on seperate models. This is not the case in you problem, you want a different connection based on the state of the model.

The can be achieved by extending the Phalcon/Mvc/Model/Manager and overloading both getReadConnection(model) and getWriteConnection(model). The return the correct connection based on model state. You then register the new ModelManager with the DI.

Beware though, don't change the expected behaviour for the ModelManager. My solution would be to have two seperate model base types the existing Phalcon\Mvc\Model and a MyStateModel (which extends Phalcon\Mvc\Model).

The get*Connection()

public function getReadConnection(ModelInterface $model) {
    if($model instanceof MyStateModel) {
        return; // the connection based on $model->variable
    }

    // A normal model, return the expected behaviour
    return parent::getReadConnection($model);
}

If the connection database is stored in session, would it be possible to have your bootstrap function access $_SESSION? Something like:

$DI->setShared('db',function() use($Config){
    $database = (isset($_SESSION['use_database'])) ? $_SESSION['use_database'] : $Config->database->database;

    return new \Phalcon\DB\Adapter\Pdo\Mysql([  'host'      => $Config->database->host,
                                                'dbname'        => $database,
                                                'username'  => $Config->database->username,
                                                'password'  => $Config->database->password,
                                                'charset'       => 'utf8'
                                            ]);
}); 

The database connection isn't persistent through the life of the session, so this should work starting with the first page load after the database is set in the session.

Also, it might be useful to note that DI::get() and DI::getShared() accept an array of parameters as their second argument.

Hi guys - thanks for your replies!

quasipickle - that's pretty much what I was going for. I just couldn't seem to get the session while defining the service with phalcon calls. Also one problem was that the User model needs to access a different connection based on a form field during the login process before the actual auth session is set. Unfortunately DI::get() gets the service but to set the connection for a model SetConnection just accepts the string of a service (no parameters) and you can't set it to a service you have gotten with DI::get().

I ended up using your suggestion and putting setting the dbID into a session before auth happens in order to check the User list of that particular db. Then destroying the session if authentication fails. This is currently working!!!

Before I accept the answer - can anyone see any problems with this (using php SESSION in the service definition?) I am new to phalcon and not that familiar with it's DI and service handling yet and my app is in it's infancy - I don't want to create any security or session / service handling conflicts that will plague this thing later on.

Should I be calling the phalcon session instead of the php var SESSION and if so how? I couldn't get at it in the services loader (my modules index.php). Or should I be going more the route of trying to extend the Model Manager (which will still need to set up a connection service based on variables - probably session variables as they will not actually be in most models).

Thanks in advance for any input on the situation!