PHP and couchDB


Last days I’ve been playing with couchDB and PHP. There are several ways to use couchDB with PHP. There also are extensions but I want to build a simple library and I will show now the code.

CouchDB has a great RestFul API so I we want to use CouchDB we only need to perform http requests. I have done a small class to do the requests. You can see the code here. It’s a simple class that uses PHP’s curl functions.

I come from relational database world. NoSQL is new for me. Maybe I’m wrong but I want to use INSERT, UPDATE, DELETE and SELECT statements in CouchDB in the same way I use them in Relational database.

The class is focused in the HTTP Document API. There is a great tutorial here that explains the API. Now I’ll show the interface I’ve made to perform the statements with CouchDB.

The examples assumes there are CouchDB host at localhost:5987. Also as I’ve said before the class focused only in HTTP Document API so first of all I create a new database called users using CouchDB’s web interface (http://localhost:5984/_utils/). Now let’s start:

INSERT

$couchDb = new Nov_CouchDb('localhost', 5984);
$couchDb->db('users')->insert('gonzalo', array('password' => "g1"));

SELECT

$data = $couchDb->db('users')->select('gonzalo')->asArray();
print_r($data);

UPDATE

$couchDb->db('users')->update('gonzalo', array('password' => 'g2'));

DELETE

$out = $couchDb->db('users')->delete('gonzalo')->asArray();
print_r($out);

Basically Nov_CouchDb has a constructor that stores connection information into private member variables:

class Nov_CouchDb
{
    private $_protocol;
    private $_host;
    private $_port;
    private $_user;
    private $_password;

    public function __construct($host, $port=Nov_Http::DEF_PORT , $protocol=Nov_Http::HTTP, $user = null, $password=null)
    {
        $this->_host     = $host;
        $this->_port     = $port;
        $this->_protocol = $protocol;
        $this->_user     = $user;
        $this->_password = $password;
    }
}

There are also a public function called db. This function stores the database and returns the instance of the class (I like chainable functions)

...
    private $_db;
    /**
     * @param string $db
     * @return Nov_CouchDb
     */
    public function db($db)
    {
        $this->_db = $db;
        return $this;
    }
...

And finally the main functions:

SELECT

public function select($key)
{
    try {
        $out = Nov_Http::connect($this->_host, $this->_port, $this->_protocol)
            ->setCredentials($this->_user, $this->_password)
            ->doGet("{$this->_db}/{$key}");
    } catch (Nov_Http_Exception $e) {
        $this->_manageExceptions($e);
    }
    return new Nov_CouchDb_Resulset($out);
}

INSERT

    /**
     * @param string $key
     * @param array $values
     * @return Nov_CouchDb_Resulset
     */
    public function insert($key, $values)
    {
        try {
            $out = Nov_Http::connect($this->_host, $this->_port, $this->_protocol)
                ->setCredentials($this->_user, $this->_password)
                ->setHeaders(array('Content-Type' =>  'application/json'))
                ->doPut("{$this->_db}/{$key}", json_encode($values));
        } catch (Nov_Http_Exception $e) {
            $this->_manageExceptions($e);
        }
        return new Nov_CouchDb_Resulset($out);
    }

UPDATE

    /**
     * @param string $key
     * @param array $values
     * @return Nov_CouchDb_Resulset
     */
    public function update($key, $values)
    {
        try {
            $http = Nov_Http::connect($this->_host, $this->_port, $this->_protocol)
                ->setCredentials($this->_user, $this->_password);
            $out = $http->doGet("{$this->_db}/{$key}");
            $reg = json_decode($out);
            $out = $http->setHeaders(array('Content-Type' =>  'application/json'))
                ->doPut("{$this->_db}/{$key}", json_encode($reg));
        } catch (Nov_Http_Exception $e) {
            $this->_manageExceptions($e);
        }
        return new Nov_CouchDb_Resulset($out);
    }

DELETE

    /**
     * @param string $key
     * @return Nov_CouchDb_Resulset
     */
    public function delete($key)
    {
        try {
            $http = Nov_Http::connect($this->_host, $this->_port, $this->_protocol)
                ->setCredentials($this->_user, $this->_password);
            $out = $http->doGet("{$this->_db}/{$key}");
            $reg = json_decode($out);
            $out = $http->doDelete("{$this->_db}/{$key}", array('rev' => $reg->_rev));
        } catch (Nov_Http_Exception $e) {
            $this->_manageExceptions($e);
        }
        return new Nov_CouchDb_Resulset($out);
    }

insert, update, delete and select returns an instance of Nov_CouchDb_Resulset. CouchDb API returns a json string. But sometimes I want a PHP array or maybe an object. I use Nov_CouchDb_Resulset to perform those transformations:

// Different outputs
$data = $couchDb->db('users')->select('dummy')->asArray();
print_r($data);

$data = $couchDb->db('users')->select('dummy')->asObject();
print_r($data);

$data = $couchDb->db('users')->select('dummy')->asJson();
print_r($data);

EXCEPTIONS

CouuchDB API is a RestFul API so it uses HTTP exceptions when something wrong happens. I’ve done three exceptions. One generic and other two with the most common exception in relational databases: NoDataFound and DupValOnIndex. this is because I want do things like the following ones:

try {
    $couchDb->db('users')->update('gonzalo', array('password' => 'g2'));
} catch (Nov_CouchDb_Exception_NoDataFound $e) {
    echo "No data found \n";
}

$couchDb->db('users')->insert('gonzalo1', array('password' => "g1"));
try {
    $couchDb->db('users')->insert('gonzalo1', array('password' => "g1"));
} catch (Nov_CouchDb_Exception_DupValOnIndex $e) {
    echo "Dup Val On Index \n";
}
try {
    $couchDb->db('users')->delete('gonzalo');
} catch (Nov_CouchDb_Exception_NoDataFound $e) {
    echo "No data found \n";
}

The source code is available on google code here

About these ads

About Gonzalo Ayuso

Web Architect specialized in Open Source technologies. PHP, Python, JQuery, Dojo, PostgreSQL, CouchDB and node.js but always learning.

Posted on March 15, 2010, in CouchDB, php, Technology. Bookmark the permalink. 3 Comments.

  1. Have a look at Lithium. It already abstracts most of CouchDB and there are several sample applications to get you up and running quickly. The one thing you didn’t discuss here was concept of “views” in CouchDB which is integral to performing complex queries.

    http://rad-dev.org/lithium/wiki/about

    • Yes. I haven’t work with views yet. I haven’t needed views yet. They are in my todo list.
      I will take a look to lithium. More things into my todo list :)

  2. Haha. No kidding. Will we ever catch up? Probably not, oh well it’s still fun to try.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 953 other followers

%d bloggers like this: