Skip to content

Commit b4901ae

Browse files
committed
Merge branch 'docs-no-docs'
2 parents 8b1b5e8 + 492ca0e commit b4901ae

File tree

2 files changed

+145
-29
lines changed

2 files changed

+145
-29
lines changed

src/PHPCouchDB/Database.php

Lines changed: 98 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -76,41 +76,17 @@ public function getAllDocs($options = []) : array
7676
// grab extra params
7777
$query = $options;
7878

79-
// set some defaults
80-
if (isset($query['include_docs']) && $query['include_docs'] == false) {
81-
// needs to be a string
82-
$query['include_docs'] = "false";
79+
// convert data and set some defaults
80+
if (isset($query['include_docs'])) {
81+
$query['include_docs'] = $this->boolToString($query['include_docs']);
8382
} else {
8483
// needs to be a string and this is our chosen default value
8584
$query['include_docs'] = "true";
8685
}
8786

8887
$response = $this->client->request("GET", $endpoint, ["query" => $query]);
89-
if ($response->getStatusCode() == 200) {
90-
// try to decode JSON
91-
if ($json_data = json_decode($response->getBody(), true)) {
92-
if (isset($json_data['rows'][0]['doc'])) {
93-
// we have some data - extract the docs to return
94-
$docs = [];
95-
foreach ($json_data["rows"] as $document) {
96-
$docs[] = new Document($this, $document["doc"]);
97-
}
98-
return $docs;
99-
} else {
100-
// no docs, just return some basic info
101-
$results = [];
102-
foreach ($json_data['rows'] as $document) {
103-
$row = [];
104-
$row['id'] = $document['id'];
105-
$row['rev'] = $document['value']['rev'];
106-
$results[] = $row;
107-
}
108-
return $results;
109-
}
110-
} else {
111-
throw new Exception\ServerException('JSON response not received or not understood');
112-
}
113-
}
88+
$data = $this->handleServerResponse($response);
89+
return $data;
11490
}
11591

11692
/**
@@ -187,4 +163,97 @@ public function getDocById($id) : Document
187163
}
188164
}
189165
}
166+
167+
public function getView($options = []) : array
168+
{
169+
// check we have ddoc and view name
170+
if (!isset($options['ddoc'])) {
171+
throw new Exception\ServerException(
172+
'ddoc is a required parameter for getView'
173+
);
174+
}
175+
if (!isset($options['view'])) {
176+
throw new Exception\ServerException(
177+
'view is a required parameter for getView'
178+
);
179+
}
180+
181+
$endpoint = "/" . $this->db_name . "/_design/" . $options['ddoc']
182+
. "/_view/" . $options['view'];
183+
184+
// grab extra params
185+
$query = [];
186+
foreach ($options as $key => $value) {
187+
// skip the values we need for the URL, pass the rest through
188+
if (!in_array($key, ["ddoc", "view"])) {
189+
$query[$key] = $value;
190+
}
191+
}
192+
193+
// convert data and set some defaults
194+
if (isset($query['include_docs'])) {
195+
$query['include_docs'] = $this->boolToString($query['include_docs']);
196+
} else {
197+
// needs to be a string and this is our chosen default value
198+
$query['include_docs'] = "false";
199+
}
200+
201+
if (isset($query['reduce'])) {
202+
$query['reduce'] = $this->boolToString($query['reduce']);
203+
} else {
204+
// needs to be a string and this is our chosen default value
205+
$query['reduce'] = "true";
206+
}
207+
208+
$response = $this->client->request("GET", $endpoint, ["query" => $query]);
209+
$data = $this->handleServerResponse($response);
210+
return $data;
211+
}
212+
213+
protected function handleServerResponse($response) : array
214+
{
215+
if ($response->getStatusCode() == 200) {
216+
// try to decode JSON
217+
if ($json_data = json_decode($response->getBody(), true)) {
218+
if (isset($json_data['rows'][0]['doc'])) {
219+
// we have some data - extract the docs to return
220+
$docs = [];
221+
foreach ($json_data['rows'] as $document) {
222+
$docs[] = new Document($this, $document["doc"]);
223+
}
224+
return $docs;
225+
} elseif (isset($json_data['rows'][0]['value']['rev'])) {
226+
// assume these are doc signposts
227+
$docs = [];
228+
foreach ($json_data['rows'] as $item) {
229+
$doc = [];
230+
$doc['id'] = $item['id'];
231+
$doc['rev'] = $item['value']['rev'];
232+
$docs[] = $doc;
233+
}
234+
return $docs;
235+
} else {
236+
// no docs, just return some basic info
237+
return $json_data["rows"];
238+
}
239+
} else {
240+
throw new Exception\ServerException('JSON response not received or not understood');
241+
}
242+
}
243+
}
244+
245+
/**
246+
* Convert truthy things to "true" and the rest to "false" because
247+
* Guzzle doesn't send booleans as words
248+
*
249+
* @param mixed $value The value to use
250+
* @return A string either "true" or "false"
251+
*/
252+
protected function boolToString($value) {
253+
if($value) {
254+
return "true";
255+
} else {
256+
return "false";
257+
}
258+
}
190259
}

