递归函数,直到完成值为真,并将每个响应合并为一个大的响应

时间:2015-06-19 02:37:28

标签: php arrays json iteration

我有这个功能:

public function syncTerritoriesSOQLQuery($veevaToken, $instanceUrl, $tokenUrl)
{
    $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);

    $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);

    $soqlObj2 = json_decode($jsonResponse, true);

    return $soqlObj2;
}

当我打电话给我时,我收到了回复:

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

这意味着完整的记录集将包含6911个项目,但在第一个请求时,只有前2000个记录才会返回,因为它是分页的。所以我需要一次又一次地调用相同的代码直到"done": true。在每个新请求中,我需要通过在每次调用时附加值返回来更改$soqlUrl2。例如:

1st time:
$soqlUrl2 = $instanceUrl.'/services/data/v28.0/query/?q='.urlencode($soqlQuery2);

2nd time:
$soqlUrl2 = $instanceUrl."/services/data/v28.0/query/01g8000002eI8dMAAS-2000";    

3rd time:
$soqlUrl2 = $instanceUrl."/services/data/v28.0/query/01g8000002eI8dMAAS-4000";

...

直到done获得true回复。我还应该将每次迭代的整个JSON结果合并成一个大的,让我们说:第二次的结果应该与第一次调用的结果合并意味着$soqlObj2来自3d时间的结果应该与之前的伪合并-code:

merge($soqlObj2, 1st, 2nd, 3rd, ...)

我一直在研究这个功能:

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

        while($keepRequesting){
            $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);
            $dataToSave[] = $nextRecordsUrlObj;

            echo "iteration 2", "\n";
            echo "url: ", $nextRecordsUrl, "\n";
            echo "done: ";
            var_dump($nextRecordsUrlObj['done']);
            echo "\n";

            if($nextRecordsUrlObj['done'] === true) {
                $keepRequesting = false;
            }
        }

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

我从syncTerritoriesSOQLQuery()上面的函数中调用它,如下所示:

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

但是因为我得到了这个结果所以它不起作用:

iteration 0
url: /services/data/v28.0/query/01g8000002eYb8LAAS-2000
done: bool(false)

iteration 2
url: /services/data/v28.0/query/01g8000002eYb8LAAS-2000
done: bool(false)

iteration 2
url: /services/data/v28.0/query/01g8000002eYb8LAAS-2000
done: bool(false)

iteration 2
url: /services/data/v28.0/query/01g8000002eYb8LAAS-2000
done: bool(false)

iteration 2
url: /services/data/v28.0/query/01g8000002eYb8LAAS-2000
done: bool(false)

正确的输出应该是:

// 1st
url: /services/data/v28.0/query/01g8000002eYb8LAAS-2000
done: bool(false)

// 2st
url: /services/data/v28.0/query/01g8000002eYb8LAAS-4000
done: bool(false)

// 3rd
url: /services/data/v28.0/query/01g8000002eYb8LAAS-6000
done: bool(true)

因为totalSize是6911,有什么可以帮我修复我的代码吗?我的错误在哪里?

注意:我今天早些时候问this,但我根本不清楚,所以我打开了一个包含更多信息的新问题。

1 个答案:

答案 0 :(得分:1)

您的递归函数中应该有context.Background(),每次都应该使用$soqlObj2['nextRecordsUrl']进行更新。现在它只是检查第一页,因此你得到第二页的网址。

此外,我不明白为什么你在$nextRecordsUrl中有这么多代码,你只想迭代performPaginateSOQLQuery()直到syncTerritoriesSOQLQuery(),对吧?

<强>更新

更新done以循环显示所有页面。在我做出更改的地方添加了评论。希望有所帮助。

syncTerritoriesSOQLQuery()