Doctrine – Binding a specific connection to a Model in Zend Framework

I have been looking into this for awhile now and had not figured out how I could bind a connection to a model without having to extend it in some way.

Finally… and of course it was simple and right there in front of me, but without an actual example I didn’t know!

So here it is, hope you can benefit from it:

// application > configs > application.ini 
autoloaderNamespaces[] = "Doctrine"
doctrine.db1  = "mysql://username:password@localhost/database1"
doctrine.db2  = "mysql://username:password@localhost/database2"
doctrine.db3  = "mysql://username:password@localhost/database3"

// application > Bootstrap.php
protected function _initDoctrine()
    {
        $this->getApplication()->getAutoloader()
                               ->pushAutoloader(array('Doctrine', 'autoload'));

        $manager = Doctrine_Manager::getInstance();
        $manager->setAttribute(Doctrine::ATTR_AUTO_ACCESSOR_OVERRIDE, true);
        $manager->setAttribute(
            Doctrine::ATTR_MODEL_LOADING,
            Doctrine::ATTR_QUOTE_IDENTIFIER,
            Doctrine::MODEL_LOADING_CONSERVATIVE
        );
        $manager->setAttribute(Doctrine::ATTR_AUTOLOAD_TABLE_CLASSES, true);
        $manager->addRecordListener(new App_Doctrine_Listener_RecordLog);

        $connections = $this->getOption('doctrine');

        // This will loop through our connections in the application.ini

        foreach($connections as $name => $dsn) {
	        $conn = Doctrine_Manager::connection($dsn, $name);
	        $conn->setAttribute(Doctrine::ATTR_USE_NATIVE_ENUM, true);
	        $conn->setCharset('utf8');
        }
        
        return $conn;
    }

My Zend Installation is modular – so we are going to look at adding modules to the default module…

// application > modules > models > DbTable > User.php
class Model_DbTable_User extends Model_DbTable_Generated_BaseUser
{
	
	public function setPassword($password)
    {
        return $this->_set('password',strtolower(md5(trim($password).'s3CR3][')));
    }
    
}
// application > modules > models > DbTable > UserTable.php
class Model_DbTable_UserTable extends Doctrine_Table
{
}

The key part here is the component binding at the top… that will link your model to a specific connection!

// application > modules > models > DbTable > Generated > BaseUser.php 
// Connection Component Binding
Doctrine_Manager::getInstance()->bindComponent('Model_DbTable_User', 'db1');

abstract class Model_DbTable_Generated_BaseUser extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->setTableName('user');
        $this->hasColumn('user_id', 'integer', 4, array(
             'type' => 'integer',
             'length' => 4,
             'unsigned' => 1,
             'primary' => true,
             'autoincrement' => true,
             ));
        $this->hasColumn('password', 'string', 75, array(
             'type' => 'string',
             'length' => 75,
             'fixed' => false,
             'primary' => false,
             'default' => '',
             'notnull' => true,
             'autoincrement' => false,
             ));
    }

    public function setUp()
    {
        $this->hasMany('Model_DbTable_Album as Album', array(
             'local' => 'user_id',
             'foreign' => 'user_id'));
    }
}

That’s all there is to it! I can’t believe that I didn’t figure that out sooner… you live and you learn. Feel free to ask questions, I actually respond. :)

Friday, September 4th, 2009 Doctrine

7 Comments to Doctrine – Binding a specific connection to a Model in Zend Framework

  • christian says:

    you should really install a plugin to display your code! :) good reading though! thanks

  • Matt says:

    Sorry, I saw your question in the Doctrine user group but didn’t realize that you were using the ZF. You may want to take a look at the resource plugin proposal (though it doesn’t support component binding at the moment):

    http://framework.zend.com/wiki/display/ZFPROP/Zend_Application_Resource_Doctrine+-+Matthew+Lurz

    As well as the (working) prototype (under Parables/Application/Resource):

    http://github.com/mlurz71/parables

    Also, there’s no need to return the connection in _initDoctrine as this will store that specific connection in the local registry for that resource.

    Lastly, FYI…I’ve only recently started playing with modular apps using this resource plugin but I haven’t found a way to autoload generated base models. Are you really generating the base model classes here?

    • admin says:

      Yeah I am auto-loading the generated base models as well. I renamed them following the Pear standard and Zend Autoloader loads them – as I show inside the example I gave above.

      File that is generated:

      BaseUser extends Doctrine_Record

      I name it –

      Model_DbTable_Generated_BaseUser extends Doctrine_Record

      So you are saying, in the _initDoctrine I don’t need to run my connections through? Or I just don’t need to return the connection at the end? If you could past the code change so I know what you mean, I will give it a try and change the example. Thanks!

  • Matt says:

    @admin

    Sorry, I had intended on checking back sooner to see if there were any replies.

    With regard to returning the connection, whatever you return here is stored in a local registry. In this case, the last connection that initialized and so $resource in the following returns that connection:

    $bootstrap = $this->getInvokeArg(‘bootstrap’);
    $resource = $bootstrap->getResource(‘doctrine’);

    Unfortunately, that’s very helpful as you can just as easily get the connection with a call to getConnection() on a Doctrine_Manager instance.

    In my resource plugin, I’m returning an array with 2 sub-arrays, one with path info (for executing Doctrine_Cli commands or Doctrine_Tasks) and the other with just connection names and so when I execute the above I get back that array.

    Hopefully that makes some sense.

  • Jonathan says:

    Thanks very much for this. I have a need to change the connection a model is associated with at runtime. Hopefully this will be the solution, or at least the basis of one. Thanks again. P.s. sorry to whine but loosing your comment content when the captcha is rejected, is really anoying.

  • admin says:

    Yeah that deff. is annoying – do you know of a wordpress captcha that does not do that?

  • Leave a Reply

    You must be logged in to post a comment.

    [ad code=1 align=center]