A Simple CouchDB Datasource

  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 40.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 41.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 42.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 43.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 44.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 45.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 46.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 47.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 48.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 49.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 50.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 51.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 56.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 57.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 58.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 59.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 60.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 61.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 62.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 63.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 64.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 65.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 66.
  • warning: date() [function.date]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'America/Denver' for 'MDT/-6.0/DST' instead in /home/lyniqne/public_html/planetcakephp.org/drupal/sites/all/modules/token/token_node.inc on line 67.

Yes, my waffling continues. But this time it is NOT with respect to what editor to use, as the one true editor has been configured in such a way to make my life easier. I have a personal project that I have been waffling about building in Python (first as a Django app, now maybe as a web2py app) or in CakePHP, since I would probably be most productive building out something quickly using it.

Since I'm in a CakePHP phase right now, I decided to start building out some of the components I would need to make the side project work. One of those components is the use of CouchDB as the database. Since non-relational databases are all the hawtness right now (and Jan Lehnardt is such an awesome guy) I decided the best way to learn it's use is to store search results by users to my site (no hints on what I'm doing). I figured the best way to do this was to create a CouchDB datasource, add it to my application, and then create models that would use the datasource.

While I suggest that you visit the CouchDB website for more info on what it is and how to use it, here's a quick summary: CouchDB is a non-relational datastore that you communicate with using views written in Javascript, and it returns any records that match your view as JSON-formatted data. Very simple when you think of it, but also very powerful.

I must emphasize that the code is very raw and not fully tested. Written using PHP 5.2.9 and Cake 1.2.bleeding.edge. First, the data source:
PLAIN TEXT
PHP:

  1. <?php
  2.  
  3. /**
  4. * Datasource for connecting to CouchDB
  5. *
  6. * @author Chris Hartjes
  7. */
  8. class CouchDbSource extends DataSource {
  9.     public $description = 'CouchDB Data Source';
  10.     public $host = 'localhost';
  11.     public $port = 5984;
  12.     public $error_number = null;
  13.     public $error_message = null;
  14.     public $headers = null;
  15.     public $body = null;
  16.  
  17.     public function __construct($config) {
  18.         parent::__construct($config);   
  19.  
  20.         if (!empty($this->config['host'])) {
  21.             $this->host = $this->config['host'];   
  22.         }
  23.  
  24.         if (!empty($this->config['port'])) {
  25.             $this->post = $this->config['port'];
  26.         }
  27.     }
  28.  
  29.     public function fullTableName() {
  30.         return false;
  31.     }
  32.    
  33.     /**
  34.      * Method that sends data to the CouchDB server
  35.      *
  36.      * @param $method string GET, POST, PUT or DELETE
  37.      * @param $url string URL you are trying to send to
  38.      * @param $post_data string optional data to be posted
  39.      * @return string
  40.      */
  41.     public function send($method, $url, $post_data = NULL) {
  42.         $s = fsockopen($this->host, $this->port, $this->error_number, $this->error_message);
  43.  
  44.         if (!$s) {
  45.             return false;
  46.         }
  47.  
  48.         $request = "{$method} {$url} HTTP/1.0\r\nHost: {$this->host}\r\n";
  49.  
  50.         if ($post_data) {
  51.             $request .= "Content-Length: " . strlen($post_data) . "\r\n\r\n";   
  52.             $request .= "{$post_data}\r\n";
  53.         } else {
  54.             $request .= "\r\n"; 
  55.         }
  56.  
  57.         fwrite($s, $request);
  58.  
  59.         $response = "";
  60.  
  61.         while (!feof($s)) {
  62.             $response .= fgets($s); 
  63.         }
  64.  
  65.         list($this->headers, $this->body) = explode("\r\n\r\n", $response);
  66.  
  67.         return $this->body;
  68.     }
  69. }
  70. ?>

I warned you that it was very simple.

So, if you want to use the datasource, the first thing to do is add an entry to your APP/config/database.php file with all the pertinent configuration info:
PLAIN TEXT
PHP:

  1. <?php
  2. class DATABASE_CONFIG {
  3.  
  4.     var $couchdb = array(
  5.         'datasource' => 'couchdb',
  6.         'host' => 'localhost',
  7.         'port' => 5984
  8.     );
  9. }
  10. ?>

CouchDB by default runs on port 5984, but like most flexible applications it lets you change that port if you need to. That's really all the configuration info you'll need.

So next up is configuring a model to use it.
PLAIN TEXT
PHP:

  1. <?php
  2.  
  3. class Search extends AppModel {
  4.     public $name = 'Search';
  5.     public $useDbConfig = 'couchdb';   
  6.     public $useTable = null;
  7.  
  8.     public function send($method, $url, $post_data = NULL) {
  9.         return $this->getDataSource()->send($method, $url, $post_data); 
  10.     }
  11. }
  12.  
  13. ?>

Thanks to Joel Perras for helping me dig through the CakePHP internals in order to figure out the best way to get my model to speak to the datasource. And pointing out my stupid mistake that caused CakePHP's automodel magic to bite me in the ass.

So how do you actually use this thing. Here's an example of asking CouchDB to give you a listing of all documents available on the server:
PLAIN TEXT
PHP:

  1. APP/controllers/searches_controller.php
  2. <?php
  3.  
  4. class SearchesController extends AppController {
  5.     public function show_all() {
  6.         $this->layout = 'ajax';
  7.         $response = $this->Search->send('GET', '/searches/_all_docs');
  8.         $this->set(compact('response'));
  9.     }
  10. }
  11.  
  12. ?>
  13.  
  14. APP/views/searches/show_all.ctp
  15.  
  16. <?= $response ?>

In my case, the view spit out a nice string that looked like this:
PLAIN TEXT
JAVASCRIPT:

  1. {"total_rows":1,"offset":0,"rows":[ {"id":"e2ffaae4df81b66c3d8386b75be71aa3","key":"e2ffaae4df81b66c3d8386b75be71aa3","value":{"rev":"1-71594714"}} ]}

So there you have it. If you want to do more work with this datasource, I suggest you take a look at this link on the CouchDB wiki about using PHP with CakePHP. It could use some work to add in convenience methods for adding, deleting and finding specific records but it's a good start I think.