Oct 28, 2010

Creating MongoDB connection in Zend Framework

As of this writing, MongoDB is not yet supported by Zend Framework's latest release, 1.10.8. For learning purpose, i try to use MongoDB with ZF.

To initial a MongoDB connection in Zend_Application, a custom resource plugin is needed. After studying Matthew Weier O'Phinney's post and existing resource plugins, i create a basic one as follow. In this case, i only focus on single host connection. init() reads the parameters and returns a MongoCollection object.

<?php

// library/My/Application/Resource/Mongo.php

class My_Application_Resource_Mongo extends
      Zend_Application_Resource_ResourceAbstract {

    protected $_params = array();

    public function setParams(array $params) {
        $this->_params = $params;
        return $this;
    }   

    public function init() {
        $dns = 'mongodb://';  
        if (isset($this->_params['dbname'])) {
            if (isset($this->_params['username']) &&  
                isset($this->_params['password'])) {
                $dns .= $this->_params['username'] . 
                        ':' . $this->_params['password'] . '@';
            }   
            if (isset($this->_params['hostname'])) {
                $dns .= $this->_params['hostname'];
            }   

            if (isset($this->_params['port'])) {
                $dns .= ':' . $this->_params['port'];
            }   
        } else {
            throw new Exception(__CLASS__ . ' is missing parameters.');
        }   
        try {
            $connection = new Mongo($dns);
            return $connection->selectDB($this->_params['dbname']);
        } catch (MongoConnectionException $e) {
            throw new Exception($e->getMessage());
        }   
    }   
}

In configuration file, define autoloadernamespaces and pluginPaths so that bootstrap class can find the custom resource plugin.
; application/configs/application.ini
[production]
;...
autoloadernamespaces[] = "My_"
pluginPaths.My_Application_Resource = "My/Application/Resource"
resources.mongo.params.hostname = "localhost"
resources.mongo.params.dbname = "test"
;...

i feel comfortable to directly work with MongoCursor object, its methods insert(), find(), update(),... are exactly what i want, so i simply call them in the Mapper without introducing an Application_Model_User class to handle User object, as in quick start example.

<?php

// application/models/UserMapper.php

class Application_Model_UserMapper {

    private $_db;
    private $_name = 'user';
    private $_collection;

    public function __construct() {
        $frontController = Zend_Controller_Front::getInstance();
        $this->_db = $frontController->getParam('bootstrap')
                                     ->getResource('mongo');
        $this->_collection = $this->_db->selectCollection($this->_name);
    }

    public function insert($doc, $options = array()) {
        return $this->_collection->insert($doc, $options);
    }

    public function find($query = array(), $fields = array()) {
        return $this->_collection->find($query, $fields);
    }

    public function findOne($query = array(), $fields = array()) {
        return $this->_collection->findOne($query, $fields);
    }

    public function update($criteria, $newObj, $options = array()) {
        return $this->_collection->update($criteria, $newObj, $options);
    }
//...
}

In controller, i can simply instantiate UserMapper object, and treat it as MongoCursor.

<?php

// application/controllers/IndexController.php

class IndexController extends Zend_Controller_Action {

    public function indexAction() {
        $userMapper = new Application_Model_UserMapper();
        $cursor = $userMapper->find();
        //...
    }
}

2 comments:

  1. It's great your work , I'll start with mongodb and I dont know idea of how start. thanks!.

    ReplyDelete