문서로 건너뛰기
PHP

페이지네이션

페이지로 나뉘는 모든 목록에서, 한 페이지, 모든 페이지, 또는 한 번에 한 항목씩.

list, listAll, iterate

페이지로 나뉘는 모든 목록에는 세 가지 메서드가 있습니다. list는 한 페이지를 가져와 OpenEmail\Result\Page를 반환합니다. listAll은 커서를 따라 모든 페이지를 돌고 하나의 배열을 반환합니다. iterate는 같은 페이지를 한 항목씩 순회하며 Generator를 반환하는데, 이것은 다음 페이지에 도달했을 때에만 그 페이지를 가져옵니다. 세 메서드 모두 목록의 필터, limit:, cursor:, apiKey:를 받습니다.

three_ways.php
$page = $client->emails->list(status: 'failed', limit: 50); foreach ($page as $email) {    echo $email['id'], ' ', $email['lastError'] ?? '', PHP_EOL;} $failures = $client->emails->listAll(status: 'failed'); foreach ($client->emails->iterate(status: 'failed') as $email) {    echo $email['id'], PHP_EOL;} echo count($failures), ' ', $page->hasMore ? 'more to come' : 'that is all', PHP_EOL;

네임스페이스에 목록이 둘 이상 있으면, 순회하는 목록의 이름을 붙인 같은 세 이름이 반복됩니다: emails의 listEvents, listAllEvents, iterateEvents, webhooks의 listDeliveries, listAllDeliveries, iterateDeliveries 등입니다.

OpenEmail\Result\Page

itemsarray
이 페이지의 행들로, API의 `data` 봉투에서 꺼낸 것이며 각각 연관 배열입니다. 페이지에 아무것도 없으면 비어 있습니다.
hasMorebool
다음 페이지가 있는지 여부입니다. API가 `hasMore`를 보내지 않으면, `nextCursor`가 있을 때 정확히 true가 됩니다.
nextCursorstring or null
다음 페이지를 위해 `cursor:`로 다시 전달할 값이며, 마지막 페이지에서는 null입니다.

페이지는 불변이며 속성은 readonly입니다. IteratorAggregate이자 Countable이기도 하므로, foreach ($page as $item)로 행을 순회하고 count($page)로 개수를 셉니다.

Generator

iterate는 순회를 시작하기 전까지 아무것도 요청하지 않으며, 현재 페이지의 항목을 모두 yield한 뒤에야 다음 페이지를 요청하므로, 일찍 멈추는 것은 요청도 멈춥니다. break는 순회를 끝내며, 루프를 담은 함수에서 반환하는 것도 마찬가지입니다.

generator.php
$latest = []; foreach ($client->emails->iterate(status: 'failed', limit: 100) as $email) {    $latest[] = $email;     if (count($latest) === 10) {        break;    }} $invoice = null; foreach ($client->emails->iterate(status: 'failed') as $email) {    if (($email['tags']['invoice'] ?? null) === 'inv_2026_09_4192') {        $invoice = $email;         break;    }} echo count($latest), ' ', $invoice['id'] ?? 'not found', PHP_EOL;

Generator에 호출한 iterator_to_array()처럼 모든 항목이 필요한 것은 무엇이든, listAll처럼 반환하기 전에 모든 페이지를 읽습니다.

Generator는 한 번만 순회할 수 있습니다. 두 번째로 순회하면 예외가 던져지므로, 항목이 다시 필요하면 iterate를 다시 호출하거나 Generator가 아니라 항목을 보관하세요.

커서에서 이어 가기

커서는 불투명한 값입니다. 마지막으로 읽은 페이지의 nextCursor를 보관했다가 cursor:로 다시 전달하면, 나중의 요청이나 다른 프로세스에서도 거기서부터 이어 갈 수 있습니다. listAll과 iterate도 cursor:를 받으며, 그 뒤부터 순회를 시작합니다.

resume.php
$firstPage = $client->emails->list(status: 'failed', limit: 25);$saved = $firstPage->nextCursor; if ($saved !== null) {    $rest = $client->emails->listAll(status: 'failed', cursor: $saved);    echo count($rest), PHP_EOL;}

커서는 그것을 반환한 목록과 필터에 속하므로, 같은 필터와 함께 보내세요. 목록이 위치를 찾을 수 없는 커서는 invalid_cursor로 거부되며, 그때는 커서 없이 처음부터 다시 시작하면 됩니다.

limit:

limit:은 합계가 아니라 각 페이지의 크기입니다. list에서는 돌아오는 행의 수입니다. listAll과 iterate에서는 각 요청이 요구하는 수이므로, 값이 클수록 같은 행을 더 적은 왕복으로 가져옵니다. 목록마다 고유한 범위와 기본값이 있으며, 대개 1~100이고 보내지 않으면 25입니다. 범위를 벗어난 값은 잘라 맞추지 않고 거부됩니다. 각 목록의 레퍼런스에 그 범위가 적혀 있습니다.

