ترقيم الصفحات
صفحة واحدة، أو كل الصفحات، أو عنصر واحد في كل مرة، في كل قائمة مرقّمة الصفحات.
list وlistAll وiterate
لكل قائمة مرقّمة الصفحات ثلاثة توابع. يجلب list صفحة واحدة ويعيد OpenEmail\Result\Page. ويتبع listAll المؤشر عبر كل الصفحات ويعيد مصفوفة واحدة. ويمر iterate على الصفحات نفسها عنصرًا عنصرًا ويعيد Generator لا يجلب الصفحة التالية إلا حين تصل إليها. وتأخذ الثلاثة مرشِّحات القائمة وlimit: وcursor: وapiKey:.
$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;تتكرر الأسماء الثلاثة نفسها حيثما كان لمساحة أسماء أكثر من قائمة واحدة، وتُسمّى باسم القائمة التي تمر عليها: listEvents وlistAllEvents وiterateEvents على emails، وlistDeliveries وlistAllDeliveries وiterateDeliveries على webhooks، وهكذا.
OpenEmail\Result\Page
itemsarray- صفوف هذه الصفحة، مستخرجة من غلاف `data` في API، كل منها مصفوفة ترابطية. فارغة حين لا تحتوي الصفحة على شيء.
hasMorebool- ما إذا كانت تليها صفحة أخرى. وحين لا ترسل API الحقل `hasMore`، تكون القيمة true بالضبط حين يوجد `nextCursor`.
nextCursorstring or null- ما تمرّره مرة أخرى كـ `cursor:` للحصول على الصفحة التالية، وnull في الصفحة الأخيرة.
الصفحة غير قابلة للتغيير: خصائصها readonly. وهي أيضًا IteratorAggregate وCountable، فيمر foreach ($page as $item) على صفوفها ويعدّها count($page).
Generator
لا يطلب iterate شيئًا حتى تبدأ المرور عليه، ولا يطلب الصفحة التالية إلا بعد تسليم كل عناصر الصفحة الحالية، فأي شيء يتوقف مبكرًا يوقف الطلبات أيضًا: ينهي break المرور، وكذلك الخروج من الدالة التي تحتوي الحلقة.
$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;أي شيء يحتاج إلى كل العناصر، مثل iterator_to_array() مستدعًى على الـ Generator، يقرأ كل الصفحات قبل أن يعود، كما يفعل listAll.
لا يمكن المرور على الـ Generator إلا مرة واحدة. فالمرور عليه مرة ثانية يرمي استثناءً، لذا استدعِ iterate من جديد حين تحتاج إلى العناصر مرة أخرى، أو احتفظ بالعناصر بدل الـ Generator.
الاستئناف من مؤشر
المؤشر غير شفاف. احتفظ بـ nextCursor الخاص بآخر صفحة قرأتها ومرّره مرة أخرى كـ cursor: لتواصل من هناك، في طلب لاحق أو في عملية أخرى. ويأخذ listAll وiterate أيضًا cursor:، ويبدآن مرورهما بعده.
$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 فتكون عناصر الصفحات السابقة قد سُلّمت بالفعل عندئذ، فاجعل ما تفعله الحلقة آمنًا إذا نُفّذ مرتين، أو رقّم الصفحات باستخدام list واحتفظ بكل nextCursor كي تبدأ المحاولة الثانية من حيث توقفت الأولى.
المحادثات والمسودات
يرقّم threads->list وdrafts->list، ومعهما listAll وiterate الخاصان بهما، الصفحات باستخدام pageToken وnextPageToken في API بدل المؤشر. ويخفي العميل هذا الفرق: مرّر الرمز كـ cursor: واقرأه من nextCursor.
$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 فيما يتبيّن أنه الصفحة الأخيرة، ثم لا يعيد الاستدعاء التالي أي عناصر.
صفحات تحمل المزيد
تجيب بعض القوائم بأكثر من الصفوف، فتعيد كائنًا خاصًا بها من OpenEmail\Result بدل Page. وكل منها غير قابل للتغيير، وIteratorAggregate على صفوفه، وCountable.
| الطريقة | ما يعيده | ما يضيفه |
|---|---|---|
| addresses->list | AddressBookPage | addresses بدل items، إضافة إلى unrestricted وdomains، مع hasMore وnextCursor. |
| addresses->listAll | AddressBook | كل العناوين في addresses، مع unrestricted وdomains كما أبلغت عنهما الصفحة الأخيرة. وهو listAll الوحيد الذي يعيد دفتر العناوين كاملًا بدل مصفوفة. ويمرّر addresses->iterate العناوين وحدها. |
| contacts->listPeople | PeoplePage | seen، وقيمته false حين لا يستطيع المفتاح قراءة العناوين التي ظهرت في البريد. ويعيد listAllPeople وiteratePeople الأشخاص وحدهم. |
| tempMail->listMessages | TempMessagesPage | expiresAt، أي متى تنتهي صلاحية الصندوق. ويعيد listAllMessages وiterateMessages الرسائل وحدها. |
| templates->listSends | TemplateSends | مرقّمة بالأرقام لا بالمؤشر: items وtotal وpage وpageSize. اطلب الصفحة التالية عبر page:. |
| emails->sendBatch | BatchResult | ليست صفحة: items، عنصر لكل رسالة أرسلتها، مع العددين sent وfailed. |
قوائم تعيد مصفوفة API
بعض القوائم ترقّم الصفحات بالإزاحة، أو برقم الصفحة، أو بمؤشر رقمي خاص بها، وتعيد المتن بعد فك ترميزه كما جاء، أي مصفوفة فيها data، بدل Page. ليس لها listAll ولا iterate، فترقّم صفحاتها بنفسك.
| الطريقة | ترقّم الصفحات بـ | ما يعود |
|---|---|---|
| exports->list | limit: وoffset: | data وtotal وhasMore. |
| imports->listFailures | after: وlimit: | data، وnextCursor، وهو عدد صحيح تمرّره مرة أخرى كـ after: وقيمته null في الصفحة الأخيرة. |
| subscriptions->list وsubscriptions->listDomains | limit: وoffset: | data وtotal وcounts وhasMore. |
| billing->listInvoices | page: وlimit: | data وtotal وpage وlimit وhasMore وmetered. |
$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، تعيد صفوفها مباشرة في قائمة بسيطة.