递归调用,直到值不响应

时间:2015-06-18 13:09:45

标签: php curl recursion

我对此services/data/v28.0/query/?q=SELECT Id,Name,LastModifiedDate FROM Territory进行了cURL调用,响应如下:

{
  "totalSize": 6911,
  "done": false,
  "nextRecordsUrl": "/services/data/v28.0/query/01g8000002eI8dMAAS-2000",
  "records": [ ... ]
}

这意味着完整的记录集将有6911个项目但是在第一个请求时只返回第一个2000,现在如果我将cURL调用更改为此/services/data/v28.0/query/01g8000002eI8dMAAS-2000我将获得第一个2000个项目6911等等。

我应该递归cURL直到done = truenextRecordsUrlNULL或者在回复中不再存在,怎么样?我需要一些建议或伪代码来说明如何实现这一点,因为我有点被困。

这显示了我应该执行的完整的递归调用集(这可能是动态的,因此硬代码不起作用):

call: 
/services/data/v28.0/query/?q=SELECT Id,Name,LastModifiedDate FROM Territory

response:
{
  "totalSize": 6911,
  "done": false,
  "nextRecordsUrl": "/services/data/v28.0/query/01g8000002eI8dMAAS-2000",
  "records": [ ... ]
}

call: 
/services/data/v28.0/query/01g8000002eI8dMAAS-2000

response:
{
  "totalSize": 6911,
  "done": false,
  "nextRecordsUrl": "/services/data/v28.0/query/01g8000002eI8dMAAS-4000",
  "records": [ ... ]
}

call: 
/services/data/v28.0/query/01g8000002eI8dMAAS-4000

response:
{
  "totalSize": 6911,
  "done": false,
  "nextRecordsUrl": "/services/data/v28.0/query/01g8000002eI8dMAAS-6000",
  "records": [ ... ]
}

call: 
/services/data/v28.0/query/01g8000002eI8dMAAS-6000

response:
{
  "totalSize": 6911,
  "done": true,
  "records": [ ... ]
}

更新

我已经或多或少想出了如何实现这一点,但现在我的问题是如何合并递归每个响应的值。请参阅以下代码:

$soqlQuery2 = "SELECT Id,Name,LastModifiedDate FROM Territory";
$soqlUrl2 = $instanceUrl.'/services/data/v28.0/query/?q='.urlencode($soqlQuery2);

$curl = curl_init($soqlUrl2);

curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: OAuth $veevaToken"));

$jsonResponse = curl_exec($curl);

curl_close($curl);

$soqlObj2 = json_decode($jsonResponse, true);

$this->performPaginateSOQLQuery($veevaToken, $instanceUrl, $tokenUrl, $soqlObj2['nextRecordsUrl']);

$soqlObj2['done']$soqlObj2['nextRecordsUrl']上方,我将获得第二次和递归调用所需的值。所以,我建立了这个功能:

public function performPaginateSOQLQuery($veevaToken, $instanceUrl, $tokenUrl, $nextRecordsUrl)
{
    if (isset($nextRecordsUrl) && $nextRecordsUrl !== null && $nextRecordsUrl !== "") {
        $nextRecordsUrlSOQLQuery = $instanceUrl.$nextRecordsUrl;

        $curl = curl_init($nextRecordsUrlSOQLQuery);

        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: OAuth $veevaToken"));

        $jsonResponse = curl_exec($curl);

        $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        if ($status != 200) {
            $respObj['error'] = "Error: call to token URL $tokenUrl failed with status $status, response $jsonResponse, curl_error ".curl_error(
                    $curl
                ).", curl_errno ".curl_errno($curl);

            return $respObj;
        }

        curl_close($curl);

        $nextRecordsUrlObj = json_decode($jsonResponse, true);

        while ($nextRecordsUrlObj['done'] !== true) {
            $this->performPaginateSOQLQuery($veevaToken, $instanceUrl ,$tokenUrl, $nextRecordsUrlObj['nextRecordsUrl']);
        }

        return $nextRecordsUrlObj;
    }
}

但是我需要在$soqlObj2来电的每次迭代中合并整个$nextRecordsUrlObjperformPaginateSOQLQuery(),怎么样?有什么帮助吗?

更新2:第一次迭代时丢失值

我已将代码更新为:

public function performPaginateSOQLQuery(
    $veevaToken,
    $instanceUrl,
    $tokenUrl,
    &$nextRecordsUrl,
    &$dataToSave = array()
) {
    if (isset($nextRecordsUrl) && $nextRecordsUrl !== null && $nextRecordsUrl !== "") {
        $nextRecordsUrlSOQLQuery = $instanceUrl.$nextRecordsUrl;

        $curl = curl_init($nextRecordsUrlSOQLQuery);

        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: OAuth $veevaToken"));

        $jsonResponse = curl_exec($curl);

        $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        if ($status != 200) {
            $respObj['error'] = "Error: call to token URL $tokenUrl failed with status $status, response $jsonResponse, curl_error ".curl_error(
                    $curl
                ).", curl_errno ".curl_errno($curl);

            return $respObj;
        }

        curl_close($curl);

        $nextRecordsUrlObj = json_decode($jsonResponse, true);

        echo $nextRecordsUrlObj['nextRecordsUrl'] . "\n";
        print_r($nextRecordsUrlObj);

        $dataToSave[] = $nextRecordsUrlObj;

        $i = 0;
        while ($nextRecordsUrlObj['done'] !== true) {
            echo "time ".$i;
            $i++;
            $this->performPaginateSOQLQuery(
                $veevaToken,
                $instanceUrl,
                $tokenUrl,
                $nextRecordsUrlObj['nextRecordsUrl'],
                $dataToSave
            );
        }

        return array('url' => $nextRecordsUrlObj, 'data' => $dataToSave);
    }
}

但是在迭代time 1上我收到了这个错误:

[Symfony\Component\Debug\Exception\ContextErrorException]
  Notice: Undefined index: nextRecordsUrl

为什么?

1 个答案:

答案 0 :(得分:1)

您可以使用带有布尔变量的while循环。 一旦得到的响应是最后一个(done属性为true),则更改该布尔变量的值,并且循环应该停止。

<?php

//Assuming $response contains the response you're getting
//and that it's JSON-encoded.

$keepRequesting = true;
while($keepRequesting){

  //Your curl code over here
  // ...

  $response = json_decode($response);
  if($response->done == true) {
     $keepRequesting = false;
  }

}

关于您的更新: 虽然我不认为你应该使用递归方法来解决这个问题, 只需将要“保存”as a reference的数据添加到该函数中,然后使用array_merge即可。这样的事情:

public function performPaginateSOQLQuery($veevaToken, $instanceUrl, $tokenUrl, $nextRecordsUrl, &$dataToSave = array()) { //1 new parameters.
    //More code here...


    $nextRecordsUrlObj = json_decode($jsonResponse, true);
    $dataToSave[] = $nextRecordsUrlObj;
    while ($nextRecordsUrlObj['done'] !== true) {
        $this->performPaginateSOQLQuery($veevaToken, $instanceUrl ,$tokenUrl, $nextRecordsUrlObj['nextRecordsUrl'], $dataToSave);
    }

    return array('url' => $nextRecordsUrlObj, 'data' => $dataToSave);

问题是你应该退货,否则会丢失。 您必须稍微更改一下这个功能,以便返回您想要的URL和数据。

也许这篇文章可以帮到你: php recursion global variable?