Add pdf generator

This commit is contained in:
philipp lang 2021-07-16 00:12:19 +02:00
parent 7c190d7bcf
commit 3406cf22f9
16 changed files with 129 additions and 58 deletions

2
.gitignore vendored
View File

@ -16,8 +16,8 @@ npm-debug.log
yarn-error.log
tags
/resources/js/libs
/packages
/public/vendor
/storage/temp
# Temporary files
*.swp

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "packages/silvaletter"]
path = packages/silvaletter
url = git@zoomyboy.de:silvaletter.git

View File

@ -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) {

View File

@ -31,4 +31,14 @@ class BillType implements PdfRepository
return $this->filename;
}
public function getView(): string
{
return 'tex.bill';
}
public function getTemplate(): string
{
return 'default';
}
}

View File

@ -15,7 +15,7 @@ class MemberPdfController extends Controller
return $repo === null
? response()->noContent()
: app(PdfGenerator::class)->render($repo);
: app(PdfGenerator::class)->setRepository($repo)->render();
}
}

View File

@ -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);
}
}

View File

@ -13,4 +13,8 @@ interface PdfRepository
public function getFilename(): string;
public function getView(): string;
public function getTemplate(): string;
}

View File

@ -176,6 +176,7 @@ return [
App\Providers\HorizonServiceProvider::class,
App\Providers\RouteServiceProvider::class,
App\Providers\TelescopeServiceProvider::class,
App\Tex\TexServiceProvider::class,
],

View File

@ -48,6 +48,11 @@ return [
'root' => storage_path('app'),
],
'temp' => [
'driver' => 'local',
'root' => storage_path('temp'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),

1
packages/silvaletter Submodule

@ -0,0 +1 @@
Subproject commit 63fb0c9daed5648bc2bf06a0361d95cd586db17f

View File

@ -1,6 +1,6 @@
\documentclass[silvaletter,12pt]{scrlttr2}
\setkomavar{subject}{<-- $subject -->}
\setkomavar{subject}{Rechnung}
\begin{document}
\begin{letter}{Familie Charnay\\Junkerstr 4\\42699 Solingen}

View File

@ -0,0 +1 @@
../../../../packages/silvaletter/template

View File

@ -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');
});

0
storage/temp/.gitkeep Normal file
View File

View File

@ -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);
}
}
}

View File

@ -1,18 +0,0 @@
<?php
namespace Tests\Traits;
trait FakesTex
{
public function fakeTex(): void
{
}
public function assertTexCount(int $count): void
{
}
}