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

3 thoughts on “PHP and couchDB

    1. 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 🙂

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.