Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated CouchDB datasource for CakePHP 2.0 #28

Open
wants to merge 8 commits into
base: 2.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,36 @@
* @since CakePHP Datasources v 0.3
* @license MIT License (http://www.opensource.org/licenses/mit-license.php)
*/
App::import('Core', 'HttpSocket');
App::uses('HttpSocket', 'Network/Http');
App::uses('DataSource', 'Model/Datasource');

/**
* CouchDB Datasource
*
* @package datasources
* @subpackage datasources.models.datasources
*/
class CouchdbSource extends DataSource {
class CouchDBSource extends DataSource {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that necessary - Perhaps add a todo to rename the class which we can do at the next major release (rather than force this update to be further delayed until after the next major release)


/**
* Constructor
* Start quote
*
* @var string
*/
public $startQuote = null;

/**
* End quote
*
* @var string
*/
public $endQuote = null;

/**
* Constructor.
*
* @param array $config Connection setup for CouchDB.
* @param integer $autoConnect Autoconnect
* @param integer $autoConnect Autoconnect.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of these punctuation changes are not required.

If it's not a sentence (@return boolean Success is not a sentence) it doesn't need a ".".

* @return boolean
*/
public function __construct($config = null, $autoConnect = true) {
Expand All @@ -51,10 +66,10 @@ public function __construct($config = null, $autoConnect = true) {
}

/**
* Reconnects to the database with optional new settings
* Reconnects to the database with optional new settings.
*
* @param array $config New settings
* @return boolean Success
* @param array $config New settings.
* @return boolean Success.
*/
public function reconnect($config = null) {
$this->disconnect();
Expand All @@ -64,9 +79,9 @@ public function reconnect($config = null) {
}

/**
* Connects to the database. Options are specified in the $config instance variable
* Connects to the database. Options are specified in the $config instance variable.
*
* @return boolean Connected
* @return boolean Connected.
*/
public function connect() {
if ($this->connected !== true) {
Expand All @@ -76,12 +91,12 @@ public function connect() {
if (isset($this->config['password']))
$this->config['request']['uri']['pass'] = $this->config['password'];

$this->Socket = new HttpSocket($this->config);
if (strpos($this->Socket->get(), 'couchdb') !== false) {
try {
$this->Socket = new HttpSocket($this->config);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is put in a protected method, _getSocket, testing the datasources doesn't require a connection for all tests.

$this->Socket->get();
$this->connected = true;
} else {
trigger_error(__('CouchDB Error: connection failed ', true), E_USER_WARNING);
return $this->cakeError('missingConnection', array(array('code' => 500, 'className' => 'CouchdbSource')));
} catch (SocketException $e) {
throw new MissingConnectionException(array('class' => $e->getMessage()));
}
}
return $this->connected;
Expand All @@ -92,7 +107,7 @@ public function connect() {
* connection is closed, and if DEBUG is turned on (equal to 2) displays the
* log of stored data.
*
* @return boolean Disconnected
* @return boolean Disconnected.
*/
public function close() {
if (Configure::read('debug') > 1) {
Expand All @@ -102,9 +117,9 @@ public function close() {
}

/**
* Disconnect from the database
* Disconnect from the database.
*
* @return boolean Disconnected
* @return boolean Disconnected.
*/
public function disconnect() {
if (isset($this->results) && is_resource($this->results)) {
Expand All @@ -115,19 +130,20 @@ public function disconnect() {
}

/**
* List of databases
* List of databases.
*
* @return array Databases
* @return array Databases.
*/
public function listSources() {
return $this->__decode($this->Socket->get($this->__uri('_all_dbs')), true);
$databases = $this->__decode($this->Socket->get($this->__uri('_all_dbs')), true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a noop change

return $databases;
}

/**
* Convenience method for DboSource::listSources().
* Returns the names of databases in lowercase.
*
* @return array Lowercase databases
* @return array Lowercase databases.
*/
public function sources($reset = false) {
if ($reset === true) {
Expand All @@ -137,10 +153,10 @@ public function sources($reset = false) {
}

/**
* Returns a description of the model (metadata)
* Returns a description of the model (metadata).
*
* @param Model $model
* @return array
* @return array Schema.
*/
public function describe($model) {
return $model->schema;
Expand All @@ -149,12 +165,12 @@ public function describe($model) {
/**
* Creates a new document in the database.
* If the primaryKey is declared, creates the document with the specified ID.
* To create a new database: $this->__decode($this->Socket->put($this->__uri('databaseName')));
* To create a new database: $this->Model->curlPut('databaseName');
*
* @param Model $model
* @param array $fields An array of field names to insert. If null, $model->data will be used to generate the field names.
* @param array $values An array with key values of the fields. If null, $model->data will be used to generate the field names.
* @return boolean Success
* @return boolean Success.
*/
public function create($model, $fields = null, $values = null) {
$data = $model->data;
Expand Down Expand Up @@ -183,7 +199,7 @@ public function create($model, $fields = null, $values = null) {
* Reads data from a document.
*
* @param Model $model
* @param array $queryData An array of information containing $queryData keys, similar to Model::find()
* @param array $queryData An array of information containing $queryData keys, similar to Model::find().
* @param integer $recursive Level number of associations.
* @return mixed False if an error occurred, otherwise an array of results.
*/
Expand Down Expand Up @@ -224,7 +240,7 @@ public function read($model, $queryData = array(), $recursive = null) {
* Applies the rules to the document read.
*
* @param Model $model
* @param array $queryData An array of information containing $queryData keys, similar to Model::find()
* @param array $queryData An array of information containing $queryData keys, similar to Model::find().
* @param array $result Data read from the document.
* @return mixed False if an error occurred, otherwise an array of results.
*/
Expand Down Expand Up @@ -269,7 +285,7 @@ private function __readResult($model, $queryData, $result) {
* @param array $fields
* @param array $values
* @param mixed $conditions
* @return boolean Success
* @return boolean Success.
*/
public function update($model, $fields = null, $values = null, $conditions = null) {
$data = $model->data[$model->alias];
Expand Down Expand Up @@ -307,21 +323,36 @@ private function __idRevData(&$model, &$data) {
unset($data['rev']);
} else if ($model->rev) {
$data['_rev'] = $model->rev;
} else {
$data['_rev'] = $this->__lastRevision($model, $model->id);
}
}

/**
* Generates and executes a DELETE statement
* The method searches for the latest revision of a document
*
* @param object $model
* @param int $id
* @return string Last revision of the document
*/
private function __lastRevision(&$model, $id) {
$result = $this->__decode($this->Socket->get($this->__uri($model, $id)));
return $result->_rev;
}

/**
* Generates and executes a DELETE statement.
*
* @param Model $model
* @param mixed $conditions
* @return boolean Success
* @return boolean Success.
*/
public function delete($model, $conditions = null) {
$id = $model->id;
$rev = $model->rev;

if (!empty($id) && !empty($rev)) {
if (!empty($id)) {
if (empty($rev)) $rev = $this->__lastRevision($model, $id);
$id_rev = $id . '/?rev=' . $rev;
$result = $this->__decode($this->Socket->delete($this->__uri($model, $id_rev)));
return $this->__checkOk($result);
Expand All @@ -330,23 +361,37 @@ public function delete($model, $conditions = null) {
}

/**
* Returns an instruction to count data. (SQL, i.e. COUNT() or MAX())
* Returns an instruction to count data. (SQL, i.e. COUNT() or MAX()).
*
* @param model $model
* @param string $func Lowercase name of SQL function, i.e. 'count' or 'max'
* @param array $params Function parameters (any values must be quoted manually)
* @return string An SQL calculation function
* @param string $func Lowercase name of SQL function, i.e. 'count' or 'max'.
* @param array $params Function parameters (any values must be quoted manually).
* @return string An SQL calculation function.
*/
public function calculate($model, $func, $params = array()) {
return true;
}

/**
* Gets full table name including prefix
* Returns an object to represent a database expression in a query. Expression objects
* are not sanitized or escaped.
*
* @param string $expression An arbitrary expression to be inserted into a query.
* @return stdClass An object representing a database expression to be used in a query
*/
public function expression($expression) {
$obj = new stdClass();
$obj->type = 'expression';
$obj->value = $expression;
return $obj;
}

/**
* Gets full table name including prefix.
*
* @param mixed $model
* @param boolean $quote
* @return string Full name of table
* @return string Full name of table.
*/
public function fullTableName($model = null, $quote = true) {
$table = null;
Expand All @@ -361,22 +406,75 @@ public function fullTableName($model = null, $quote = true) {
}

/**
* Perform any function in CouchDB
* Perform any function in CouchDB.
* The first position of the $params array is used to mount the uri.
* The second place in the $params array is used to assemble data from a POST or PUT.
* The third parameter is used to decode the return json.
* The fourth parameter is used to build an associative array.
*
* The method can be performed by a Model of the following ways:
*
* $this->Model->curlGet('_all_dbs');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the model need to know that the command it is issuing is curl-based?

* $this->Model->curlPut('document_name');
* $this->Model->curlPost('document_name', array('field' => 'value'));
* $this->Model->curlDelete('document_name');
* $this->Model->curlPost('document_name', array('field' => 'value'), false);
* $this->Model->curlPost('document_name', array('field' => 'value'), true , false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These examples all look like standard CRUD operations - with the wrong method name (I mean they look logically equivalent to calling save/delete)

*
* @param string $uri
* @param array $post
* @param string $method
* @param array $params Parâmetros aceitos na ordem: uri, data, decode, assoc
* @return object
*/
public function query($uri, $post) {
return $this->__decode($this->Socket->post($uri, $this->__encode($post)));
public function query($method, $params) {
list($uri, $data, $decode, $assoc) = $this->__queryParams($params);

$request = array(
'method' => strtoupper(str_replace('curl', '', $method))
);

if (!empty($uri))
$request['uri'] = '/' . $uri;

if (!empty($data))
$request['body'] = $this->__encode($data);

$result = $this->Socket->request($request);

if ($decode === true) {
$result = $this->__decode($result, $assoc);
}

return $result;
}

/**
* Get a URI
* Construct the parameter of the query method.
*
* @param array $params
* @return array
*/
private function __queryParams($params) {
if (isset($params[0])) $uri = $params[0];
else $uri = '';

if (isset($params[1])) $data = $params[1];
else $data = array();

if (isset($params[2])) $decode = $params[2];
else $decode = true;

if (isset($params[3])) $assoc = $params[3];
else $assoc = true;

return array($uri, $data, $decode, $assoc);
}

/**
* Get a URI.
*
* @param mixed $model
* @param string $params
* @return string URI
* @return string URI.
*/
private function __uri($model = null, $params = null) {
if (!is_null($params)) {
Expand All @@ -386,17 +484,18 @@ private function __uri($model = null, $params = null) {
}

/**
* JSON encode
* JSON encode.
*
* @param string json $data
* @return string JSON
* @return string JSON.
*/
private function __encode($data) {
return json_encode($data);
}

/**
* JSON decode
* JSON decode.
*
* @param string json $data
* @param boolean $assoc If true, returns array. If false, returns object.
* @return mixed Object or Array.
Expand All @@ -406,7 +505,7 @@ private function __decode($data, $assoc = false) {
}

/**
* Checks if the result returned ok = true
* Checks if the result returned ok = true.
*
* @param object $object
* @return boolean
Expand All @@ -415,3 +514,4 @@ private function __checkOk($object = null) {
return isset($object->ok) && $object->ok === true;
}
}
?>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no new line at the end of this file

Loading