diff --git a/.gitignore b/.gitignore index 6ca0234..670ea96 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ doc cover +phpunit.xml.dist diff --git a/Couchbase.php b/Couchbase.php index 8131e82..8e6db47 100644 --- a/Couchbase.php +++ b/Couchbase.php @@ -1,5 +1,5 @@ query_server = array("host" => $host, "port" => $couchport); $this->couchdb = new Couchbase_CouchDB("http://$host:$couchport/{$this->default_bucket_name}"); $this->couchbase = new Couchbase_Internal("http://$internal_host:$internal_port/"); - $this->_readDesignDocs(); return parent::addServer($host, $port); } /** * Helper method to allow defining a new view programatically. * - * @param Couchbase_ViewDefinition $view_definition View definition. + * @param Couchbase_View $view_definition View definition. * @return bool */ - function addView($view_definition) + public function addView(Couchbase_View $view_definition) { + $this->_readDesignDocs(); + $this->queries[$view_definition->ddoc_name] [$view_definition->name] = $view_definition; $this->_updateDesignDocument($view_definition->ddoc_name); @@ -106,19 +96,15 @@ function addView($view_definition) return true; } - // wait for ddocs to be all synced to all buckets and whatnot - // the server should do the wait for me or send me a notification - function _waitForDesignDocUglyHack($ddoc_name) + /** + * @todo: Remove this hack? + * + * wait for ddocs to be all synced to all buckets and whatnot + * the server should do the wait for me or send me a notification + */ + private function _waitForDesignDocUglyHack($ddoc_name) { - // var_dump("--waitForDdoc"); sleep(4); - // do { - // usleep(300); - // $result = $this->couchdb->view("default", $ddoc_name); - // var_dump($result); - // $json_result = json_decode($result); - // } while(isset($json_result->error) && ($json_result->error == "not_found")); - // var_dump("--done waitForDdoc"); } /** @@ -129,14 +115,16 @@ function _waitForDesignDocUglyHack($ddoc_name) * @param $view_name Name of the view inside the design doc * @return Couchbase_View instance ready for querying */ - function getView($ddoc_name, $view_name) + public function getView($ddoc_name, $view_name) { + $this->_readDesignDocs(); + if(!isset($this->queries[$ddoc_name][$view_name])) { return false; } $view = $this->queries[$ddoc_name][$view_name]; - $view->db = $this; + $view->setDatabase($this); return $view; } @@ -145,11 +133,9 @@ function getView($ddoc_name, $view_name) * * @return Couchbase_AllDocsView */ - function getAllDocsView() + public function getAllDocsView() { - $allDocsView = new Couchbase_AllDocsView; - $allDocsView->db = $this; - return $allDocsView; + return new Couchbase_AllDocsView($this); } /** @@ -160,7 +146,7 @@ function getAllDocsView() * @param integer $expriy Number of seconds until the item expires. * @return boolean Success or not. */ - function touch($key, $expriy = 0) + public function touch($key, $expriy = 0) { if(!method_exists("Memcached", "touch")) { trigger_error(E_WARNING, @@ -182,8 +168,12 @@ function touch($key, $expriy = 0) * all the time. * @return void */ - function _readDesignDocs() + private function _readDesignDocs() { + if ($this->queries !== null) { + return; + } + if(!$this->couchbase->bucketExists($this->default_bucket_name)) { return; } @@ -196,6 +186,7 @@ function _readDesignDocs() return; } + $this->queries = array(); foreach($ddocs->rows AS $ddoc_row) { $ddoc = $ddoc_row->doc; $ddoc_name = str_replace("_design/", "", $ddoc->_id); @@ -214,7 +205,7 @@ function _readDesignDocs() * @param string $ddoc_name design doc to update. * @return void */ - function _updateDesignDocument($ddoc_name) + private function _updateDesignDocument($ddoc_name) { $ddoc_definition = $this->queries[$ddoc_name]; $ddoc = new stdClass; @@ -246,4 +237,26 @@ function _updateDesignDocument($ddoc_name) $ddoc_json = json_encode($ddoc); $this->couchdb->saveDoc($ddoc_json); } + + /** + * Register Autoloader for Couchbase PHP SDK + * + * @return void + */ + static public function registerAutoload() + { + spl_autoload_register(array("Couchbase", "autoload")); + } + + /** + * Autoloader function + * + * @param string $class + */ + static public function autoload($class) + { + if (strpos($class, "Couchbase") === 0) { + require_once dirname(__FILE__) . "/" . str_replace("_", "/", $class) . ".php"; + } + } } diff --git a/Couchbase/AllDocsView.php b/Couchbase/AllDocsView.php new file mode 100644 index 0000000..f54529d --- /dev/null +++ b/Couchbase/AllDocsView.php @@ -0,0 +1,34 @@ +db->couchdb->allDocs($options) + ); + } +} \ No newline at end of file diff --git a/Couchbase/CouchDB.php b/Couchbase/CouchDB.php index 2175c0a..33dc461 100644 --- a/Couchbase/CouchDB.php +++ b/Couchbase/CouchDB.php @@ -6,13 +6,12 @@ */ class Couchbase_CouchDB { - /** * CouchDB server url, parsed into an object. * * @var URL CouchDB Server URL */ - var $server = null; + protected $server = null; /** * Constructor, takes a URL spcifying the CouchDB server and database. @@ -20,7 +19,7 @@ class Couchbase_CouchDB * @param string $dsn URL to a CouchDB server and database * @example http://localhost:5984/database */ - function __construct($dsn) + public function __construct($dsn) { $this->server = new stdClass; $this->dsn = $dsn; @@ -35,7 +34,7 @@ function __construct($dsn) * @param string $name database name, must match [a-z][a-z0-9$()/_-]. * @return string JSON success or error message. */ - function createDb($name) + public function createDb($name) { return $this->send("PUT", $this->server->path); } @@ -46,7 +45,7 @@ function createDb($name) * @param string $name database name. * @return string JSON success or error message. */ - function deleteDb($name) + public function deleteDb($name) { return $this->send("DELETE", $this->server->path); } @@ -57,7 +56,7 @@ function deleteDb($name) * @param string $doc JSON representation of a document. * @return string JSON success or error message. */ - function saveDoc($doc) + public function saveDoc($doc) { return $this->send("POST", $this->server->path, $doc); } @@ -69,7 +68,7 @@ function saveDoc($doc) * @param string $id The documents's id. * @return string document or error message as a JSON string. */ - function open($id) + public function open($id) { return $this->send("GET", $this->server->path . "/$id"); } @@ -82,7 +81,7 @@ function open($id) * @param string $options Associative array of CouchDB view query options. * @return string JSON result set of a CouchDB view Query. */ - function view($group, $name, $options = array()) + public function view($group, $name, $options = array()) { $qs = $this->_options_to_query_string($options); return $this->send("GET", @@ -94,7 +93,7 @@ function view($group, $name, $options = array()) * * @param string $options Associative array of CouchDB view query options. */ - function allDocs($options) + public function allDocs($options) { $qs = $this->_options_to_query_string($options); return $this->send("GET", $this->server->path . "/_all_docs?$qs"); @@ -107,7 +106,7 @@ function allDocs($options) * @param string $options Associative array of CouchDBview query options. * @return string URL query string to be appended to a view query. */ - function _options_to_query_string($options) + private function _options_to_query_string($options) { // TODO: keys POST $qs = array(); @@ -156,7 +155,7 @@ function _options_to_query_string($options) * application/json. * @return string JSON response. */ - function send($method, $url, $post_data = NULL, $content_type = "application/json") + protected function send($method, $url, $post_data = NULL, $content_type = "application/json") { $s = fsockopen( $this->server->host, @@ -187,7 +186,10 @@ function send($method, $url, $post_data = NULL, $content_type = "application/jso // var_dump($request); // var_dump("-------------"); fwrite($s, $request); - $response = ""; + $response = ""; + + while ( ( ( $line = fgets( $s ) ) !== false ) && + ( ( $lineContent = rtrim( $line ) ) === '' ) ); while(!feof($s)) { $response .= fgets($s); @@ -205,6 +207,7 @@ function send($method, $url, $post_data = NULL, $content_type = "application/jso } // var_dump($response); // var_dump("--------------------------------"); + return $this->body; } } diff --git a/Couchbase/Internal.php b/Couchbase/Internal.php index 1e7d97d..6969f54 100644 --- a/Couchbase/Internal.php +++ b/Couchbase/Internal.php @@ -13,7 +13,7 @@ class Couchbase_Internal extends Couchbase_CouchDB * @param string $name database/bucket name. * @param Couchbase $cb Couchbase client library object. */ - function deleteDb($name, $cb = null) + public function deleteDb($name, $cb = null) { $result = $this->send("DELETE", "/pools/default/buckets/$name"); if(empty($result)) { // some error deleting, don't wait. @@ -28,7 +28,7 @@ function deleteDb($name, $cb = null) * @param string $name database/bucket name. * @param Couchbase $cb Couchbase client library object. */ - function createDb($name, $cb = null) + public function createDb($name, $cb = null) { $result = $this->send( "POST", "/pools/default/buckets", @@ -47,7 +47,7 @@ function createDb($name, $cb = null) * @param string $name database/bucket name. * @return boolean Whether the database/bucket exists. */ - function bucketExists($name) + public function bucketExists($name) { $bucket_info = $this->send("GET", "/pools/default/buckets/$name"); return $bucket_info != '["Unexpected server error, request logged."]' @@ -61,7 +61,7 @@ function bucketExists($name) * @param Couchbase $cb Couchbase client library object. * @param constant Expected memcached result code. */ - function _waitForBucket($cb, $resultCode = Memcached::RES_SUCCESS) + private function _waitForBucket($cb, $resultCode = Memcached::RES_SUCCESS) { // var_dump("--waitForBucket"); do { diff --git a/Couchbase/View.php b/Couchbase/View.php index a50b8cb..a3815c8 100644 --- a/Couchbase/View.php +++ b/Couchbase/View.php @@ -10,37 +10,12 @@ TODO: Add query options and different languages. */ -class Couchbase_AllDocsView extends Couchbase_View -{ - /** - * Constructor, fake ddoc and view names - */ - function __construct() - { - parent::__construct("_builtin", "_all_docs"); - } - - /** - * Return a Couchbase query result. - * - * Overrides the parent's method to query `_all_docs` instead of a custom - * view. - * - * @param array $options Optional associative array of view options. - * @return Couchbase_ViewResult - */ - function getResult($options = array()) - { - return new Couchbase_ViewResult( - $this->db->couchdb->allDocs($options) - ); - } -} - /** * Access Couchbase views. * * @package Couchbase + * @property-read string $ddoc_name + * @property-read string $name */ class Couchbase_View { @@ -50,7 +25,7 @@ class Couchbase_View * @todo redundant? * @var string Design document id. */ - var $_id; + protected $_id; /** * Design Document revision for the view. @@ -58,35 +33,35 @@ class Couchbase_View * @todo redundant? * @var string Design document revision. */ - var $_rev; + protected $_rev; /** * Database object instance. * * @var Couchbase instance to access the server. */ - var $db; + protected $db; /** * Couchbase view definition object, designed to be turned into JSON. * * @var Couchbase_ViewDefinition that holds the JavaScript function code. */ - var $view_definition; + protected $view_definition; /** * Design doc name sans "_design/" prefix. * * @var string */ - var $ddoc_name; + protected $ddoc_name; /** * View name * * @var string View name. */ - var $view_name; + protected $name; /** * Constructor, instantiates a new view with a design doc name and a view @@ -95,11 +70,21 @@ class Couchbase_View * @param string $ddoc_name Design doc name. * @param string $view_name View name. */ - function __construct($ddoc_name, $view_name) + public function __construct($ddoc_name, $view_name, Couchbase $db = null) { $this->ddoc_name = $ddoc_name; $this->name = $view_name; $this->view_definition = new Couchbase_ViewDefinition; + $this->db = $db; + } + + /** + * @param Couchbase $db + * @return void + */ + public function setDatabase(Couchbase $db) + { + $this->db = $db; } /** @@ -209,5 +194,10 @@ function setReduceFunction($code) { $this->view_definition->setReduceFunction($code); } + + public function __get($name) + { + return $this->$name; + } } diff --git a/Couchbase/ViewDefinition.php b/Couchbase/ViewDefinition.php index 38b9816..5a02285 100644 --- a/Couchbase/ViewDefinition.php +++ b/Couchbase/ViewDefinition.php @@ -1,11 +1,18 @@ map = $code; } @@ -46,8 +53,13 @@ function setMapFunction($code) * @param string $code reduce function code * @return void */ - function setReduceFunction($code) + public function setReduceFunction($code) { $this->reduce = $code; } + + public function __get($name) + { + return $this->$name; + } } diff --git a/Couchbase/ViewResult.php b/Couchbase/ViewResult.php index 2e0e168..4a724c6 100644 --- a/Couchbase/ViewResult.php +++ b/Couchbase/ViewResult.php @@ -1,4 +1,5 @@ total_rows)) { + if (isset($result->total_rows)) { $this->total_rows = $result->total_rows; } - if(isset($result->offset)) { + if (isset($result->offset)) { $this->offset = $result->offset; } - if(isset($result->rows)) { + if (isset($result->rows)) { $this->rows = $result->rows; } - if(isset($result->errors)) { + if (isset($result->errors)) { $this->errors = $result->errors; } } + + public function __get($name) + { + return $this->$name; + } + } diff --git a/Couchbase/ViewResultPaginator.php b/Couchbase/ViewResultPaginator.php index 1a61c79..719632b 100644 --- a/Couchbase/ViewResultPaginator.php +++ b/Couchbase/ViewResultPaginator.php @@ -1,26 +1,27 @@ view = $view; } @@ -61,7 +62,8 @@ function __construct($view) * @param integer $rowsPerPage * @return void */ - function setRowsPerPage($rowsPerPage) { + public function setRowsPerPage($rowsPerPage) + { $this->rowsPerPage = $rowsPerPage; } @@ -71,7 +73,8 @@ function setRowsPerPage($rowsPerPage) { * @param array $pageKey Page key. * @return void */ - function setPageKey($pageKey) { + public function setPageKey($pageKey) + { $this->page_key = $pageKey; } @@ -81,7 +84,8 @@ function setPageKey($pageKey) { * @param array $options View query options. * @return void */ - function setOptions($options) { + public function setOptions($options) + { $this->options = $options; } @@ -90,7 +94,7 @@ function setOptions($options) { * * @return void */ - function rewind() + public function rewind() { $this->page_key = null; $this->current(); @@ -101,20 +105,16 @@ function rewind() * * @return Couchbase_ViewResult Result page. */ - function current() + public function current() { - $options = array_merge($this->options, - array("limit" => $this->rowsPerPage + 1)); + $options = array_merge($this->options, array("limit" => $this->rowsPerPage + 1)); $result = $this->view->getResultByRange( - $this->page_key, - null, - $options + $this->page_key, null, $options ); // TODO: descending, flip start/end - // if there is an extra row at the end, grab it's key and docid and // store them as the next_page_key - if(isset($result->rows[$this->rowsPerPage]) && $result->rows[$this->rowsPerPage]->key) { + if (isset($result->rows[$this->rowsPerPage]) && $result->rows[$this->rowsPerPage]->key) { $row = $result->rows[$this->rowsPerPage]; $this->next_page_key = array($row->key, $row->id); } else { @@ -130,7 +130,7 @@ function current() * * @return array Page key. */ - function key() + public function key() { return $this->page_key; } @@ -140,7 +140,7 @@ function key() * * @return void */ - function next() + public function next() { $this->page_key = $this->next_page_key; $this->next_page_key = null; @@ -152,8 +152,9 @@ function next() * * @return void */ - function valid() + public function valid() { return $this->page_key !== false; } + } diff --git a/README.md b/README.md index 6e0256e..92adc06 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ Open Source after all. addCouchbaseServer("localhost"); // connects to Couchbase ports 11211 // and 8091 by default. @@ -345,7 +347,6 @@ can be used: - integrate proper(!) HTTP client - detect new couch-api endpoints dynamically - local-cache server design docs - - make E_ALL | E_STRICT | E_DEPRECATED compatible - add proper credits ## Credits diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..617b446 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,35 @@ + + + + + + test + + + + + + + + + + + + + + Couchbase.php + Couchbase + + + + diff --git a/test/CouchbaseClusterTest.php b/test/CouchbaseClusterTest.php index c612977..2135814 100644 --- a/test/CouchbaseClusterTest.php +++ b/test/CouchbaseClusterTest.php @@ -1,19 +1,18 @@ cb = new Couchbase; - $this->cb->addCouchbaseServer("localhost", 12001, 9500); + $this->cb->addCouchbaseServer($GLOBALS['COUCHBASE_SERVER'], $GLOBALS['COUCHBASE_MEMCACHE_PORT'], $GLOBALS['COUCHBASE_COUCHDB_PORT'], $GLOBALS['COUCHBASE_INTERNAL_HOST'], $GLOBALS['COUCHBASE_INTERNAL_PORT']); $this->cb->flush(); // $this->cb->couchbase->deleteDb("default", $this->cb); $this->cb->couchbase->createDb("default", $this->cb); @@ -29,7 +28,7 @@ function tearDown() function kill_node($node) { $cmd = "kill `ps ax | grep beam | grep n_$node | awk '{print $1}'`"; - `$cmd`; + shell_exec($cmd); } function test_basic_query() @@ -54,9 +53,9 @@ function test_a_b() $this->cb->set("a", '{"a":1}'); $this->cb->set("b", '{"a":2}'); - $view = new Couchbase_View; + $view = new Couchbase_View("default", "cluster"); $view->setMapFunction("function(doc) { emit(doc.a, 1); }"); - $this->cb->addView("default", "cluster", $view); + $this->cb->addView($view); sleep(10); @@ -73,9 +72,9 @@ function test_a_b_with_dead_node() $this->cb->set("a", '{"a":1}'); $this->cb->set("b", '{"a":2}'); - $view = new Couchbase_View; + $view = new Couchbase_View("default", "cluster"); $view->setMapFunction("function(doc) { emit(doc.a, 1); }"); - $this->cb->addView("default", "cluster", $view); + $this->cb->addView($view); sleep(10); $this->kill_node(1); diff --git a/test/CouchbaseTest.php b/test/CouchbaseTest.php index 85bef76..0c6e4b7 100644 --- a/test/CouchbaseTest.php +++ b/test/CouchbaseTest.php @@ -13,7 +13,7 @@ class CouchbaseTest extends PHPUnit_Framework_TestCase function setUp($flush = true) { $this->cb = new Couchbase; - $this->cb->addCouchbaseServer("localhost", 12001, 9500, "localhost", 9000); + $this->cb->addCouchbaseServer($GLOBALS['COUCHBASE_SERVER'], $GLOBALS['COUCHBASE_MEMCACHE_PORT'], $GLOBALS['COUCHBASE_COUCHDB_PORT'], $GLOBALS['COUCHBASE_INTERNAL_HOST'], $GLOBALS['COUCHBASE_INTERNAL_PORT']); if($flush) { $this->cb->flush(); // $this->cb->couchbase->deleteDb("default", $this->cb); diff --git a/test/bootstrap.php b/test/bootstrap.php new file mode 100644 index 0000000..32f35ec --- /dev/null +++ b/test/bootstrap.php @@ -0,0 +1,4 @@ +