tests/PHPCouchDB/DatabaseTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,51 @@ public function testAllDocsWithoutIncludeDocs() {
163163
$this->assertArrayHasKey('id', $docs[0]);
164164
$this->assertArrayHasKey('rev', $docs[0]);
165165
}
166+
167+
public function testView() {
168+
$view = '{"rows":[
169+
{"key":"2012","value":34028},
170+
{"key":"2013","value":33023},
171+
{"key":"2014","value":21324}
172+
]}';
173+
$view_response = new Response(200, [], $view);
174+
175+
$mock = new MockHandler([ $this->use_response, $view_response ]);
176+
177+
$handler = HandlerStack::create($mock);
178+
$client = new Client(['handler' => $handler]);
179+
180+
// userland code starts
181+
$server = new \PHPCouchDB\Server(["client" => $client]);
182+
$database = $server->useDB(["name" => "egdb"]);
183+
$docs = $database->getView(["ddoc" => "myview", "view" => "year", "group" => true]);
184+
185+
$this->assertInternalType('array', $docs);
186+
$this->assertEquals(3, count($docs));
187+
$this->assertInternalType('array', $docs[0]);
188+
}
189+
190+
public function testViewWithIncludeDocs() {
191+
$view = '{"total_rows":88375,"offset":0,"rows":[
192+
{"id":"27881d866ac53784daebdd4fd3036986","key":"2012","value":1,"doc":{"_id":"27881d866ac53784daebdd4fd3036986","_rev":"1-d3d95288556bb4875daa17ab81b21813","Retailer country":"Italy","Order method type":"Sales visit","Retailer type":"Warehouse Store","Product line":"Camping Equipment","Product type":"Lanterns","Product":"EverGlow Single","Year":"2012","Quarter":"Q1 2012","Revenue":"15130.95","Quantity":"447","Gross margin":"0.46706056"}},
193+
{"id":"27881d866ac53784daebdd4fd3037731","key":"2012","value":1,"doc":{"_id":"27881d866ac53784daebdd4fd3037731","_rev":"1-4ccc2e75f0328ac53b852684f303906f","Retailer country":"Italy","Order method type":"Sales visit","Retailer type":"Warehouse Store","Product line":"Personal Accessories","Product type":"Knives","Product":"Single Edge","Year":"2012","Quarter":"Q1 2012","Revenue":"37411.15","Quantity":"3115","Gross margin":"0.28726062"}},
194+
{"id":"27881d866ac53784daebdd4fd30378ed","key":"2012","value":1,"doc":{"_id":"27881d866ac53784daebdd4fd30378ed","_rev":"1-d10f91c4f214cc96bd7bf5d38943693f","Retailer country":"Italy","Order method type":"Sales visit","Retailer type":"Warehouse Store","Product line":"Personal Accessories","Product type":"Knives","Product":"Double Edge","Year":"2012","Quarter":"Q1 2012","Revenue":"9151.38","Quantity":"567","Gross margin":"0.29182156"}}
195+
]}';
196+
$view_response = new Response(200, [], $view);
197+
198+
$mock = new MockHandler([ $this->use_response, $view_response ]);
199+
200+
$handler = HandlerStack::create($mock);
201+
$client = new Client(['handler' => $handler]);
202+
203+
// userland code starts
204+
$server = new \PHPCouchDB\Server(["client" => $client]);
205+
$database = $server->useDB(["name" => "egdb"]);
206+
$docs = $database->getView(["ddoc" => "myview", "view" => "year", "reduce" => false, "limit" => 3, "include_docs" => true]);
207+
208+
$this->assertInternalType('array', $docs);
209+
$this->assertEquals(3, count($docs));
210+
$this->assertInstanceOf('PHPCouchDB\Document', $docs[0]);
211+
$this->assertObjectHasAttribute('Product type', $docs[0]);
212+
}
166213
}

0 commit comments

Comments
 (0)