DEV Community

jcfrane
jcfrane

Posted on

Laravel Queue: archiving PDF Files

I’ve been working with Laravel Queues lately and it is indeed a pleasant experience. If you are not yet familiar with Laravel Queue you can read more about it here.

Queues are typically used in tasks that require an intensive amount of resources. For example, generating a large CSV report might take a while to finish. You can delegate the task in a queue that runs as a background task (managed by Supervisor) and just give the users feedback over time. This way, end-users will not wait for a long time for the report to finish. Most, users will even think that your application might be crashing.

In one of my projects I need to create a Zip Archive of PDF Files for about hundreds of users. Generating PDF Files usually takes time and resource. As such, I do it via Queue. Each Job not only generates PDF File it also updates the Zip Archive.

GeneratePDFResult.php:

<?php

namespace App\Jobs;

use App\Models\Result;
use App\ResultCheckers\NISResultChecker;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
use PDF;
use ZipArchive;

// Supports local driver, for now.
class GeneratePDFResult implements ShouldQueue
{
    use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    private const CACHE_TTL = 31556926;
    public $tries = 1;
    public $result;

    public function __construct(Result $result)
    {
        $this->result = $result;
    }

    public function handle()
    {
        $payload = [
            'scores' => $this->result->scores,
            'details' => $this->result->details,
        ];

        $batchId = $this->batch()->id;
        $pdf = PDF::loadView('neuro_report', [ 'payload' => $payload ])->setPaper('legal', 'portrait');
        $fileName =  sprintf('%s %s %s.pdf',
            $payload['details']['exam_date'],
            $payload['details']['first_name'],
            $payload['details']['last_name'],
        );

        $pdfFilePath = '/results/' . $batchId . '/' . $fileName;
        Storage::disk('local')->put($pdfFilePath, $pdf->output());

        $this->updateZipArchive($batchId, $pdfFilePath, $fileName);
    }

    private function updateZipArchive($batchId, $pdfFilePath, $fileName)
    {
        $zip = new ZipArchive();
        $zipFilePath = Storage::disk('local')->path('/results/' . $this->batchId . '/' . $this->batchId . '.zip');
        $pdfLocalFilePath = Storage::disk('local')->path($pdfFilePath);

        if ($zip->open($zipFilePath, ZipArchive::CREATE) === TRUE) {
            $zip->addFromString($fileName, Storage::disk('local')->get($pdfFilePath));
            $zip->close();
        } else {
            logger('Failed opening zip file:' . $zipFilePath);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

As you’ve noticed, I used a 3rd party library called laravel-dompdf to generate PDF Files from HTML. I’ve used the ZipArchive class of PHP for creating and updating the Zip Archives. I’ve batched the jobs so that they are logically grouped and I can monitor them as a whole. Also you can notice how the Storage facade works perfectly with these two.

That’s it! I hope you learn something new that you can apply on your backend applications.

Originally posted at jcfrane.com

Discussion (0)