У меня есть вызов cURL этим services/data/v28.0/query/?q=SELECT Id,Name,LastModifiedDate FROM Territory
и ответ выглядит так:
{ "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 и так далее.
Я должен вызывать nextRecordsUrl
cURL до тех пор, пока done = true
или nextRecordsUrl
будет NULL
или больше не существует в ответе, как? Мне нужен совет или псевдокод, которые иллюстрируют мне, как добиться этого, так как я немного застрял.
Это показывает полный набор рекурсивных вызовов, которые я должен выполнить (это может быть динамическим, поэтому жесткий код не будет работать):
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
с $nextRecordsUrlObj
из каждой итерации в performPaginateSOQLQuery()
, как? Любая помощь?
ОБНОВЛЕНИЕ 2: Потеря значений на 1-й итерации
Я обновил свой код:
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
итерации time 1
я получаю эту ошибку:
[Symfony\Component\Debug\Exception\ContextErrorException] Notice: Undefined index: nextRecordsUrl
Почему это?
Вы можете использовать цикл 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; } }
в<?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; } }
Что касается вашего обновления: хотя я не думаю, что вы должны использовать рекурсивные методы для этой проблемы, просто добавьте данные, которые вы хотите сохранить в качестве ссылки на функцию, и используйте 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?