순회가 멈추는 때

  • 페이지의 hasMore가 false일 때.
  • 페이지에 nextCursor가 없을 때. 더 있다고 하면서 커서를 알려 주지 않는 페이지는 영원히 반복될 것이기 때문입니다.
  • API가 이미 따라간 커서를 돌려줄 때. 같은 이유입니다.

각 페이지는 GET이므로, 예외가 던져지기 전에 다른 읽기처럼 개별적으로 재시도됩니다. 재시도 후에도 남은 실패는 listAll 밖으로 던져지며, 이미 가져온 항목은 버려집니다. iterate에서는 그때 이미 앞 페이지의 항목이 yield되었으므로, 루프가 하는 일을 두 번 실행해도 안전하게 만들거나, list로 페이지를 가져오며 각 nextCursor를 보관해 두 번째 시도가 첫 시도가 멈춘 곳에서 시작할 수 있게 하세요.

스레드와 초안

threads->list와 drafts->list, 그리고 각각의 listAll과 iterate는 커서가 아니라 API의 pageToken과 nextPageToken으로 페이지를 나눕니다. 클라이언트는 이 차이를 숨깁니다: 토큰을 cursor:로 전달하고 nextCursor에서 읽으세요.

page_token.php
$page = $client->threads->list(folder: 'inbox', limit: 50);$later = $page->hasMore ? $client->threads->list(folder: 'inbox', limit: 50, cursor: $page->nextCursor) : null; echo count($page), ' ', $later === null ? 0 : count($later), PHP_EOL;

서버는 페이지가 가득 찬 채 돌아올 때마다 토큰을 주므로, 결과적으로 마지막이었던 페이지에서도 hasMore가 true일 수 있으며, 그 경우 다음 호출은 항목을 반환하지 않습니다.

더 많은 것을 담은 페이지

몇몇 목록은 행 외의 정보도 함께 응답하며, Page 대신 OpenEmail\Result에 있는 자체 객체를 반환합니다. 각각 불변이며, 행에 대한 IteratorAggregate이자 Countable입니다.

메서드반환 내용추가되는 것
addresses->listAddressBookPageitems 대신 addresses, 그리고 unrestricted와 domains, hasMore와 nextCursor.
addresses->listAllAddressBookaddresses에 모든 주소가 담기고, unrestricted와 domains는 마지막 페이지가 보고한 값입니다. 배열이 아니라 주소록 전체를 반환하는 유일한 listAll입니다. addresses->iterate는 주소만 yield합니다.
contacts->listPeoplePeoplePageseen. 키가 메일에서 본 주소를 읽을 수 없으면 false입니다. listAllPeople과 iteratePeople은 사람만 반환합니다.
tempMail->listMessagesTempMessagesPageexpiresAt. 받은편지함이 만료되는 시각입니다. listAllMessages와 iterateMessages는 메시지만 반환합니다.
templates->listSendsTemplateSends커서가 아니라 번호로 페이지를 나눕니다: items, total, page, pageSize. 다음 페이지는 page:로 요청하세요.
emails->sendBatchBatchResult페이지가 아닙니다: 보낸 메시지마다 하나씩인 items와, sent 및 failed 건수입니다.

API의 배열을 반환하는 목록

일부 목록은 오프셋, 페이지 번호, 또는 자체 숫자 커서로 페이지를 나누며, Page가 아니라 받은 그대로의 디코딩된 본문, 즉 data를 가진 배열을 반환합니다. listAll이나 iterate가 없으므로 페이지 처리는 직접 하세요.

메서드페이지 방식반환되는 것
exports->listlimit:와 offset:data, total, hasMore.
imports->listFailuresafter:와 limit:data와 nextCursor. 이는 after:로 다시 전달할 정수이며, 마지막 페이지에서는 null입니다.
subscriptions->list와 subscriptions->listDomainslimit:와 offset:data, total, counts, hasMore.
billing->listInvoicespage:와 limit:data, total, page, limit, hasMore, metered.
offset_paging.php
$offset = 0; do {    $batch = $client->subscriptions->list(status: 'active', limit: 50, offset: $offset);     foreach ($batch['data'] as $row) {        echo $row['senderEmail'], ' ', $row['total'], PHP_EOL;    }     $offset += count($batch['data']);} while ($batch['hasMore'] && $batch['data'] !== []);

languages->list, labels->listColors, roles->listPermissions처럼 페이지로 나뉘지 않는 목록은 행을 곧바로 일반 리스트로 반환합니다.