From 261468f9f0e9097714dc17ced13d2b9fa637e6c4 Mon Sep 17 00:00:00 2001 From: misterspelik Date: Mon, 13 Nov 2023 19:01:56 +0100 Subject: [PATCH] Fixes of installations for Laravel less than 8, fixes of tests and documentation improvements --- README.md | 29 ++++++++++++++---- composer.json | 6 ++-- .../Providers/PdfServiceProvider.php | 14 +++++++-- tests/PdfTest.php | 1 - tests/snapshots/exposify.pdf | Bin 45709 -> 35669 bytes 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b302fcf..0931072 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ To start using Laravel, add the Service Provider and the Facade to your `config/ ```php 'providers' => [ // ... - misterspelik\LaravelPdf\PdfServiceProvider::class + misterspelik\LaravelPdf\Providers\PdfServiceProvider::class ] ``` @@ -74,7 +74,7 @@ return [ 'subject' => 'This Document will explain the whole universe.', 'keywords' => 'PDF, Laravel, Package, Peace', // Separate values with comma 'creator' => 'Laravel Pdf', - 'display_mode' => 'fullpage' + 'display_mode' => 'fullpage', ]; ``` @@ -163,9 +163,8 @@ You can use your own styles in the generated PDFs. The css file have to be locat ```php return [ - ... - 'defaultCssFile' => base_path('public/css/pdf.css'), - ... + //... + 'defaultCssFile' => base_path('public/css/pdf.css'), ]; ``` @@ -180,18 +179,36 @@ There are a fews permissions: `'copy'`, `'print'`, `'modify'`, `'annot-forms'`, ```php use PDF; -function generate_pdf() { +function generate_pdf() +{ $data = [ 'foo' => 'bar' ]; $pdf = PDF::loadView('pdf.document', $data); $pdf->SetProtection(['copy', 'print'], '', 'pass'); + return $pdf->stream('document.pdf'); } ``` Find more information to `SetProtection()` here: https://mpdf.github.io/reference/mpdf-functions/setprotection.html +## PDF Wrapper extension + +This package has own wrapper for the Mpdf\Mpdf class. But it can be also overrided or extended on the project level. + +There is a setting in the config file to use a custom PdfWrapper. + +```php +return [ + // ... + 'pdfWrapper' => 'misterspelik\LaravelPdf\Wrapper\PdfWrapper', +]; +``` + +The only requirement that the wrapper must implement the interface +`misterspelik\LaravelPdf\PdfInterface\PdfWrapperInterface` + ## Testing To use the testing suite, you need some extensions and binaries for your local PHP. On macOS, you can install them like this: diff --git a/composer.json b/composer.json index 57cb647..a025f65 100755 --- a/composer.json +++ b/composer.json @@ -11,7 +11,9 @@ "ext-gd": "*", "ext-imagick": "*", "ext-mbstring": "*", - "misterspelik/mpdf": "^8.1.6" + "misterspelik/mpdf": "^8.1.6", + "psr/http-message": "^1.1 || ^2.0", + "psr/log": "^1.1.0 || ^2.0.0 || ^3.0.0" }, "require-dev": { "phpunit/phpunit": "^9.6.0", @@ -33,7 +35,7 @@ "extra": { "laravel": { "providers": [ - "misterspelik\\LaravelPdf\\PdfServiceProvider" + "misterspelik\\LaravelPdf\\Providers\\PdfServiceProvider" ], "aliases": { "PDF": "misterspelik\\LaravelPdf\\Facades\\Pdf" diff --git a/src/LaravelPdf/Providers/PdfServiceProvider.php b/src/LaravelPdf/Providers/PdfServiceProvider.php index 30ed79e..8e67be3 100644 --- a/src/LaravelPdf/Providers/PdfServiceProvider.php +++ b/src/LaravelPdf/Providers/PdfServiceProvider.php @@ -4,7 +4,7 @@ use Illuminate\Support\ServiceProvider; use misterspelik\LaravelPdf\LaravelPdfFactory; -use misterspelik\LaravelPdf\Wrapper\PdfWrapper; +use misterspelik\LaravelPdf\Wrapper\PdfWrapperInterface; class PdfServiceProvider extends ServiceProvider { @@ -56,8 +56,8 @@ public function register() __DIR__ . '/../../config/pdf.php', 'pdf' ); - $this->app->bind('mpdf.wrapper', function($app) { - return $this->factory->createPdfWrapper(); + $this->app->bind('mpdf.wrapper', function ($app) { + return $this->getPdfWrapper(); }); } @@ -72,4 +72,12 @@ public function provides() 'mpdf.pdf' ]; } + + /** + * @return \misterspelik\LaravelPdf\Wrapper\PdfWrapperInterface + */ + protected function getPdfWrapper(): PdfWrapperInterface + { + return $this->factory->createPdfWrapper(); + } } diff --git a/tests/PdfTest.php b/tests/PdfTest.php index c192b24..cbc64dd 100644 --- a/tests/PdfTest.php +++ b/tests/PdfTest.php @@ -40,7 +40,6 @@ protected function compareToSnapshot(string $snapshotId, $data): void // create snapshot if it doesn't exist if (!file_exists($snapshotFile)) { file_put_contents($snapshotFile, $data); - return; } $snapshot = file_get_contents($snapshotFile); diff --git a/tests/snapshots/exposify.pdf b/tests/snapshots/exposify.pdf index 1357644c60ef209e249da4314406a4897d96a227..a4555613539624a8c65198bb4211990bd06535db 100644 GIT binary patch delta 3767 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