From 3406cf22f98a2d4c7c5b077cabb8ea8c3af77463 Mon Sep 17 00:00:00 2001 From: philipp lang Date: Fri, 16 Jul 2021 00:12:19 +0200 Subject: [PATCH] Add pdf generator --- .gitignore | 2 +- .gitmodules | 3 ++ app/Http/Views/MemberView.php | 6 +-- app/Pdf/BillType.php | 10 ++++ app/Pdf/MemberPdfController.php | 2 +- app/Pdf/PdfGenerator.php | 55 ++++++++++++++++---- app/Pdf/PdfRepository.php | 4 ++ config/app.php | 1 + config/filesystems.php | 5 ++ packages/silvaletter | 1 + resources/views/tex/bill.tex | 2 +- resources/views/tex/templates/default | 1 + routes/web.php | 3 +- storage/temp/.gitkeep | 0 tests/Feature/Pdf/GenerateTest.php | 74 ++++++++++++++++++--------- tests/Traits/FakesTex.php | 18 ------- 16 files changed, 129 insertions(+), 58 deletions(-) create mode 100644 .gitmodules create mode 160000 packages/silvaletter create mode 120000 resources/views/tex/templates/default create mode 100644 storage/temp/.gitkeep delete mode 100644 tests/Traits/FakesTex.php diff --git a/.gitignore b/.gitignore index f1b69ccb..880078a8 100644 --- a/.gitignore +++ b/.gitignore @@ -16,8 +16,8 @@ npm-debug.log yarn-error.log tags /resources/js/libs -/packages /public/vendor +/storage/temp # Temporary files *.swp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..b967b3d9 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "packages/silvaletter"] + path = packages/silvaletter + url = git@zoomyboy.de:silvaletter.git diff --git a/app/Http/Views/MemberView.php b/app/Http/Views/MemberView.php index e7913baa..69b391f5 100644 --- a/app/Http/Views/MemberView.php +++ b/app/Http/Views/MemberView.php @@ -2,12 +2,12 @@ namespace App\Http\Views; -use App\Member\MemberResource; use App\Member\Member; -use Illuminate\Http\Request; +use App\Member\MemberResource; +use App\Payment\PaymentResource; use App\Payment\Status; use App\Payment\Subscription; -use App\Payment\PaymentResource; +use Illuminate\Http\Request; class MemberView { public function index(Request $request) { diff --git a/app/Pdf/BillType.php b/app/Pdf/BillType.php index 1520f32e..8dc69efc 100644 --- a/app/Pdf/BillType.php +++ b/app/Pdf/BillType.php @@ -31,4 +31,14 @@ class BillType implements PdfRepository return $this->filename; } + public function getView(): string + { + return 'tex.bill'; + } + + public function getTemplate(): string + { + return 'default'; + } + } diff --git a/app/Pdf/MemberPdfController.php b/app/Pdf/MemberPdfController.php index c68a4382..8e9c0b24 100644 --- a/app/Pdf/MemberPdfController.php +++ b/app/Pdf/MemberPdfController.php @@ -15,7 +15,7 @@ class MemberPdfController extends Controller return $repo === null ? response()->noContent() - : app(PdfGenerator::class)->render($repo); + : app(PdfGenerator::class)->setRepository($repo)->render(); } } diff --git a/app/Pdf/PdfGenerator.php b/app/Pdf/PdfGenerator.php index d1e6417c..4e4aad22 100644 --- a/app/Pdf/PdfGenerator.php +++ b/app/Pdf/PdfGenerator.php @@ -3,29 +3,64 @@ namespace App\Pdf; use Illuminate\Contracts\Support\Responsable; +use Illuminate\Support\Str; use Storage; class PdfGenerator implements Responsable { private ?string $filename = null; + private PdfRepository $repo; + private string $dir; - public function render(PdfRepository $repo): self + public function setRepository(PdfRepository $repo): self { - $content = view()->make('pdf.pdf', [ - 'data' => $repo, + $this->repo = $repo; + + return $this; + } + + public function render(): self + { + $this->filename = $this->repo->getFilename(); + $this->dir = Str::random(32); + + Storage::disk('temp')->put($this->dir.'/'.$this->repo->getFilename().'.tex', $this->compileView()); + Storage::disk('temp')->makeDirectory($this->dir); + + $this->copyTemplateTo(Storage::disk('temp')->path($this->dir)); + + $command = 'cd '.Storage::disk('temp')->path($this->dir); + $command .= ' && '.env('XELATEX').' --halt-on-error '.$this->repo->getFilename().'.tex'; + exec($command, $output, $returnVar); + + return $this; + } + + public function compileView(): string + { + return (string) view()->make($this->repo->getView(), [ + 'data' => $this->repo, ]); - - $filename = $repo->getFilename(); - dd($filename); - - Storage::disk('temp')->put($repo->getBasename(), $content); } public function toResponse($request) { - return response()->file($this->filename); + return response()->file($this->getCompiledFilename(), [ + 'Content-Type' => 'application/pdf', + 'Content-Disposition' => "inline; filename=\"{$this->filename}.pdf\"", + ]); + } + + public function getCompiledFilename(): string + { + return Storage::disk('temp')->path($this->dir.'/'.$this->filename.'.pdf'); + } + + private function copyTemplateTo(string $destination): void + { + $templatePath = resource_path("views/tex/templates/{$this->repo->getTemplate()}"); + exec('cp '.$templatePath.'/* '.$destination); } } - diff --git a/app/Pdf/PdfRepository.php b/app/Pdf/PdfRepository.php index 392c1ee8..b9e2e3e4 100644 --- a/app/Pdf/PdfRepository.php +++ b/app/Pdf/PdfRepository.php @@ -13,4 +13,8 @@ interface PdfRepository public function getFilename(): string; + public function getView(): string; + + public function getTemplate(): string; + } diff --git a/config/app.php b/config/app.php index 95245838..3b7bb52b 100644 --- a/config/app.php +++ b/config/app.php @@ -176,6 +176,7 @@ return [ App\Providers\HorizonServiceProvider::class, App\Providers\RouteServiceProvider::class, App\Providers\TelescopeServiceProvider::class, + App\Tex\TexServiceProvider::class, ], diff --git a/config/filesystems.php b/config/filesystems.php index 94c81126..ae136ed9 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -48,6 +48,11 @@ return [ 'root' => storage_path('app'), ], + 'temp' => [ + 'driver' => 'local', + 'root' => storage_path('temp'), + ], + 'public' => [ 'driver' => 'local', 'root' => storage_path('app/public'), diff --git a/packages/silvaletter b/packages/silvaletter new file mode 160000 index 00000000..63fb0c9d --- /dev/null +++ b/packages/silvaletter @@ -0,0 +1 @@ +Subproject commit 63fb0c9daed5648bc2bf06a0361d95cd586db17f diff --git a/resources/views/tex/bill.tex b/resources/views/tex/bill.tex index 32ed8686..ebf2e6a9 100644 --- a/resources/views/tex/bill.tex +++ b/resources/views/tex/bill.tex @@ -1,6 +1,6 @@ \documentclass[silvaletter,12pt]{scrlttr2} -\setkomavar{subject}{<-- $subject -->} +\setkomavar{subject}{Rechnung} \begin{document} \begin{letter}{Familie Charnay\\Junkerstr 4\\42699 Solingen} diff --git a/resources/views/tex/templates/default b/resources/views/tex/templates/default new file mode 120000 index 00000000..7e888992 --- /dev/null +++ b/resources/views/tex/templates/default @@ -0,0 +1 @@ +../../../../packages/silvaletter/template \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index 71494856..abebd687 100644 --- a/routes/web.php +++ b/routes/web.php @@ -21,6 +21,7 @@ Route::group(['middleware' => 'auth:web'], function () { Route::resource('allpayment', AllpaymentController::class); Route::resource('subscription', SubscriptionController::class); Route::post('/member/{member}/confirm', MemberConfirmController::class); - Route::post('/member/{member}/pdf', MemberPdfController::class)->name('member.singlepdf'); + Route::get('/member/{member}/pdf', MemberPdfController::class) + ->name('member.singlepdf'); }); diff --git a/storage/temp/.gitkeep b/storage/temp/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/Feature/Pdf/GenerateTest.php b/tests/Feature/Pdf/GenerateTest.php index 24c924cd..b0a9f69b 100644 --- a/tests/Feature/Pdf/GenerateTest.php +++ b/tests/Feature/Pdf/GenerateTest.php @@ -10,6 +10,8 @@ use App\Nationality; use App\Payment\Payment; use App\Payment\Subscription; use App\Pdf\BillType; +use App\Pdf\PdfGenerator; +use App\Pdf\PdfRepositoryFactory; use Database\Factories\Member\MemberFactory; use Database\Factories\Payment\PaymentFactory; use Illuminate\Foundation\Testing\RefreshDatabase; @@ -22,13 +24,11 @@ class GenerateTest extends TestCase { use RefreshDatabase; - use FakesTex; public function setUp(): void { parent::setUp(); - $this->fakeTex(); Storage::fake('temp'); } @@ -63,7 +63,7 @@ class GenerateTest extends TestCase 'type' => BillType::class, 'filename' => 'rechnung-fur-firstname-lastname.pdf', 'output' => [ - '12,00 €', + '12.00', 'Familie ::lastname::', ], ], @@ -80,8 +80,55 @@ class GenerateTest extends TestCase ): void { $this->withoutExceptionHandling(); $this->login(); + $members = $this->setupMembers($members); - $members = collect($members)->map(function (array $member): Member { + $urlId = call_user_func($urlCallable, $members); + $response = $this->call('GET', "/member/{$urlId}/pdf", [ + 'type' => $type, + ]); + + if ($filename === null) { + $response->assertStatus(204); + + return; + } + + $this->assertEquals('application/pdf', $response->headers->get('content-type')); + $this->assertEquals('inline; filename="' . $filename . '"', $response->headers->get('content-disposition')); + } + + /** @dataProvider generatorProvider */ + public function testItGeneratesTheLayout( + array $members, + callable $urlCallable, + string $type, + ?string $filename = null, + ?array $output = null + ): void { + $this->withoutExceptionHandling(); + $this->login(); + $members = $this->setupMembers($members); + + $urlId = call_user_func($urlCallable, $members); + $member = Member::find($urlId); + $repo = app(PdfRepositoryFactory::class)->fromSingleRequest($type, $member); + + if ($filename === null) { + $this->assertNull($repo); + + return; + } + + $content = app(PdfGenerator::class)->setRepository($repo)->compileView(); + + foreach ($output as $out) { + $this->assertStringContainsString($out, $content); + } + } + + private function setupMembers(array $members): Collection + { + return collect($members)->map(function (array $member): Member { $memberFactory = Member::factory() ->for(Nationality::factory()) ->for(Subscription::factory()->for(Fee::factory())) @@ -97,25 +144,6 @@ class GenerateTest extends TestCase return $memberModel->load('payments'); }); - - $urlId = call_user_func($urlCallable, $members); - $response = $this->post("/member/{$urlId}/pdf", [ - 'type' => $type, - ]); - - if ($filename === null) { - $response->assertStatus(204); - $this->assertTexCount(0); - - return; - } - - $this->assertEquals('application/pdf', $response->headers->get('content-type')); - $this->assertTrue('attachment; filename="' . $filename . '"', $response->headers->get('content-disposition')); - - foreach ($output as $out) { - $this->assertTexGeneratedWith($out); - } } } diff --git a/tests/Traits/FakesTex.php b/tests/Traits/FakesTex.php deleted file mode 100644 index e30ed8d4..00000000 --- a/tests/Traits/FakesTex.php +++ /dev/null @@ -1,18 +0,0 @@ -