الاستخدام في الإنتاج مع CodeIgniter 4
لمحة سريعة
قسم بعنوان «لمحة سريعة»تتلقى متحكمات الإنتاج خدمات NextPDF المُجسَّدة. وهي تعالج تسلسل الاستثناءات المُوثَّق صراحةً وتُصدر إشارات قابلية الرصد. انقل أعمال إنشاء المستندات المحمولة (PDF) الطويلة الأمد خارج الطلب عبر CodeIgniter 4 Queue.
نظرة مفاهيمية عامة
قسم بعنوان «نظرة مفاهيمية عامة»يحلّ CodeIgniter 4 خدمات الحزمة عبر مُحدِّد المواقع الخاص به. في نمط مُحدِّد الخدمات، يتلقى الكائن حاوية ويستخدمها لاسترجاع تبعياته بنفسه. تنصح إرشادات توصية PHP المعيارية (PSR) بتجنّب هذا النمط (PSR-11 §1.3، الصيغة الوجوبية SHOULD NOT). لاتّباع هذه الإرشادات، حلّ كل خدمة من خدمات NextPDF مرة واحدة عند حدود المتحكم، ثم مرّر الكائن المُجسَّد إلى الداخل. لا تمرّر صنف Services أو أي حاوية إلى شيفرة المجال لديك.
يضع كل مثال PHP declare(strict_types=1); في سطر مستقل (PSR-12 §x1.x3.p34).
سطح واجهة برمجة التطبيقات
قسم بعنوان «سطح واجهة برمجة التطبيقات»| مهمة الإنتاج | السطح المُتحقَّق منه |
|---|---|
| حلّ الخدمات | Services::pdf(false)، Services::pdfDocument(false)، Services::documentFactory() |
| بناء الاستجابة | PdfResponse::download() / inline() → DownloadResponse |
| التقاط حالات الفشل | NextPDF\Exception\NextPdfException (النوع الأساسي للنظام البيئي) |
| التوليد غير المتزامن | GeneratePdfJob مُسجَّلة في Config\Queue::$jobHandlers |
| حواجز المسار / القابل للاستدعاء | GeneratePdfJob تُطلق InvalidArgumentException |
متحكم الإنتاج — معالجة الأخطاء وقابلية الرصد
قسم بعنوان «متحكم الإنتاج — معالجة الأخطاء وقابلية الرصد»يطلق محرّك النواة استثناءات تمتدّ جميعها من NextPDF\Exception\NextPdfException. التقط هذا النوع الواحد لتغطية حالات فشل النواة والامتدادات. تُسجّل كتلة الالتقاط هذه السياق وتُعيد استجابة خطأ مُحدَّدة، ولا تكون أبداً كتلة التقاط فارغة.
<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\DownloadResponse;use CodeIgniter\HTTP\ResponseInterface;use NextPDF\CodeIgniter\Config\Services;use NextPDF\Exception\NextPdfException;use Psr\Log\LoggerInterface;
final class InvoiceController extends BaseController{ public function download(int $id): DownloadResponse|ResponseInterface { /** @var LoggerInterface $logger */ $logger = \service('logger');
$start = \hrtime(true);
try { $pdf = Services::pdf(false); $pdf->document()->addPage(); $pdf->document()->cell(0, 10, "Invoice #{$id}");
$response = $pdf->download("invoice-{$id}.pdf");
$logger->info('pdf.invoice.generated', [ 'invoice_id' => $id, 'elapsed_ms' => (\hrtime(true) - $start) / 1_000_000, ]);
return $response; } catch (NextPdfException $e) { $logger->error('pdf.invoice.failed', [ 'invoice_id' => $id, 'exception' => $e::class, 'message' => $e->getMessage(), ]);
return $this->response ->setStatusCode(ResponseInterface::HTTP_INTERNAL_SERVER_ERROR) ->setJSON(['error' => 'pdf_generation_failed', 'invoice_id' => $id]); } }}تُعيد Services::pdf(false) مكتبة جديدة ومستنداً أساسياً جديداً في كل استدعاء. لا تتشارك الطلبات المتزامنة أبداً حالة المستند. تؤكّد الاختبارات الوظيفية للحزمة هذا السلوك.
أعمار الخدمات الآمنة للعامل
قسم بعنوان «أعمار الخدمات الآمنة للعامل»سجلّا الخطوط والصور كائنان أحاديّان بعمر العملية حسب التصميم. يُهيَّأ سجلّ الخطوط ويُقفَل مرة واحدة. أما سجلّ الصور فهو ذاكرة تخزين مؤقت محدودة من نوع الأقل استخداماً مؤخراً (LRU). في عامل طويل الأمد (خادم CodeIgniter spark، أو مشغِّل بأسلوب RoadRunner، أو عامل قائمة انتظار)، يكون هذا السلوك مقصوداً: تبقى السجلّات المكلفة، بينما يكون كل مستند جديداً. لا تطلب مستنداً مشتركاً (Services::pdfDocument(true)) في شيفرة الطلب أو المهمة؛ فهو موجود فقط لإعادة تعيين الاختبار، وسيتشارك المحتوى عبر الطلبات.
التوليد غير المتزامن باستخدام CodeIgniter Queue
قسم بعنوان «التوليد غير المتزامن باستخدام CodeIgniter Queue»تُشغِّل GeneratePdfJob توليد PDF خارج الطلب عبر codeigniter4/queue. يتطلب زمن تشغيل قائمة الانتظار إعدادَين. اضبطهما كليهما بشكل صحيح.
1. سجّل معالج المهمة بالاسم
قسم بعنوان «1. سجّل معالج المهمة بالاسم»تحلّ قائمة الانتظار المهمة عبر مفتاح اسم، لا عبر سلسلة صنف. يتحقق معالج قائمة الانتظار من اسم المهمة المدفوعة بمقارنته مع مفاتيح Config\Queue::$jobHandlers. وترفض الاسم غير المعروف عبر CodeIgniter\Queue\Exceptions\QueueException. سجّل المهمة في app/Config/Queue.php:
<?php
declare(strict_types=1);
namespace Config;
use CodeIgniter\Queue\Config\Queue as BaseQueue;use NextPDF\CodeIgniter\Jobs\GeneratePdfJob;
final class Queue extends BaseQueue{ /** @var array<string, class-string> */ public array $jobHandlers = [ 'generate-pdf' => GeneratePdfJob::class, ];}2. أرسل عبر الاسم المُسجَّل
قسم بعنوان «2. أرسل عبر الاسم المُسجَّل»ادفع المهمة مع الاسم المُسجَّل كوسيط ثانٍ. الوسيط الأول هو اسم قائمة الانتظار، والوسيط الثالث هو مصفوفة بيانات المهمة.
<?php
declare(strict_types=1);
namespace App\Controllers;
use CodeIgniter\HTTP\ResponseInterface;
final class InvoiceController extends BaseController{ public function queueInvoice(int $id): ResponseInterface { \service('queue')->push('pdf-queue', 'generate-pdf', [ 'builder' => 'App\\PdfBuilders\\InvoiceBuilder::build', 'outputPath' => WRITEPATH . 'pdfs/invoice-' . $id . '.pdf', 'context' => ['invoice_id' => $id], ]);
return $this->response ->setStatusCode(ResponseInterface::HTTP_ACCEPTED) ->setJSON(['status' => 'queued', 'invoice_id' => $id]); }}3. نفّذ الباني ضمن App\PdfBuilders
قسم بعنوان «3. نفّذ الباني ضمن App\PdfBuilders»تسمح المهمة بالبناة القابلين للاستدعاء فقط ضمن مساحة الأسماء App\PdfBuilders وتحصر مسارات الإخراج في WRITEPATH/pdfs/. نفّذ الباني كطريقة ساكنة. يتلقى Document جديداً ومصفوفة السياق، ثم يعيد المستند.
<?php
declare(strict_types=1);
namespace App\PdfBuilders;
use NextPDF\Core\Document;
final class InvoiceBuilder{ /** @param array<string, mixed> $context */ public static function build(Document $document, array $context): Document { $invoiceId = (int) ($context['invoice_id'] ?? 0);
$document->addPage(); $document->cell(0, 10, "Invoice #{$invoiceId}");
return $document; }}شغّل العامل
قسم بعنوان «شغّل العامل»php spark queue:work pdf-queueيبدأ كل تشغيل للمهمة بمستند جديد من Services::pdfDocument(). يطبّق الباني، ثم يحفظ في المسار المُتحقَّق منه. تتحقق اختبارات الحزمة من أن تشغيلَين متتاليين للمهمة لا يتشاركان حالة المستند.
الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»- ترفض قائمة الانتظار
GeneratePdfJob::classكاسم للمهمة عند الدفع لأنه ليس المفتاح المُسجَّل'generate-pdf'. ادفع دائماً مفتاحjobHandlers. - يجب أن تطابق سلسلة الباني
App\PdfBuilders\<Class>::<method>تماماً. الدوال، أو مساحات الأسماء الأخرى، أو الحمولات ذات البادئة أو اللاحقة تُطلقInvalidArgumentExceptionقبل تشغيل أي شيفرة. - يجب أن يُحلّ مسار الإخراج داخل
WRITEPATH/pdfs/وأن ينتهي بـ.pdf(غير حساس لحالة الأحرف). تُرفض مسارات الاجتياز والبادئة الشقيقة. codeigniter4/queueهي تبعية مخصصة للتطوير فقط للحزمة. اطلبها في التطبيق الذي يشغّل العمّال.
الأداء
قسم بعنوان «الأداء»تُنشأ السجلّات مرة واحدة لكل عملية عامل. تتناسب تكلفة بناء المستند مع المحتوى، لا مع المُحوِّل. للمهام الدُّفعية الكبيرة، استخدم مسار قائمة الانتظار حتى يبقى عمّال الطلبات سريعي الاستجابة. عيّن performance_budget في أي وصفة لها هدف قابل للقياس.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»مهمة قائمة الانتظار هي السطح الأعلى خطورة. عندما يكون الوسيط قابلاً للوصول، تكون حمولات قائمة الانتظار عرضة لتأثير المهاجم. تُغطّى قائمة السماح للقابل للاستدعاء وحصر المسار في /integrations/codeigniter/security-and-operations/ مع حالات الرفض المُتحقَّق منها.
المطابقة
قسم بعنوان «المطابقة»- تتلقى المتحكمات خدمات مُجسَّدة، لا حاوية، بما يتوافق مع إرشادات مُحدِّد الخدمات في PSR-11 §1.3.
السياق التجاري
قسم بعنوان «السياق التجاري»نواة NextPDF مرخّصة بموجب Apache-2.0. لإنتاج مخرجات مُوقَّعة ومخرجات PDF/A في مهام قائمة الانتظار، ثبّت NextPDF Pro أو Enterprise في بيئة العامل. تكشف حزمة CodeIgniter طرق الخدمة المقابلة. وتُعيد null إلى أن تُثبَّت حزمة Premium المطابقة. انظر </get-license/?intent=codeigniter-async-signing>.
انظر أيضاً
قسم بعنوان «انظر أيضاً»- /integrations/codeigniter/quickstart/ — النسخة المختصرة من هذه المتحكمات.
- /integrations/codeigniter/configuration/ — التوقيع، وسلطة الطوابع الزمنية (TSA)، وضبط المسار.
- /integrations/codeigniter/security-and-operations/ — نموذج تهديد قائمة الانتظار والتعزيز الأمني.
- /integrations/codeigniter/troubleshooting/ — أنماط فشل قائمة الانتظار والاكتشاف.
- /integrations/codeigniter/integration/ — مرجع التوصيل واختبار الدخان.