Hello, this is Jan Lehnardt and you're visiting my blog. Thanks for stopping by.
plok — It reads like a blog, but it sounds harder!
↑ Archives
As I mentioned in the Post Scriptum of an earlier post, JavaScript is not the only language that you can create CouchDB views with. You can now use PHP, too.
Here is how views work again: You specify a JavaScript function that receives a document parameter (which is a JSON object). You can do whatever to that object and return it again. Or you don’t return anything. When a new document is added to a CouchDB database, it gets passed to the JavaScript function and, depending on its return value, is included into the view that is associated with the function &endash; or not.
function(doc) { if("Value" == doc.field) { return doc; } }
This function adds the full document to the view when it has a field called field
and when that has the value Value. This is just a refresher on how views work in CouchDB.
Now on to PHP. CouchDB lets you hook up any language interpreter or compiler & executor via a simple line-based protocol that gets exchanged over standard in- and output. The core PHP code to wrap the PHP interpreter around that protocol and stdio is not even 70 lines of code and 130 with a some helper functions and comments. It needs PHP 5 and the JSON extension.
To use this, copy the scripts to your CouchDB installation $dir/bin/main.php and change the JsServer entry in your couch.ini
file to bin/main.php, restart CouchDB and you are ready to go. I’ll show a copy of that script at the end of the file.
Instead of sending in JavaScript functions for view definitions, you now send PHP functions.
function field_view($doc) { if("Value" == $doc->field) { return $doc; } }
This does the same as the JavaScript function above. You can also use all of PHP’s functions to work with the document object you get in.
And since this is so damn easy, people made this for other languages as well. Check the wiki if you want to do it yourself.
!/usr/bin/env php
jan@php.net for the public domain. PHP5+ */ errorreporting(EALL);
define("DEBUG", true); define("DEBUG_LOGFILE", "../logs/php.log");
_log("launched");
/* ["reset"] ["addmapfun","function foo($doc) { return true;}"] ["map_doc","{id:1}"]
["addmapfun","function(doc) { return doc;}"] */
$cmd = ''; $functions = array();
while($line = readline("")) {
//silence in case we don't get passed $arg @list($cmd, $arg) = json_decode($line); $jarg = $arg; $arg = json_encode($arg); _log($line); switch($cmd) { case "reset": // pretend to free resources unset($functions); $functions = array(); println("true"); break; case "add_map_fun": // $arg is a string that will compile to a function list($func, $body) = _parseFunc($arg); _log("function name: '$func'"); _log("function body: '$body'"); $functions[] = array($func, $body); if(eval($body) === false) { _log("eval failed: $func: '$body'"); println(json_encode('"error", "String must eval to a function (ex: \"function($doc) {return $doc;}\")."')); } else { println("true"); } break; case "map_doc": $results = array(); foreach($functions AS $function) { list($name, $body) = $function; try { _log("mapping against $name"); _log("doc: $arg"); _log(var_export($jarg, true)); $result = $name($jarg); _log("result: ".json_encode($result)); if($result === NULL) { $results[] = 0; } elseif($result === 0) { $results[] = "{value:0}"; } else { $results[] = $result; } } catch(Exception $e) { $results[] = 0; } } $results = json_encode($results); _log("jres: $results"); println($results); break; default: println("error"); exit(1); break; }
}
function println($msg) { echo "$msg\n"; flush(); // flush stdout needed for CouchDB }
function parseFunc($func) { $matches = array(); pregmatch('/function\s+([A-Za-z_][A-Za-z0-9]+)/', $func, $matches); $name = $matches[1];
$func = substr($func, 1, strlen($func)-2); return array($name, $func);
}
function _log($msg) { if(!DEBUG) { return; }
static $fp = false; $logfile = DEBUG_LOGFILE; if(!$fp) { $fp = fopen($logfile, "a") or die("Unable to open logfile '$logfile'."); } $time = time(); fwrite($fp, "($time) $msg\n");
}
function _flush() { flush(); } ?>
Good tutorial. Thx!
This is really cool - guess i fell in love with couchDB.
But the formatting of the code seems to be broken. Could you maybe fix it or provide the script as download?
Thanks!!