Skip to content

Commit 2b35bb1

Browse files
committed
lib: introduce curl_multi
1 parent 146f0f5 commit 2b35bb1

File tree

3 files changed

+415
-55
lines changed

3 files changed

+415
-55
lines changed

README.md

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,27 @@ try {
4141
));
4242
}
4343

44-
$response = $qb->api('API_DoQuery', array(
45-
'dbid' => '*****',
46-
'clist' => '3.12',
47-
'options' => 'num-5'
44+
$results = $qb->api(array(
45+
array(
46+
'action' => 'API_DoQuery',
47+
'options' => array(
48+
'dbid' => '*****',
49+
'clist' => '3.12',
50+
'options' => 'num-5'
51+
)
52+
),
53+
array(
54+
'action' => 'API_DoQuery',
55+
'options' => array(
56+
'dbid' => '*****',
57+
'clist' => '3.12',
58+
'options' => 'num-5'
59+
)
60+
)
4861
));
4962

50-
var_dump($response['table']['records']);
63+
var_dump($results[0]); // First DoQuery
64+
var_dump($results[1]); // Second DoQuery
5165
}catch(\QuickBase\QuickBaseError $err){
5266
echo '('.$err->getCode().') '.$err->getMessage().'. '.$err->getDetails();
5367
}
@@ -59,11 +73,15 @@ Class
5973
```php
6074
class \QuickBase\QuickBase {
6175

62-
public cURL $ch;
76+
public cURL multi $mch;
77+
public array $chs;
6378

6479
private $defaults;
6580

6681
final public api($action[, $options = array()]);
82+
final public api($actions = array());
83+
84+
final public static genCH();
6785

6886
}
6987

@@ -102,8 +120,10 @@ class \QuickBase\QuickBaseQuery {
102120
final public addFlags();
103121
final public constructPayload();
104122
final public checkForAndHandleError();
123+
final public finalize();
124+
final public prepareCH();
125+
final public processCH();
105126
final public processOptions();
106-
final public transmit();
107127

108128
final public static arr2Obj(&$arr[, $return = false]);
109129
final public static arr2Xml($arr, &$xml);

quickbase.php

Lines changed: 117 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -49,42 +49,95 @@ class QuickBase {
4949
'responseAsObject' => false
5050
);
5151

52-
public $ch;
52+
public $mch;
53+
public $chs;
5354

5455
public function __construct($options = array()){
5556
$this->settings = array_replace_recursive($this->defaults, $options);
5657

57-
$this->ch = curl_init();
58-
59-
curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
60-
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
61-
curl_setopt($this->ch, CURLOPT_HEADER, true);
62-
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, true);
58+
$this->mch = curl_multi_init();
59+
$this->chs = array();
6360

6461
return $this;
6562
}
6663

6764
public function __destruct(){
68-
curl_close($this->ch);
65+
for($i = 0, $l = count($this->chs); $i < $l; ++$i){
66+
curl_close($this->chs[$i]);
67+
}
68+
69+
curl_multi_close($this->mch);
6970
}
7071

72+
// final public function api($actions = array()){
7173
final public function api($action, $options = array()){
72-
$query = new QuickBaseQuery($this, $action, $options);
73-
74-
$query
75-
->addFlags()
76-
->processOptions()
77-
->actionRequest()
78-
->constructPayload()
79-
->transmit()
80-
->checkForAndHandleError()
81-
->actionResponse();
82-
83-
if(isset($query->options['responseAsObject']) && $query->options['responseAsObject']){
84-
QuickBaseQuery::arr2Obj($query->response);
74+
if(!is_array($action)){
75+
$actions = array(
76+
array(
77+
'action' => $action,
78+
'options' => $options
79+
)
80+
);
81+
}else{
82+
$actions = $action;
83+
}
84+
85+
$nActions = count($actions);
86+
$queries = array();
87+
$results = array();
88+
89+
for($i = 0; $i < $nActions; ++$i){
90+
if(!isset($this->chs[$i])){
91+
$this->chs[] = self::genCH();
92+
}
93+
94+
$query = new QuickBaseQuery($this, $actions[$i]['action'], $actions[$i]['options']);
95+
96+
$query
97+
->addFlags()
98+
->processOptions()
99+
->actionRequest()
100+
->constructPayload()
101+
->prepareCH($this->chs[$i]);
102+
103+
curl_multi_add_handle($this->mch, $this->chs[$i]);
104+
105+
$queries[] = $query;
106+
}
107+
108+
do {
109+
curl_multi_exec($this->mch, $running);
110+
curl_multi_select($this->mch);
111+
}while($running > 0);
112+
113+
for($i = 0; $i < $nActions; ++$i){
114+
$queries[$i]
115+
->processCH()
116+
->checkForAndHandleError()
117+
->actionResponse()
118+
->finalize();
119+
120+
$results[] = $queries[$i]->response;
121+
122+
curl_multi_remove_handle($this->mch, $this->chs[$i]);
85123
}
86124

87-
return $query->response;
125+
if($nActions === 1){
126+
return $results[0];
127+
}
128+
129+
return $results;
130+
}
131+
132+
final public static function genCH(){
133+
$ch = curl_init();
134+
135+
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
136+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
137+
curl_setopt($ch, CURLOPT_HEADER, true);
138+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
139+
140+
return $ch;
88141
}
89142

90143
}
@@ -223,7 +276,9 @@ final public function checkForAndHandleError(){
223276

224277
return $this
225278
->constructPayload()
226-
->transmit();
279+
->prepareCH()
280+
->processCH()
281+
->checkForAndHandleError();
227282
}catch(Exception $newTicketErr){
228283
++$this->nErrors;
229284

@@ -241,24 +296,16 @@ final public function checkForAndHandleError(){
241296
return $this;
242297
}
243298

244-
final public function processOptions(){
245-
if(isset($this->options['fields'])){
246-
$this->options['field'] = $this->options['fields'];
247-
248-
unset($this->options['fields']);
249-
}
250-
251-
foreach($this->options as $key => $value){
252-
if(method_exists('\QuickBase\QuickBaseOption', $key)){
253-
$this->options[$key] = QuickBaseOption::{$key}($value);
254-
}
299+
final public function finalize(){
300+
if(isset($this->options['responseAsObject']) && $this->options['responseAsObject']){
301+
QuickBaseQuery::arr2Obj($this->response);
255302
}
256303

257304
return $this;
258305
}
259306

260-
final public function transmit(){
261-
curl_setopt($this->parent->ch, CURLOPT_URL, implode('', array(
307+
final public function prepareCH(&$ch){
308+
curl_setopt($ch, CURLOPT_URL, implode('', array(
262309
$this->settings['useSSL'] ? 'https://' : 'http://',
263310
$this->settings['realm'],
264311
'.',
@@ -270,11 +317,11 @@ final public function transmit(){
270317
$this->settings['flags']['useXML'] ? '' : $this->payload
271318
)));
272319

273-
curl_setopt($this->parent->ch, CURLOPT_PORT, $this->settings['useSSL'] ? 443 : 80);
320+
curl_setopt($ch, CURLOPT_PORT, $this->settings['useSSL'] ? 443 : 80);
274321

275322
if($this->settings['flags']['useXML']){
276-
curl_setopt($this->parent->ch, CURLOPT_POST, true);
277-
curl_setopt($this->parent->ch, CURLOPT_HTTPHEADER, array(
323+
curl_setopt($ch, CURLOPT_POST, true);
324+
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
278325
'POST /db/'.(isset($this->options['dbid']) ? $this->options['dbid'] : 'main').' HTTP/1.0',
279326
'Content-Type: text/xml;',
280327
'Accept: text/xml',
@@ -283,25 +330,31 @@ final public function transmit(){
283330
'Content-Length: '.strlen($this->payload),
284331
'QUICKBASE-ACTION: '.$this->action
285332
));
286-
curl_setopt($this->parent->ch, CURLOPT_POSTFIELDS, $this->payload);
333+
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->payload);
287334
}else{
288-
curl_setopt($this->parent->ch, CURLOPT_POST, false);
289-
curl_setopt($this->parent->ch, CURLOPT_HTTPHEADER, false);
290-
curl_setopt($this->parent->ch, CURLOPT_POSTFIELDS, false);
335+
curl_setopt($ch, CURLOPT_POST, false);
336+
curl_setopt($ch, CURLOPT_HTTPHEADER, false);
337+
curl_setopt($ch, CURLOPT_POSTFIELDS, false);
291338
}
292339

293-
$response = curl_exec($this->parent->ch);
340+
$this->ch = $ch;
294341

295-
$errno = curl_errno($this->parent->ch);
296-
$error = curl_error($this->parent->ch);
342+
return $this;
343+
}
344+
345+
final public function processCH(){
346+
$response = curl_multi_getcontent($this->ch);
347+
348+
$errno = curl_errno($this->ch);
349+
$error = curl_error($this->ch);
297350

298-
$headerSize = curl_getinfo($this->parent->ch, CURLINFO_HEADER_SIZE);
351+
$headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE);
299352

300353
if($response === false){
301354
++$this->nErrors;
302355

303356
if($this->nErrors <= $this->settings['maxErrorRetryAttempts']){
304-
return $this->transmit();
357+
return $this->prepareCH()->processCH();
305358
}
306359

307360
throw new QuickBaseError($errno, $error);
@@ -327,6 +380,22 @@ final public function transmit(){
327380
return $this;
328381
}
329382

383+
final public function processOptions(){
384+
if(isset($this->options['fields'])){
385+
$this->options['field'] = $this->options['fields'];
386+
387+
unset($this->options['fields']);
388+
}
389+
390+
foreach($this->options as $key => $value){
391+
if(method_exists('\QuickBase\QuickBaseOption', $key)){
392+
$this->options[$key] = QuickBaseOption::{$key}($value);
393+
}
394+
}
395+
396+
return $this;
397+
}
398+
330399
/* Helpers */
331400
final public static function arr2Obj(&$arr, $return = false){
332401
$obj = new \stdClass;

0 commit comments

Comments
 (0)