Commits

Jon Langevin committed c0bed11 Merge
  • Participants
  • Parent commits 355bbbd, c6b0cee

Comments (0)

Files changed (10)

      * @return int
      */
     public function getR($r = null) {
-        if ($r != null)
+        if ($r !== null)
             return $r;
-        if ($this->_r != null)
+        if ($this->_r !== null)
             return $this->_r;
         return $this->client->r;
     }
      * @param int $w Optional: The W-Value to be returned if not null
      * @return int
      */
-    public function getW($w) {
-        if ($w != null)
+    public function getW($w=null) {
+        if ($w !== null)
             return $w;
-        if ($this->_w != null)
+        if ($this->_w !== null)
             return $this->_w;
         return $this->client->w;
     }
      * @param int $dw Optional: The DW-Value to be returned if not null
      * @return int
      */
-    public function getDW($dw) {
-        if ($dw != null)
+    public function getDW($dw=null) {
+        if ($dw !== null)
             return $dw;
-        if ($this->_dw != null)
+        if ($this->_dw !== null)
             return $this->_dw;
         return $this->client->dw;
     }
      * @return Bucket
      */
     public function setProperties(array $props) {
-        /**
-         * Construct the Contents
-         */
-        $content = CJSON::encode(array('props' => $props));
-
-        /**
-         * Run the request
-         */
         Yii::trace('Setting Bucket properties for bucket "' . $this->name . '"', 'ext.riiak.Bucket');
-        $headers = array('Content-Type: application/json');
-        $response = $this->client->transport->putObject($this, $headers, $content);
-
-        /**
-         * Use a Object to interpret the response, we are just interested in the value
-         */
-        $obj = new Object($this->client, $this);
-        $this->client->transport->populate($obj, $this, $response, 'setBucketProperties');
-
-        if (!$obj->exists)
-            throw new Exception('Error setting bucket properties.');
+        $this->client->transport->setBucket($this, array('props'=>$props));
 
         $this->_properties = null;
 
      */
     public function getProperties($refresh = false) {
         if ($refresh || !is_array($this->_properties)) {
-            Yii::trace('Fetching Bucket properties for bucket "' . $this->name . '"', 'ext.riiak.Bucket');
-            $obj = $this->fetchBucketProperties(array('props' => 'true', 'keys' => 'false'));
-            if(empty($obj->data['props']))
+            Yii::trace('Fetching properties for bucket "' . $this->name . '"', 'ext.riiak.Bucket');
+            $props = $this->client->transport->listBucketProps($this);
+            if(empty($props))
                 return array();
-            $this->_properties = $obj->data['props'];
+            $this->_properties = $props;
         }
         return $this->_properties;
     }
     public function getKeys($refresh = false) {
         if ($refresh || !is_array($this->_keys)) {
             Yii::log('Bucket key listing is a very intensive operation, and should never occur in production!', \CLogger::LEVEL_WARNING);
-            Yii::trace('Fetching Bucket keys for bucket "' . $this->name . '"', 'ext.riiak.Bucket');
-            /**
-             * Non-null key param will prompt format of /buckets/BUCKET/keys/
-             */
-            $obj = $this->fetchBucketProperties(array('props' => 'false', 'keys' => 'stream'), '');
-            if (empty($obj->data['keys']))
-                return array();
-            $this->_keys = array_map('urldecode', array_unique($obj->data['keys']));
+            Yii::trace('Fetching keys for bucket "' . $this->name . '"', 'ext.riiak.Bucket');
+            $this->_keys = $this->client->transport->listBucketKeys($this);
         }
         return $this->_keys;
     }
 
     /**
-     * Fetches bucket properties
-     *
-     * @param array $params
-     * @param string $key
-     * @return \riiak\Object
-     */
-    protected function fetchBucketProperties(array $params = array(), $key = null) {
-        /**
-         * Run the request
-         */
-        $response = $this->client->transport->getObject($this, $params, $key);
-
-        /**
-         * Use a Object to interpret the response, we are just interested in the value
-         */
-        $obj = new Object($this->client, $this);
-        $this->client->transport->populate($obj, $this, $response, 'getBucketProperties');
-
-        if (!$obj->exists)
-            throw new Exception('Error getting bucket properties.');
-
-        return $obj;
-    }
-
-    /**
      * Search a secondary index
      * @author Eric Stevens <estevens@taglabsinc.com>
      * @param string $name - The name of the index to search
         $url = $this->client->transport->buildBucketIndexPath($this, $name . '_' . $type, $startOrExact, $end);
         $response = $this->client->transport->get($url);
 
-        $obj = Object::populateResponse(new Object($this->client, $this), $response);
+        $obj = Object::populateResponse(new Object($this->client, $this), $response, 'secondaryIndex');
         if (!$obj->exists)
             throw new Exception('Error searching index.');
 
         $key->client = $this->client;
     }
 
-}
+}

File MapReduce.php

      * Run the map/reduce operation. Returns array of results
      * or Link objects if last phase is link phase
      *
-     * @param integer $timeout Timeout in seconds. Default: null
+     * @param integer $timeout optional Timeout in milliseconds. Riak default is 60000 (60s).
      * @return array
      */
     public function run($timeout = null) {
          */
         Yii::trace('Running Map/Reduce query', 'ext.riiak.MapReduce');
 
-        $response = $this->client->transport->post($this->client->transport->buildMapReducePath(), array(), $content);
+        $transport = $this->client->transport;
+        $response = $transport->post($transport->buildMapReducePath(), array(), $content);
+
+        /**
+         * Verify that we got one of the expected statuses. Otherwise, throw an exception
+         */
+        try {
+            $transport->validateResponse($response, 'mapReduce');
+        }catch(\Exception $e) {
+            throw new \Exception($e . PHP_EOL . PHP_EOL . 'Job Request: '. $content . PHP_EOL . PHP_EOL
+                . 'Response: '. \CVarDumper::dumpAsString($response), $e->getCode(), $e);
+        }
+
         $result = CJSON::decode($response['body']);
 
         /**
  * @property array[string]string $autoIndexes
  * @property array[int]string $siblings
  *
- * @property-read int $status Status code of response
+ * @property-read int $httpCode Status code of response
+ * @property-read string $httpStatus Status msg response
  * @property-read bool $hasSiblings
  * @property-read int $siblingCount
  * @property-read array[int]Link $links
     }
 
     /**
-     * Returns HTTP status of last operation
+     * Returns HTTP status code of last operation
      *
      * @return int
      */
-    public function getStatus() {
+    public function getHttpCode() {
         return $this->headers['http_code'];
     }
 
     /**
+     * Returns HTTP status msg of last operation
+     *
+     * @return string
+     */
+    public function getHttpStatus() {
+        return $this->headers['http_status'];
+    }
+
+    /**
      * Returns the object's content type
      *
      * @return string
      * @return Object
      */
     public function store($w = null, $dw = null) {
-        /**
-         * Use defaults if not specified
-         */
-        $w = $this->bucket->getW($w);
-        $dw = $this->bucket->getDW($w);
-
-        /**
-         * Construct the URL
-         */
-        $params = array('returnbody' => 'true', 'w' => $w, 'dw' => $dw);
-        $url = $this->client->transport->buildBucketKeyPath($this->bucket, $this->key, null, $params);
-
-        /**
-         * Construct the headers
-         */
-        $headers = array('Accept: text/plain, */*; q=0.5',
-            'Content-Type: ' . $this->getContentType(),
-            'X-Riak-ClientId: ' . $this->client->clientId);
-
-        /**
-         * Add the vclock if it exists
-         */
-        if (!empty($this->vclock))
-            $headers[] = 'X-Riak-Vclock: ' . $this->vclock;
-
-        /**
-         * Add the Links
-         */
-        foreach ($this->_links as $link)
-            $headers[] = 'Link: ' . $link->toLinkHeader($this->client);
-
-        /**
-         * Add the auto indexes
-         */
-        if (is_array($this->_autoIndexes) && !empty($this->_autoIndexes)) {
-            if (!is_array($this->data))
-                throw new Exception('Auto index feature requires that "$this->data" be an array.');
-
-            $collisions = array();
-            foreach ($this->_autoIndexes as $index => $fieldName) {
-                $value = null;
-                // look up the value
-                if (isset($this->data[$fieldName])) {
-                    $value = $this->data[$fieldName];
-                    $headers[] = 'X-Riak-Index-' . $index . ': ' . urlencode($value);
-
-                    // look for value collisions with normal indexes
-                    if (isset($this->_indexes[$index]))
-                        if (false !== array_search($value, $this->_indexes[$index]))
-                            $collisions[$index] = $value;
-                }
-            }
-
-            $this->_meta['client-autoindex'] = count($this->_autoIndexes) > 0 ? CJSON::encode($this->_autoIndexes) : null;
-            $this->_meta['client-autoindexcollision'] = count($collisions) > 0 ? CJSON::encode($collisions) : null;
-        }
-
-        /**
-         * Add the indexes
-         */
-        foreach ($this->_indexes as $index => $values)
-            if (is_array($values))
-                $headers[] = 'X-Riak-Index-' . $index . ': ' . implode(', ', array_map('urlencode', $values));
-
-        /**
-         * Add the metadata
-         */
-        foreach ($this->_meta as $metaName => $metaValue)
-            if ($metaValue !== null)
-                $headers[] = 'X-Riak-Meta-' . $metaName . ': ' . $metaValue;
-
-        if ($this->jsonize)
-            $content = CJSON::encode($this->data);
-        else
-            $content = $this->data;
-
-        /**
-         * Run the operation
-         */
-        if ($this->key) {
-            Yii::trace('Storing object with key "' . $this->key . '" in bucket "' . $this->bucket->name . '"', 'ext.riiak.Object');
-            $response = $this->client->transport->putObject($this->bucket, $headers, $content, $url);
-        } else {
-            Yii::trace('Storing new object in bucket "' . $this->bucket->name . '"', 'ext.riiak.Object');
-            $response = $this->client->transport->post($url, $headers, $content);
-        }
-
-        return self::populateResponse($this, $response, 'storeObject');
+        $params = array('returnbody' => 'true', 'w' => $this->bucket->getW($w), 'dw' => $this->bucket->getDW($dw));
+        $response = $this->client->transport->storeObject($this, $params);
+        return self::populateResponse($this, $response);
     }
 
     /**
          */
         $params = array('r' => $this->bucket->getR($r));
         Yii::trace('Reloading object "' . $this->key . '" from bucket "' . $this->bucket->name . '"', 'ext.riiak.Object');
-        $response = $this->client->transport->getObject($this->bucket, $params, $this->key, null);
+        $response = $this->client->transport->fetchObject($this->bucket, $this->key, $params);
         return self::populateResponse($this, $response);
     }
 
          * Get (fetch) multiple objects
          */
         $responses = $client->transport->multiGet(array_keys($objects));
-        array_walk($objects, function(&$object, $url)use(&$responses) {
+        array_walk($objects, function($object, $url)use(&$responses) {
                     Object::populateResponse($object, $responses[$url]);
                 });
         return $objects;
     }
 
     /**
+     * @static
      * @param Object $object
      * @param array $response
      * @return Object
      */
-    public static function populateResponse(Object &$object, $response, $action='fetchObject') {
-        $object->client->transport->populate($object, $object->bucket, $response, $action);
+    public static function populateResponse(Object $object, $response) {
+        $object->client->transport->populate($object, $response);
 
         /**
          * Parse the index and metadata headers
         /**
          * Use defaults if not specified
          */
-        $dw = $this->bucket->getDW($dw);
-
-        /**
-         * Construct the URL
-         */
-        $url = $this->client->transport->buildBucketKeyPath($this->bucket, $this->key, null, array('dw' => $dw));
-
-        /**
-         * Run the operation
-         */
-        Yii::trace('Deleting object "' . $this->key . '" from bucket "' . $this->bucket->name . '"', 'ext.riiak.Object');
-        $response = $this->client->transport->delete($url);
-        $this->client->transport->populate($this, $this->bucket, $response, 'deleteObject');
+        $params = array('dw'=>$this->bucket->getDW($dw));
+        $response = $this->client->transport->deleteObject($this, $params);
+        $this->client->transport->populate($this, $response);
 
         return $this;
     }
         $params = array('r' => $r, 'vtag' => $vtag);
 
         Yii::trace('Fetching sibling "' . $i . '" of object "' . $this->key . '" from bucket "' . $this->bucket->name . '"', 'ext.riiak.Object');
-        $response = $this->client->transport->getObject($this->bucket, $params, $this->key, null);
+        $response = $this->client->transport->fetchObject($this->bucket, $this->key, $params);
 
         /**
          * Respond with a new object
          */
         $obj = new Object($this->client, $this->bucket, $this->key);
         $obj->jsonize = $this->jsonize;
-        return self::populateResponse($obj, $response, 'getSibling');
+        return self::populateResponse($obj, $response);
     }
 
     /**
     public function buckets() {
         Yii::log('Bucket listing is a very intensive operation, and should never occur in production!', \CLogger::LEVEL_WARNING);
         Yii::trace('Fetching list of buckets', 'ext.riiak.Riiak');
-        return $this->transport->getBuckets($this);
+        return array_map(array($this, 'bucket'), $this->transport->listBuckets());
     }
 
     /**

File Transport.php

 /**
  * Contains transport layer actions of Riak
  * @package riiak
+ *
+ * @property-read bool $isAlive
+ * @property-read array $riakConfiguration
+ * @property-read \riiak\transport\Status $statusObject
  */
 abstract class Transport extends CComponent {
 
     }
 
     /**
-     * Builds URL to connect to Riak server
-     *
-     * @return string
-     */
-    #abstract public function buildUrl();
-
-    /**
-     * Builds a REST URL to access Riak API
-     *
-     * @param object $bucket
-     * @param string $key
-     * @param string $spec
-     * @param array $params
-     * @return string
-     */
-    #abstract public function buildRestPath(Bucket $bucket = NULL, $key = NULL, $spec = NULL, array $params = NULL);
-
-    /**
-     * Return array of Bucket objects
+     * Return array of Bucket names
      *
      * @return array
      */
-    abstract public function getBuckets();
+    abstract public function listBuckets();
+
+    /**
+     * Return array of Bucket's object keys
+     *
+     * @return array
+     */
+    abstract public function listBucketKeys(\riiak\Bucket $bucket);
+    abstract public function listBucketProps(\riiak\Bucket $bucket);
+
+    /**
+     * Fetches Bucket object
+     *
+     * @return array
+     */
+    abstract public function getBucket(\riiak\Bucket $bucket, array $params = array());
+
+    /**
+     * Updates (sets) Bucket object
+     *
+     * @return array
+     */
+    abstract public function setBucket(\riiak\Bucket $bucket, array $properties);
+
+    abstract public function fetchObject(\riiak\Bucket $bucket, $key, array $params = null);
+
+    abstract public function storeObject(\riiak\Object $object, array $params = array());
+
+    abstract public function deleteObject(\riiak\Object $object, array $params = array());
+
+    abstract public function linkWalk(\riiak\Bucket $bucket, $key, array $links, array $params = null);
+
+    abstract public function mapReduce();
+
+    abstract public function secondaryIndex();
+
+    abstract public function ping();
+
+    abstract public function status();
+
+    abstract public function listResources();
 
     /**
      * Check if Riak server is alive
     abstract public function getIsAlive();
 
     /**
-     * Get (fetch) an object
-     *
-     * @param \riiak\Bucket $bucket
-     * @param array $params
-     * @param string $key
-     * @param string $spec
-     * @return array
-     */
-    #abstract public function get(Bucket $bucket = NULL, array $params = array(), $key = null, $spec = null);
-
-    /**
-     * Put (save) an object
-     *
-     * @param \riiak\Bucket $bucket
-     * @param array $params
-     * @return array $response
-     */
-    #abstract public function put(Bucket $bucket = NULL, $headers = NULL, $contents = '');
-
-    /**
-     * Method to store object in Riak.
-     *
-     * @param string $url
-     * @param array $params
-     * @param string $headers
-     * @return array
-     */
-    #abstract public function post($url = NULL, array $params = array(), $headers = '');
-
-    /**
-     * Method to delete object in Riak.
-     *
-     * @param string $url
-     * @param array $params
-     * @param string $headers
-     * @return array
-     */
-    #abstract public function delete(Bucket $bucket = NULL, $key = '', array $params = array(), $headers = '');
-
-    /**
      * Executes request, returns named array(headers, body) of request, or null on error
      *
      * @param 'GET'|'POST'|'PUT'|'DELETE' $method
      *
      * @param string $response
      * @param string $action
-     * @return bool
+     * @throws \Exception
      */
     abstract public function validateResponse($response, $action);
 
     /**
-     * Get staus handling class object
+     * Get status handling class object
      *
      * @return object http\Status
      */

File transport/Http.php

 namespace riiak\transport;
 
 use \CJSON,
-    \Exception,
-    \Yii,
-    \CLogger;
+\Exception,
+\Yii,
+\CLogger;
 
 /**
  * The Http object allows you to perform all Riak operation
  * through HTTP protocol
- * @package riiak.transport
+ *
+ * @package            riiak.transport
  *
  * @abstract
  *
- * @method array get() get(string $url, array $requestHeaders = array(), string $content = '') Alias for processRequest('GET', ...)
- * @method array post() post(string $url, array $requestHeaders = array(), string $content = '') Alias for processRequest('POST', ...)
- * @method array put() put(string $url, array $requestHeaders = array(), string $content = '') Alias for processRequest('PUT', ...)
+ * @method array get   () get(string $url, array $requestHeaders = array(), string $content = '') Alias for processRequest('GET', ...)
+ * @method array post  () post(string $url, array $requestHeaders = array(), string $content = '') Alias for processRequest('POST', ...)
+ * @method array put   () put(string $url, array $requestHeaders = array(), string $content = '') Alias for processRequest('PUT', ...)
  * @method array delete() delete(string $url, array $requestHeaders = array(), string $content = '') Alias for processRequest('DELETE', ...)
  */
 abstract class Http extends \riiak\Transport {
         return parent::__call($name, $parameters);
     }
 
+    public function listBuckets() {
+        /**
+         * Construct URL
+         */
+        $url = $this->buildBucketPath(null, null, array('buckets' => 'true'));
+        Yii::trace('Running listBuckets request', 'ext.riiak.transport.http.listBuckets');
+
+        /**
+         * Run the request
+         */
+        $response = $this->processRequest('GET', $url);
+        $this->validateResponse($response, 'listBuckets');
+
+        /**
+         * Return array of bucket names
+         */
+        $body = (array)CJSON::decode($response['body']);
+        if (isset($body['buckets']) && is_array($body['buckets']))
+            return array_map('urldecode', array_unique($body['buckets']));
+        return array();
+    }
+
+    public function listBucketKeys(\riiak\Bucket $bucket) {
+        /**
+         * Fetch the bucket
+         */
+        Yii::trace('Running listKeys request for bucket "' . $bucket->name . '"', 'ext.riiak.transport.http.listKeys');
+        $bucketArr = $this->getBucket($bucket, array('props' => 'false', 'keys' => 'stream'));
+
+        if (isset($bucketArr['keys']) && is_array($bucketArr['keys']))
+            return array_map('urldecode', array_unique($bucketArr['keys']));
+        return array();
+    }
+
+    public function listBucketProps(\riiak\Bucket $bucket) {
+        /**
+         * Fetch the bucket
+         */
+        Yii::trace('Running listProps request for bucket "' . $bucket->name . '"', 'ext.riiak.transport.http.listProps');
+        $bucketArr = $this->getBucket($bucket, array('props' => 'true', 'keys' => 'false'));
+
+        if (isset($bucketArr['props']) && is_array($bucketArr['props']))
+            return array_map('urldecode', array_unique($bucketArr['props']));
+        return array();
+    }
+
+    public function getBucket(\riiak\Bucket $bucket, array $params = array()) {
+        /**
+         * Construct the URL
+         */
+        $url = $this->buildBucketKeyPath($bucket, null, null, $params);
+        Yii::trace('Running getBucket request for bucket "' . $bucket->name . '"', 'ext.riiak.transport.http.getBucket');
+
+        /**
+         * Run the request.
+         */
+        $response = $this->processRequest('GET', $url);
+        $this->validateResponse($response, 'getBucket');
+
+        /**
+         * Return decoded bucket array
+         */
+        return (array)CJSON::decode($response['body']);
+    }
+
+    public function setBucket(\riiak\Bucket $bucket, array $properties) {
+        /**
+         * Construct the contents
+         */
+        $headers = array('Content-Type: application/json');
+        $content = CJSON::encode(array('props' => $properties));
+
+        /**
+         * Construct the request URL.
+         */
+        $url = $this->buildBucketKeyPath($bucket);
+        Yii::trace('Running setBucket request for bucket "' . $bucket->name . '"', 'ext.riiak.transport.http.setBucket');
+
+        /**
+         * Process request & return response
+         */
+        $response = $this->processRequest('PUT', $url, $headers, $content);
+        $this->validateResponse($response, 'setBucket');
+
+        return true;
+    }
+
+    public function fetchObject(\riiak\Bucket $bucket, $key, array $params = null) {
+        /**
+         * Construct the URL
+         */
+        $url = $this->buildBucketKeyPath($bucket, $key, null, $params);
+        Yii::trace('Running fetchObject request for bucket "' . $bucket->name . '"', 'ext.riiak.transport.fetchObject');
+
+        /**
+         * Process request.
+         */
+        $response = $this->processRequest('GET', $url);
+        try {
+            $this->validateResponse($response, 'fetchObject');
+        }catch(\Exception $e) {
+            /**
+             * Allow 404 for missing objects
+             * @todo Perhaps 404 should still toss exception?
+             */
+            if($e->getCode()!='404')
+                throw $e;
+        }
+
+        /**
+         * Return response
+         */
+        return $response;
+    }
+
+    public function storeObject(\riiak\Object $object, array $params = array()) {
+        /**
+         * Construct the URL
+         */
+        $url    = $this->buildBucketKeyPath($object->bucket, $object->key, null, $params);
+
+        /**
+         * Construct the headers
+         */
+        $headers = array('Accept: text/plain, */*; q=0.5',
+            'Content-Type: ' . $object->getContentType(),
+            'X-Riak-ClientId: ' . $object->client->clientId);
+
+        /**
+         * Add the vclock if it exists
+         */
+        if (!empty($object->vclock))
+            $headers[] = 'X-Riak-Vclock: ' . $object->vclock;
+
+        /**
+         * Add the Links
+         */
+        foreach ($object->links as $link)
+            $headers[] = 'Link: ' . $link->toLinkHeader($object->client);
+
+        /**
+         * Add the auto indexes
+         */
+        if (is_array($object->autoIndexes) && !empty($object->autoIndexes)) {
+            if (!is_array($object->data))
+                throw new Exception('Auto index feature requires that "$object->data" be an array.');
+
+            $collisions = array();
+            foreach ($object->autoIndexes as $index => $fieldName) {
+                $value = null;
+                // look up the value
+                if (isset($object->data[$fieldName])) {
+                    $value     = $object->data[$fieldName];
+                    $headers[] = 'X-Riak-Index-' . $index . ': ' . urlencode($value);
+
+                    // look for value collisions with normal indexes
+                    if (isset($object->indexes[$index]))
+                        if (false !== array_search($value, $object->indexes[$index]))
+                            $collisions[$index] = $value;
+                }
+            }
+
+            $object->meta['client-autoindex']          = count($object->autoIndexes) > 0 ? CJSON::encode($object->autoIndexes) : null;
+            $object->meta['client-autoindexcollision'] = count($collisions) > 0 ? CJSON::encode($collisions) : null;
+        }
+
+        /**
+         * Add the indexes
+         */
+        foreach ($object->indexes as $index => $values)
+            if (is_array($values))
+                $headers[] = 'X-Riak-Index-' . $index . ': ' . implode(', ', array_map('urlencode', $values));
+
+        /**
+         * Add the metadata
+         */
+        foreach ($object->meta as $metaName => $metaValue)
+            if ($metaValue !== null)
+                $headers[] = 'X-Riak-Meta-' . $metaName . ': ' . $metaValue;
+
+        if ($object->jsonize)
+            $content = CJSON::encode($object->data);
+        else
+            $content = $object->data;
+
+        /**
+         * Run the operation
+         */
+        if ($object->key !== null) {
+            Yii::trace('Storing object with key "' . $object->key . '" in bucket "' . $object->bucket->name . '"', 'ext.riiak.Object');
+            $response = $this->put($url, $headers, $content);
+        } else {
+            Yii::trace('Storing new object in bucket "' . $object->bucket->name . '"', 'ext.riiak.Object');
+            $response = $this->post($url, $headers, $content);
+        }
+
+        $action = (isset($params['returnbody']) && $params['returnbody']) ? 'fetchObject' : 'storeObject';
+        $this->validateResponse($response, $action);
+
+        return $response;
+    }
+
+    public function deleteObject(\riiak\Object $object, array $params = array()) {
+        /**
+         * Construct the URL
+         */
+        $url = $this->buildBucketKeyPath($object->bucket, $object->key, null, $params);
+        Yii::trace('Running deleteObject request for object "' . $object->key . '"', 'ext.riiak.transport.deleteObject');
+
+        /**
+         * Process request.
+         */
+        $response = $this->processRequest('DELETE', $url);
+        $this->validateResponse($response, 'deleteObject');
+
+        /**
+         * Return response
+         */
+        return $response;
+    }
+
+    /**
+     * @todo Handle multipart/mixed response from linkwalk
+     */
+    public function linkWalk(\riiak\Bucket $bucket, $key, array $links, array $params = null) {
+        /**
+         * Construct the URL
+         */
+        $url = $this->buildBucketKeyPath($bucket, $key, $links, $params);
+        Yii::trace('Running linkWalk request for object "' . $key . '"', 'ext.riiak.transport.linkWalk');
+
+        /**
+         * Process request.
+         */
+        $response = $this->processRequest('GET', $url);
+        $this->validateResponse($response, 'linkWalk');
+
+        /**
+         * Return response
+         */
+        return $response;
+    }
+
+    public function mapReduce() {
+        /**
+         * @todo Build out this function
+         */
+    }
+
+    public function secondaryIndex() {
+        /**
+         * @todo Build out this function
+         */
+    }
+
+    public function ping() {
+        Yii::trace('Pinging Riak server', 'ext.riiak.transport.http.ping');
+        $response = $this->processRequest('GET', $this->buildUri('/' . $this->client->pingPrefix));
+        $this->validateResponse($response, 'ping');
+
+        return ($response !== NULL) && ($response['body'] == 'OK');
+    }
+
+    public function status() {
+        /**
+         * @todo implement
+         */
+    }
+
+    public function listResources() {
+        /**
+         * @todo implement
+         */
+    }
+
     /**
      * Get status handling class object
      *
-     * @return object http\StatusCodes
+     * @return object http\Status
      */
     public function getStatusObject() {
         /**
          * Check for existing status handling class object
          */
         if (!is_object($this->status))
-            $this->status = new http\StatusCodes();
+            $this->status = new http\Status();
 
         /*
          * Return status class object
     }
 
     /**
-     * Validate Riak response using http\StatusCodes class
+     * Validate Riak response using http\Status class
      *
-     * @param string $response
+     * @param array  $response
      * @param string $action
-     * @return bool
+     * @throws \Exception
      */
     public function validateResponse($response, $action) {
-        return $this->getStatusObject()->validateStatus($response, $action);
+        if(!$this->getStatusObject()->validateStatus($response, $action)) {
+            $httpCode = $response['headers']['http_code'];
+            $httpStatus = $response['headers']['http_status'];
+
+            $errorMsg = (is_array($httpStatus) ? implode(', ', $httpStatus) : $httpStatus) . ' - ';
+            /**
+             * Check for error definitions
+             */
+            if (array_key_exists($httpCode, $this->getStatusObject()->errorCodes[$action]))
+                $errorMsg .= $this->getStatusObject()->errorCodes[$action][$httpCode];
+            else
+                $errorMsg .= 'An undefined error has occurred!';
+
+            throw new Exception($errorMsg, $httpCode);
+        }
     }
 
     /**
     }
 
     /**
-     * Get (fetch) an object
+     * @param string $appendPath optional
+     * @param array  $params     optional
      *
-     * This is renamed from "get", as "get" should be a generic function...
-     * @todo Function is in dire need of refactoring
-     *
-     * @param \riiak\Bucket $bucket
-     * @param array $params
-     * @param string $key
-     * @param array $links
-     * @return array
-     */
-    public function getObject(\riiak\Bucket $bucket, array $params = array(), $key = null, $links = array()) {
-        /**
-         * Construct the URL
-         */
-        $url = $this->buildBucketKeyPath($bucket, $key, $links, $params);
-        Yii::trace('Running getObject request for bucket "' . $bucket->name . '"', 'ext.riiak.transport.httpRequest');
-
-        /**
-         * Process request.
-         */
-        $response = $this->processRequest('GET', $url);
-
-        /**
-         * Remove bulk of empty keys.
-         */
-        $response['body'] = $this->getStreamedBucketKeys($response, $params);
-
-        /**
-         * Return response
-         */
-        return $response;
-    }
-
-    /**
-     * Put (save) an object
-     *
-     * This is renamed from "put", as "put" should be a generic function...
-     *
-     * @param \riiak\Bucket $bucket
-     * @param string $headers
-     * @param string $content
-     * @param string $url
-     * @return array $response
-     */
-    public function putObject(\riiak\Bucket $bucket = NULL, $headers = NULL, $content = '', $url = '') {
-        /**
-         * Construct the request URL.
-         */
-        if ($url == '')
-            $url = $this->buildBucketKeyPath($bucket);
-
-        /**
-         * Process request.
-         */
-        $response = $this->processRequest('PUT', $url, $headers, $content);
-
-        /**
-         * Return Riak response
-         */
-        return $response;
-    }
-
-    /**
-     * @param string $appendPath optional
-     * @param array $params optional
      * @return string
      */
     public function buildMapReducePath($appendPath = NULL, array $params = NULL) {
      * @author Eric Stevens <estevens@taglabsinc.com>
      *
      * @param \riiak\Bucket $bucket
-     * @param string $index Index name and type (e.g. - 'indexName_bin')
-     * @param string|int $start Starting value or exact match if no end value
-     * @param string|int $end optional Ending value for range search
-     * @param array $params optional Any extra query parameters
+     * @param string        $index  Index name and type (e.g. - 'indexName_bin')
+     * @param string|int    $start  Starting value or exact match if no end value
+     * @param string|int    $end    optional Ending value for range search
+     * @param array         $params optional Any extra query parameters
+     *
      * @return string
      */
     public function buildBucketIndexPath(\riiak\Bucket $bucket, $index, $start, $end = NULL, array $params = NULL) {
      * Builds URL for Riak bucket/keys query
      *
      * @param \riiak\Bucket $bucket
-     * @param string $key optional
-     * @param array $links optional
-     * @param array $params optional
+     * @param string        $key    optional
+     * @param array         $links  optional
+     * @param array         $params optional
+     *
      * @return string
      */
     public function buildBucketKeyPath(\riiak\Bucket $bucket, $key = NULL, array $links = NULL, array $params = NULL) {
     /**
      * Builds URL for Riak bucket query
      *
-     * @param \riiak\Bucket $bucket optional
-     * @param string $appendPath optional
-     * @param array $params optional
+     * @param \riiak\Bucket $bucket     optional
+     * @param string        $appendPath optional
+     * @param array         $params     optional
+     *
      * @return string
      */
     public function buildBucketPath(\riiak\Bucket $bucket = NULL, $appendPath = NULL, array $params = NULL) {
      * Generic method for building uri
      *
      * @param string $path
-     * @param array $params optional
+     * @param array  $params optional
+     *
      * @return string
      */
     public function buildUri($path, array $params = NULL) {
     /**
      * Returns process headers along with status code & body
      *
-     * @param int $httpCode
+     * @param int    $httpCode
      * @param string $headers
      * @param string $body
+     *
      * @return array[headers,body]
      */
     public function processResponse($httpCode, $headers, $body) {
      * Parse HTTP header string into an assoc array
      *
      * @param string $headers
+     *
      * @return array
      */
     public function processHeaders($headers) {
         $retVal = array();
         $fields = array_filter(explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $headers)));
         foreach ($fields as $field) {
-            if (preg_match('/([^:]+): (.+)/m', $field, $match)) {
+            if (preg_match('@^HTTP/1\.1\s+(\d+\s+[\w\s]+)@', $field, $match)) {
+                if (isset($retVal['http_status']))
+                    $retVal['http_status'] = array_merge((array)$retVal['http_status'], (array)trim($match[1]));
+                else
+                    $retVal['http_status'] = trim($match[1]);
+            } elseif (preg_match('/([^:]+): (.+)/m', $field, $match)) {
                 $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', strtolower(trim($match[1])));
                 if (isset($retVal[$match[1]]))
-                    $retVal[$match[1]] = array($retVal[$match[1]], $match[2]);
+                    $retVal[$match[1]] = array_merge((array)$retVal[$match[1]], (array)trim($match[2]));
                 else
                     $retVal[$match[1]] = trim($match[2]);
             }
     }
 
     /**
-     * Return array of Bucket objects
-     *
-     * @return array
-     */
-    public function getBuckets() {
-        Yii::trace('Fetching list of buckets', 'ext.riiak.transport.http');
-        /**
-         * Construct URL
-         */
-        $url = $this->buildBucketPath(null, null, array('buckets' => 'true'));
-
-        /**
-         * Send request to fetch buckets.
-         */
-        $response = $this->processRequest('GET', $url);
-        $responseObj = (array) CJSON::decode($response['body']);
-        $buckets = array();
-
-        /**
-         * Prepare loop to process bucket list.
-         */
-        foreach ($responseObj['buckets'] as $name)
-            $buckets[] = $this->client->bucket($name);
-
-        /**
-         * Return bucket array.
-         */
-        return $buckets;
-    }
-
-    /**
      * Get (fetch) multiple objects
      *
-     * @param array $urls
-     * @param array $requestHeaders
+     * @param array  $urls
+     * @param array  $requestHeaders
      * @param string $content
+     *
      * @return array
      */
     abstract public function multiGet(array $urls, array $requestHeaders = array(), $content = '');
      * Populates the object. Only for internal use
      *
      * @param \riiak\Object $object
-     * @param \riiak\Bucket $bucket
-     * @param array $response Output of transport layer processing
-     * @param string $action Action label (used to fetch expected statuses)
+     * @param array         $response Output of transport layer processing
+     *
      * @return \riiak\Object
      */
-    public function populate(\riiak\Object $object, \riiak\Bucket $bucket, array $response = array(), $action = '') {
-        /**
-         * Check for allowed response status list.
-         */
-        $expectedStatuses = $this->getStatusObject()->getExpectedStatus($action);
-
-        if (0 >= count($expectedStatuses))
-            $expectedStatuses = array(200, 201, 300);
-
-        /**
-         * Check for riiak\Object class object
-         */
-        if (!is_object($object))
-            $object = new \riiak\Object($this->client, $bucket);
-
+    public function populate(\riiak\Object $object, array $response = array()) {
         $object->clear();
 
         /**
-         * If no response given, then return
-         */
-        if (is_null($response))
-            return $this;
-
-        /**
          * Update the object
          */
         $object->headers = $response['headers'];
-        $object->data = $response['body'];
-
-        /**
-         * Check if the server is down (status==0)
-         */
-        if ($object->status == 0)
-            throw new Exception('Could not contact Riak Server: ' . $this->baseUrl() . '!');
-
-        /**
-         * Verify that we got one of the expected statuses. Otherwise, throw an exception
-         */
-        if (!$this->validateResponse($response, $action))
-            throw new Exception('Expected status ' . implode(' or ', $expectedStatuses) . ', received ' . $object->status);
+        $object->data    = $response['body'];
 
         /**
          * If 404 (Not Found), then clear the object
          */
-        if ($object->status == 404) {
+        if ($object->httpCode == 404) {
             $object->clear();
             return $object;
         }
         /**
          * If 300 (siblings), load first sibling, store the rest
          */
-        if ($object->status == 300) {
+        if ($object->httpCode == 300) {
             $siblings = explode("\n", trim($object->data));
             array_shift($siblings); # Get rid of 'Siblings:' string.
             $object->siblings = $siblings;
-            $object->exists = true;
+            $object->exists   = true;
             return $object;
-        }
-
-        if ($object->status == 201) {
-            $pathParts = explode('/', $object->headers['location']);
+        }elseif ($object->httpCode == 201) {
+            $pathParts   = explode('/', $object->headers['location']);
             $object->key = array_pop($pathParts);
         }
 
         /**
          * Possibly JSON decode
          */
-        if (($object->status == 200 || $object->status == 201) && $object->jsonize)
+        if (($object->httpCode == 200 || $object->httpCode == 201) && $object->jsonize)
             $object->data = CJSON::decode($object->data, true);
 
         return $object;

File transport/Status.php

  * @abstract
  */
 abstract class Status {
-    
+
     /**
-     * List of normal codes for Riak operations
-     * 
-     * @var array 
+     * List of Expected status codes for Riak operations
+     *
+     * @var array
      */
-    protected $normalCodes;
-    
+    protected $expectedStatus;
+
     /**
      * List of Error codes for Riak operations
      * 
      * @var array 
      */
     protected $errorCodes;
-    
-    /**
-     * List of Expected status codes for Riak operations
-     * 
-     * @var array 
-     */
-    protected $expectedStatus;
 
     /**
-     * Validate Riak response
-     * 
-     * @param string $response
+     * Handle Riak response
+     *
+     * @param array $response
      * @param string $action
      * @return bool 
      */
-    abstract public function validateStatus($response, $action);
-    
-    /**
-     * Handle Riak response
-     * 
-     * @param string $status
-     * @param string $index
-     * @return bool 
-     */
-    abstract public function handleResponse($status, $index);
-    
-    /**
-     * Get Riak response status code
-     * 
-     * @param string $response
-     * @return string 
-     */
-    abstract public function getResponseStatus($response);
-    
+    abstract public function validateStatus(array $response, $action);
+
     /**
      * Get expected status codes for Riak operation
      * 
      * @param string $action
      * @return array 
      */
-    abstract public function getExpectedStatus($action = '');
+    abstract public function getExpectedStatus($action);
 }

File transport/http/Curl.php

         $ch = curl_init();
         $curlOpts = $this->buildCurlOpts($method, $url, $requestHeaders, $content);
 
+        Yii::trace('Processing HTTP "'.strtoupper($method).'" request to "'.$url.'"', 'ext.riiak.transport.http.curl.processRequest');
         if ($this->client->enableProfiling)
             $profileToken = 'ext.riiak.transport.http.curl.processRequest(' . \CVarDumper::dumpAsString($this->readableCurlOpts($curlOpts)) . ')';
 
          *  Convert input string into array
          *  for example :
          *  Input string is {"keys":[]}{"keys":["admin"]}{"keys":[]}{"keys":["test"]} etc.
-         *  then output wiil be {"keys":[]},{"keys":["admin"]},{"keys":[]},{"keys":["test"]}
+         *  then output will be {"keys":[]},{"keys":["admin"]},{"keys":[]},{"keys":["test"]}
          */
         $arrInput = explode('#,#', str_replace('}{', '}#,#{', $response['body']));
 
             $data = (array) CJSON::decode($value);
 
             /**
-             *  Check for keys count is greate than 0.
+             *  Check for keys count is greater than 0.
              */
             if (array_key_exists('keys', $data) && 1 < count($data['keys']))
                 $strKeys .= implode('#,#', $data['keys']) . '#,#';
         return CJSON::encode($arrOutput);
     }
 
-}
+}

File transport/http/Status.php

+<?php
+
+namespace riiak\transport\http;
+
+/**
+ * Status Object allows you to validate all Riak operation
+ * responses.
+ * @package riiak.transport.http
+ *
+ * @todo Streamline custom error definitions
+ */
+class Status extends \riiak\transport\Status {
+
+    /**
+     * List of Expected status codes for Riak operations.
+     *
+     * @var array
+     */
+    public $expectedStatus = array(
+        'listBuckets' => array('200'),
+        'getBucketProperties' => array('200'),
+        'setBucketProperties' => array('204'),
+        'fetchObject' => array('200', '300', '304'),
+        'storeObject' => array('200', '201', '204', '300'),
+        'deleteObject' => array('204', '404'),
+        'linkWalking' => array('200'),
+        'mapReduce' => array('200'),
+        'secondaryIndex' => array('200'),
+        'ping' => array('200'),
+        'status' => array('200'),
+        'listResource' => array('200')
+    );
+
+    /**
+     * List of known error codes for Riak operations
+     *
+     * @var array
+     */
+    public $errorCodes = array(
+        'setBucketProperties' => array(
+            '400' => 'Submitted JSON is invalid',
+            '415' => 'The Content-Type was not set to application/json in the request'
+        ),
+        'fetchObject' => array(
+            '400' => 'Bad request, e.g. r parameter is invalid (> N)',
+            '404' => 'The object could not be found on enough partitions',
+            '503' => 'The request timed out'
+        ),
+        'storeObject' => array(
+            '400' => 'Bad request, e.g. r, w, or dw parameters are invalid (> N)',
+            '412' => 'Precondition Failed (r, w, or dw parameters are invalid (> N))'
+        ),
+        'deleteObject' => array(
+            '400' => 'Bad request, e.g. rw parameter is invalid (> N)'
+        ),
+        'linkWalking' => array(
+            '400' => 'Format of the query in the URL is invalid',
+            '404' => 'Origin object of the walk was missing'
+        ),
+        'mapReduce' => array(
+            '400' => 'Invalid job is submitted.',
+            '500' => 'There was an error in processing a map or reduce function',
+            '503' => 'The job timed out before it could complete'
+        ),
+        'secondaryIndex' => array(
+            '400' => 'The index name or index value is invalid.',
+            '500' => 'There was an error in processing a map or reduce function, or indexing is not supported by the system.',
+            '503' => 'The job timed out before it could complete'
+        ),
+        'status' => array(
+            '404' => 'The setting "riak_kv_stat" may be disabled',
+        )
+    );
+
+    /**
+     * Handle Riak response
+     *
+     * @param array $response
+     * @param string $action
+     * @return bool
+     */
+    public function validateStatus(array $response, $action) {
+        /**
+         * Check for normal status codes
+         */
+        if (!in_array($response['headers']['http_code'], $this->getExpectedStatus($action))) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Get expected status codes for Riak operation
+     *
+     * @param string $action
+     * @return array
+     */
+    public function getExpectedStatus($action) {
+        /**
+         * Check for action is exists in expectedStatus array or not.
+         */
+        if (!array_key_exists($action, $this->expectedStatus))
+            return array('200');
+
+        return $this->expectedStatus[$action];
+    }
+
+}

File transport/http/StatusCodes.php

-<?php
-
-namespace riiak\transport\http;
-
-use \CJSON,
-    \Exception,
-    \Yii,
-    \CLogger;
-
-/**
- * StatusCodes Object allows you to validate all Riak operation
- * responses.
- * @package riiak.transport.http
- *
- * @todo Give basic definition of HTTP codes, using header response
- * @todo Streamline custom error definitions
- */
-class StatusCodes extends \riiak\transport\Status {
-
-    /**
-     * List of Expected status codes for Riak operations.
-     *
-     * @var array
-     */
-    protected $expectedStatus = array(
-        'listBuckets' => array('200'),
-        'listKeys' => array('200'),
-        'getBucketProperties' => array('200'),
-        'setBucketProperties' => array('204'),
-        'fetchObject' => array('200', '300', '304'),
-        'storeObject' => array('200', '201', '204', '300'),
-        'deleteObject' => array('204', '404'),
-        'linkWalking' => array('200'),
-        'mapReduce' => array('200'),
-        'secondaryIndex' => array('200'),
-        'ping' => array('200'),
-        'status' => array('200'),
-        'listResource' => array('200')
-    );
-
-    /**
-     * List of normal codes for Riak operations
-     *
-     * @var array
-     */
-    protected $normalCodes = array(
-        'listBuckets' => array(
-            '200' => 'OK'
-        ),
-        'listKeys' => array(
-            '200' => 'OK'
-        ),
-        'getBucketProperties' => array(
-            '200' => 'OK'
-        ),
-        'setBucketProperties' => array(
-            '204' => 'No Content'
-        ),
-        'fetchObject' => array(
-            '200' => 'OK',
-            '300' => 'Multiple Choices',
-            '304' => 'Not Modified'
-        ),
-        'storeObject' => array(
-            '200' => 'OK',
-            '201' => 'Created',
-            '204' => 'No Content',
-            '300' => 'Multiple Choices'
-        ),
-        'deleteObject' => array(
-            '204' => 'No Content',
-            '404' => 'Not Found'
-        ),
-        'linkWalking' => array(
-            '200' => 'Ok'
-        ),
-        'mapReduce' => array(
-            '200' => 'Ok'
-        ),
-        'secondaryIndex' => array(
-            '200' => 'Ok'
-        ),
-        'ping' => array(
-            '200' => 'OK'
-        ),
-        'status' => array(
-            '200' => 'OK'
-        ),
-        'listResource' => array(
-            '200' => 'OK'
-        ),
-    );
-
-    /**
-     * List of Error codes for Riak operations
-     *
-     * @var array
-     */
-    protected $errorCodes = array(
-        'setBucketProperties' => array(
-            '400' => 'Set Bucket Properties - Bad Request - Submitted JSON is invalid',
-            '415' => 'Set Bucket Properties - Unsupported Media Type - The Content-Type was not set to application/json in the request'
-        ),
-        'fetchObject' => array(
-            '400' => 'Fetch Bucket Properties - Bad Request - e.g. r parameter is invalid (> N)',
-            '404' => 'Fetch Bucket Properties - The object could not be found on enough partitions',
-            '503' => 'Fetch Bucket Properties - Service Unavailable - The request timed out'
-        ),
-        'storeObject' => array(
-            '400' => 'Store Object - Bad Request - e.g. r, w, or dw parameters are invalid (> N)',
-            '412' => 'Store Object - Precondition Failed (r, w, or dw parameters are invalid (> N))'
-        ),
-        'deleteObject' => array(
-            '400' => 'Delete Object - Bad Request - e.g. rw parameter is invalid (> N)'
-        ),
-        'linkWalking' => array(
-            '400' => 'Link Walking - Bad Request - Format of the query in the URL is invalid',
-            '404' => 'Link Walking - Not Found - Origin object of the walk was missing'
-        ),
-        'mapReduce' => array(
-            '400' => 'MapReduce - Bad Request - Invalid job is submitted.',
-            '500' => 'MapReduce - Internal Server Error - There was an error in processing a map or reduce function',
-            '503' => 'MapReduce - Service Unavailable - The job timed out before it could complete'
-        ),
-        'secondaryIndex' => array(
-            '400' => 'Secondary Indexes - Bad Request - The index name or index value is invalid.',
-            '500' => 'Secondary Indexes - Internal Server Error - There was an error in processing a map or reduce function, or indexing is not supported by the system.',
-            '503' => 'Secondary Indexes - Service Unavailable - The job timed out before it could complete'
-        ),
-        'status' => array(
-            '404' => 'Riak Server Status - Not Found - The setting "riak_kv_stat" may be disabled',
-        )
-    );
-
-    /**
-     * Validate Riak response
-     *
-     * @param string $response
-     * @param string $action
-     * @return bool
-     */
-    public function validateStatus($response, $action) {
-        $status = $this->getResponseStatus($response);
-
-        /**
-         * Check for Ok Status (200 = Ok)
-         */
-        if ($status != 200)
-            return $this->handleResponse($status, $action);
-
-        return true;
-    }
-
-    /**
-     * Handle Riak response
-     *
-     * @param string $status
-     * @param string $index
-     * @return bool
-     */
-    public function handleResponse($status, $index) {
-        /**
-         * Check for OK status(200)
-         */
-        if ($status != 200) {
-            /**
-             * Check for normal status codes
-             */
-            if (!in_array($status, $this->normalCodes[$index])) {
-                /**
-                 * Check for error codes
-                 */
-                if (in_array($status, $this->errorCodes[$index])) {
-                    Yii::log($this->errorCodes[$index][$status], CLogger::LEVEL_ERROR, 'ext.riiak.transport.http.statusCodes.handleResponse');
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Get Riak response status code
-     *
-     * @param string $response
-     * @return string
-     */
-    public function getResponseStatus($response) {
-        return $response['headers']['http_code'];
-    }
-
-    /**
-     * Get expected status codes for Riak operation
-     *
-     * @param string $action
-     * @return array
-     */
-    public function getExpectedStatus($action = '') {
-        /**
-         * Check for action is exists in expectedStaus array or not.
-         */
-        if (!array_key_exists($action, $this->expectedStatus))
-            return array('200');
-
-        return $this->expectedStatus[$action];
-    }
-
-}