الاستخدام الإنتاجي لحزمة NextPDF الخاصة بـ Laravel
لمحة سريعة
قسم بعنوان «لمحة سريعة»في بيئة الإنتاج، حُلّ عقد المستند عبر حقن المُنشئ. عالِج حالات فشل كتابة PDF باستثناء محدد النوع. انقل التوليد الثقيل أو الدُفعي إلى GeneratePdfJob، واربط استدعاءات النجاح والفشل صراحةً.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/laravelphp artisan vendor:publish --tag=nextpdf-configهيّئ اتصال قائمة الانتظار في config/nextpdf.php. حدِّد queue.connection، وqueue.queue، وqueue.timeout. ثم تأكَّد من تشغيل عامل على الاتصال المُهيّأ.
نظرة مفاهيمية عامة
قسم بعنوان «نظرة مفاهيمية عامة»يُتيح الحاوي NextPDF\Contracts\PdfDocumentInterface على شكل ربط مصنع. تنتج كل عملية حلّ NextPDF\Core\Document جديدًا. يسمح PSR-11 للحاوي بإرجاع قيم مختلفة من استدعاءات get() المتتالية، بحسب استراتيجية الربط (PSR-11 §1.1.2). تستخدم هذه الحزمة ربط مصنع حتى لا تعبر الحالة المتغيرة محدودة النطاق بالطلب بين الطلبات أبدًا. سجلّا الخطوط والصور مفردان (singletons). يحفظ ذلك العقد الذي ينص على أن المعرِّف المربوط يُحلّ إلى مدخله المُسجَّل (PSR-11 §1.1.2)، مع الإبقاء على مشاركة الموارد المكلفة عبر العامل.
فضّل حقن المُنشئ على الواجهة (facade) في شِفرة الإنتاج. فهذا يجعل التبعية صريحة، ويُبقي وحدة التحكُّم قابلة لاختبار الوحدة دون تشغيل جذر الواجهة.
نموذج شِفرة — الإنتاج
قسم بعنوان «نموذج شِفرة — الإنتاج»وحدة تحكُّم مربوطة بحقن التبعيات مع معالجة أخطاء ذات أنواع محددة
قسم بعنوان «وحدة تحكُّم مربوطة بحقن التبعيات مع معالجة أخطاء ذات أنواع محددة»<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\Response;use NextPDF\Contracts\PdfDocumentInterface;use NextPDF\Laravel\Http\PdfResponse;use Psr\Log\LoggerInterface;use Throwable;
final class InvoiceController extends Controller{ public function __construct( private readonly PdfDocumentInterface $document, private readonly LoggerInterface $logger, ) {}
public function show(int $invoiceId): Response { try { $this->document->addPage(); $this->document->cell(0, 10, "Invoice #{$invoiceId}", newLine: true); $this->document->cell(0, 10, 'Thank you for your business.');
return PdfResponse::download( $this->document, "invoice-{$invoiceId}.pdf", ); } catch (Throwable $exception) { // Rethrow as an HTTP-meaningful failure; never swallow. $this->logger->error('Invoice PDF generation failed', [ 'invoice_id' => $invoiceId, 'exception' => $exception::class, ]);
return new Response('Could not generate the invoice PDF.', 500); } }}احقن PdfDocumentInterface، لا الصنف الملموس Document، حتى تتمكن من استبدال الربط في الاختبارات. يُرجع الحاوي مستندًا جديدًا لكل تهيئة لوحدة التحكُّم. لا تُعِد استخدام النسخة نفسها من وحدة التحكُّم لمستندين غير مرتبطين ضمن العملية الواحدة.
تُسجِّل كتلة الالتقاط صنف الاستثناء وتُرجع خطأ HTTP محددًا بدلًا من تسريب تتبُّع المكدس. استخدم Psr\Log\LoggerInterface، الذي يحلّه الحاوي إلى مُسجِّل إطار العمل. يترك PSR-3 تهريب النائب (placeholder escaping) للمُنفِّذ، ويوجّه المستدعين إلى عدم تهريب قيم السياق مسبقًا (PSR-3 §1.2). مرِّر سياقًا مُهيكلًا، لا سلاسل نصية مُدمَجة.
التوليد عبر قائمة الانتظار مع استدعاءات النجاح والفشل
قسم بعنوان «التوليد عبر قائمة الانتظار مع استدعاءات النجاح والفشل»GeneratePdfJob مهمة من نوع ShouldQueue. تستخدم افتراضيًا ثلاث محاولات، ومهلة قدرها 120 ثانية، وتراجعًا قدره 10 ثوانٍ. يمكنك تجاوز القيم الثلاث كلها في config/nextpdf.php. تتلقى مُغلِّفة (closure) البناء المستندَ المحلول من الحاوي، ويجب أن تُرجع مستندًا مُهيّأً.
<?php
declare(strict_types=1);
namespace App\Jobs;
use NextPDF\Contracts\PdfDocumentInterface;use NextPDF\Laravel\Jobs\GeneratePdfJob;use Psr\Log\LoggerInterface;use Throwable;
final class DispatchMonthlyStatement{ public function __construct(private readonly LoggerInterface $logger) {}
public function __invoke(int $accountId): void { // Dispatchable::dispatch() is `public static`: it constructs the // job from the arguments it receives and returns a PendingDispatch. // Pass every constructor argument — including the callbacks — to // the static call. Building an instance and then calling // `$job->dispatch(...)` would discard that instance (and its // callbacks) and queue a different job from only the static args. GeneratePdfJob::dispatch( storage_path("app/statements/{$accountId}.pdf"), static fn (PdfDocumentInterface $document): PdfDocumentInterface => $document ->addPage() ->cell(0, 10, "Statement for account {$accountId}", newLine: true), function (string $path) use ($accountId): void { $this->logger->info('Statement PDF written', [ 'account_id' => $accountId, 'path' => $path, ]); }, function (Throwable $exception) use ($accountId): void { $this->logger->error('Statement PDF failed', [ 'account_id' => $accountId, 'exception' => $exception::class, ]); }, ); }}يُمرِّر GeneratePdfJob::dispatch() وسائطه مباشرةً إلى المُنشئ (string $outputPath, callable $builder, ?callable $onSuccess, ?callable $onFailure). ونتيجةً لذلك، تُربط استدعاءات النجاح والفشل بالمهمة نفسها التي تُوضع في قائمة الانتظار. يطابق هذا الصيغة الموضعية GeneratePdfJob::dispatch($path, $builder) في /integrations/laravel/quickstart/. يتلقى استدعاء النجاح مسار الإخراج، ويتلقى استدعاء الفشل Throwable. تكشف المهمة أيضًا المُحدِّدَين الانسيابيَّين then() وcatch()، وهما يُرجعان المهمة للتسلسل. استخدم هذين المُحدِّدَين فقط عندما تحتفظ بالنسخة نفسها وتُرسلها، مثلًا عبر المساعِد dispatch(). تكشف المهمة أيضًا طريقة failed()، التي يستدعيها مُشغِّل قائمة الانتظار عند الفشل النهائي. تُغلَّف الاستدعاءات في مُغلِّفات قابلة للتسلسل (serializable) حتى تنجو من نقل قائمة الانتظار.
ضبط سلوك قائمة الانتظار
قسم بعنوان «ضبط سلوك قائمة الانتظار»| الخاصية | الافتراضي | مفتاح التهيئة |
|---|---|---|
tries | 3 | ليس مدفوعًا بالتهيئة؛ اشتقّ صنفًا فرعيًا للتغيير |
timeout | 120 | nextpdf.queue.timeout |
backoff | 10 | ليس مدفوعًا بالتهيئة؛ اشتقّ صنفًا فرعيًا للتغيير |
| اسم قائمة الانتظار | pdf | nextpdf.queue.queue |
| الاتصال | افتراضي | nextpdf.queue.connection |
tries وbackoff خاصيتان عامتان تُقرآن من نسخة المهمة. لا تقرأهما المهمة المُرسلة من التهيئة. إذا اختلفت سياسة إعادة المحاولة لديك، فاشتقّ صنفًا فرعيًا من GeneratePdfJob لتجاوزهما.
الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»- يجب أن تُرجع مُغلِّفة البناء كائنًا من نوع
PdfDocumentInterface. تحفظ المهمة قيمة الإرجاع هذه، لا النسخة التي حُلّت أصلًا. يؤكد اختبار المهمة هذا العقد صراحةً. - يُرجع حلّ
SignerInterfaceالقيمةnullما لم يكن التوقيع مُفعَّلًا وشهادة مُهيّأة وnextpdf/premiumمثبَّتة. تحقَّق دائمًا من القيمة null قبل التوقيع. - تتشارك العمّال طويلة العمر (Octane/RoadRunner/Swoole) سجلّ الخطوط المُقفَل. هيّئ
preload_fontsكي يجري الإحماء مرة واحدة عند إقلاع العامل بدلًا من أن يجري عند أول طلب. - تستدعي المهمة الفاشلة
failed()بعد استنفادtries. لا يستدعي فشل المحاولة الواحدةonFailureحتى يُعلن مُشغِّل قائمة الانتظار الفشل النهائي.
الأداء
قسم بعنوان «الأداء»يحجب التوليد المتزامن في وحدة التحكُّم الطلب طوال مدة بناء PDF بالكامل. للإخراج متعدد الصفحات أو الدُفعي، أرسِل GeneratePdfJob وارجع فورًا. توزِّع السجلّات المفردة تحليل الخطوط وفك ترميز الصور على مدى عمر العامل. تنحصر التكلفة لكل طلب عندئذٍ في بناء المستند وإصدار المحتوى.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»تُسجِّل وحدة التحكُّم المعتمِدة على حقن التبعيات صنف الاستثناء، لا رسالته أو تتبُّعه، لتجنُّب تسريب التفاصيل الداخلية إلى السجلّات. يتحقق GeneratePdfJob من مسار الإخراج على العامل للتخفيف من أثر الحمولات المُسلسَلة المُلاعَب بها على نقل قائمة الانتظار. التغطية الكاملة موجودة في /integrations/laravel/security-and-operations/.
المطابقة
قسم بعنوان «المطابقة»| الادعاء | المصدر | البند | reference_id |
|---|---|---|---|
| المعرِّف المربوط يُحلّ إلى مدخله المُسجَّل | PSR-11 Container | §1.1.2 | |
| قد تختلف عمليات الحلّ المتتالية بحسب استراتيجية الربط (ربط مصنع) | PSR-11 Container | §1.1.2 |
يَرِد توجيه التسجيل وفق PSR-3 في مواصفة PSR-3. يُسنِد ذلك التوجيه تهريب النائب إلى المُنفِّذ، ويوجّه المستدعين إلى تمرير سياق مُهيكل. انظر المستند psr_3_logger §1.2.
السياق التجاري
قسم بعنوان «السياق التجاري»يستخدم إخراج PAdES B-B الموقَّع وأرشفة PDF/A عبر nextpdf/premium سطح حقن التبعيات (DI) نفسه. هذه قدرة Enterprise اختيارية. لا تحتاج حزمة Core الموثَّقة هنا إلى أي تغيير في الشِفرة لاعتمادها. انظر https://nextpdf.dev/get-license/?intent=laravel-signing.
انظر أيضًا
قسم بعنوان «انظر أيضًا»- /integrations/laravel/quickstart/ — أبسط مثال أولي
- /integrations/laravel/configuration/ — مفاتيح قائمة الانتظار والتوقيع والخطوط
- /integrations/laravel/security-and-operations/ — نموذج التهديد والتقوية
- /integrations/laravel/troubleshooting/ — حالات فشل الإنتاج الشائعة