From fb9d7a660c6e170eedf7a11b02f7cfeff14346ab Mon Sep 17 00:00:00 2001 From: Philipp Lang Date: Fri, 28 Oct 2022 11:55:09 +0200 Subject: [PATCH] Add tex compilation --- src/BaseCompiler.php | 61 ++++++++++++++++++++++++++++++++++++++++ src/Compiler.php | 48 +------------------------------ src/CompilerFake.php | 52 +++++----------------------------- src/CompilerSpy.php | 51 ++++----------------------------- src/Document.php | 27 ++++++++++-------- src/FakesCompilation.php | 47 +++++++++++++++++++++++++++++++ 6 files changed, 137 insertions(+), 149 deletions(-) create mode 100644 src/BaseCompiler.php create mode 100644 src/FakesCompilation.php diff --git a/src/BaseCompiler.php b/src/BaseCompiler.php new file mode 100644 index 0000000..5bf07fb --- /dev/null +++ b/src/BaseCompiler.php @@ -0,0 +1,61 @@ +prepareForCompilation($document); + + $contents = $document->renderBody(); + file_put_contents("{$this->file->getPath()}/{$document->filename()}", $contents); + + if ($document->template()) { + $templatePath = $document->template()->fullPath(); + exec('rsync -av '.escapeshellarg($templatePath).'/ '.escapeshellarg($this->file->getPath())); + } + + exec($this->command($document), $output, $returnVar); + $this->refreshFile(); + + throw_unless($this->file->isFile(), CompilerException::class, 'Compilation failed.'); + + return $this; + } + + public function toResponse($request) + { + return response()->file($this->file->getRealPath(), [ + 'Content-Type' => 'application/pdf', + 'Content-Disposition' => "inline; filename=\"{$this->file->getFilename()}\"", + ]); + } + + protected function prepareForCompilation(Document $document): void + { + $workDir = '/tmp/'.Str::random(32); + mkdir($workDir, 0777, true); + $this->file = new File($workDir.'/'.$document->compiledFilename(), false); + } + + private function refreshFile(): void + { + $this->file = new File($this->file->getPathname(), false); + } + + private function command(Document $document): string + { + return collect([ + 'cd '.escapeshellarg($this->file->getPath()), + $document->getEngine()->binary().' --halt-on-error '.$document->filename(), + $document->getEngine()->binary().' --halt-on-error '.$document->filename(), + ])->implode(' && '); + } +} diff --git a/src/Compiler.php b/src/Compiler.php index 01afcab..6c241d5 100644 --- a/src/Compiler.php +++ b/src/Compiler.php @@ -2,52 +2,6 @@ namespace Zoomyboy\Tex; -use Illuminate\Contracts\Support\Responsable; -use Illuminate\Http\File; -use Illuminate\Support\Str; - -class Compiler implements Responsable +class Compiler extends BaseCompiler { - public File $file; - - public function compile(Document $document): self - { - $filename = $document->filename(); - $dir = Str::random(32); - - $contents = $document->renderBody(); - - mkdir('/tmp/'.$dir); - file_put_contents('/tmp/'.$dir.'/'.$document->filename().'.tex', $contents); - - if ($document->template()) { - $templatePath = $document->template()->fullPath(); - exec('rsync -av '.escapeshellarg($templatePath).'/ /tmp/'.escapeshellarg($dir)); - } - - $command = collect([ - 'cd /tmp/'.escapeshellarg($dir), - $document->getEngine()->binary().' --halt-on-error '.$document->filename().'.tex', - $document->getEngine()->binary().' --halt-on-error '.$document->filename().'.tex', - ])->implode(' && '); - - exec($command, $output, $returnVar); - dd($output); - - if (file_exists('/tmp/'.$dir.'/'.$document->filename().'.pdf')) { - $this->file = new File('/tmp/'.$dir.'/'.$document->filename().'.pdf'); - } else { - throw new Exception('Compilation failed'); - } - - return $this; - } - - public function toResponse($request) - { - return response()->file($this->file->getRealPath(), [ - 'Content-Type' => 'application/pdf', - 'Content-Disposition' => "inline; filename=\"{$this->file->getFilename()}\"", - ]); - } } diff --git a/src/CompilerFake.php b/src/CompilerFake.php index 7054c27..99745f6 100644 --- a/src/CompilerFake.php +++ b/src/CompilerFake.php @@ -2,60 +2,22 @@ namespace Zoomyboy\Tex; -use Illuminate\Http\File; use Illuminate\Http\UploadedFile; -use Illuminate\Support\Collection; -use PHPUnit\Framework\Assert; class CompilerFake extends Compiler { - /** - * @var array - */ - private array $compiledDocuments = []; - - /** - * @param class-string $documentClass - * @param callable(Document): bool $check - */ - public function assertCompiled(string $documentClass, callable $check): void - { - $compilations = $this->getCompilations($documentClass); - Assert::assertFalse( - $compilations->isEmpty(), - 'The TeX Document "'.$documentClass.'" has not been compiled at all.' - ); - - Assert::assertFalse( - $compilations->isEmpty(), - 'The TeX Document "'.$documentClass.'" has not been compiled.' - ); - - $validDocuments = $compilations->filter(fn ($compilation) => $check($compilation)); - - Assert::assertNotEmpty($validDocuments, 'Failed that TeX Document "'.$documentClass.'" has been compiled with given check.'); - } - - /** - * @param class-string $documentClass - * - * @return Collection - */ - protected function getCompilations(string $documentClass): Collection - { - return collect($this->compiledDocuments)->filter(fn ($rendered) => get_class($rendered) === $documentClass); - } + use FakesCompilation; public function compile(Document $document): self { - $path = '/tmp/'.$document->filename().'.pdf'; - $file = UploadedFile::fake()->create($document->filename().'.pdf', 100, 'application/pdf'); + $this->prepareForCompilation($document); - file_put_contents($path, $file->get()); + file_put_contents( + $this->file->getPathname(), + UploadedFile::fake()->create($this->file->getFilename(), 100, 'application/pdf')->get() + ); - $this->file = new File($path, true); - - $this->compiledDocuments[] = $document; + $this->registerCompilation($document); return $this; } diff --git a/src/CompilerSpy.php b/src/CompilerSpy.php index a2ce69e..b061beb 100644 --- a/src/CompilerSpy.php +++ b/src/CompilerSpy.php @@ -2,58 +2,17 @@ namespace Zoomyboy\Tex; -use Illuminate\Support\Collection; -use PHPUnit\Framework\Assert; - -class CompilerSpy +class CompilerSpy extends BaseCompiler { + use FakesCompilation; + public static Compiler $actualCompiler; - /** - * @var array - */ - private array $compiledDocuments = []; - /** - * @param class-string $documentClass - * @param callable(Document): bool $check - */ - public function assertCompiled(string $documentClass, callable $check): void - { - $compilations = $this->getCompilations($documentClass); - Assert::assertFalse( - $compilations->isEmpty(), - 'The TeX Document "'.$documentClass.'" has not been compiled at all.' - ); - - Assert::assertFalse( - $compilations->isEmpty(), - 'The TeX Document "'.$documentClass.'" has not been compiled.' - ); - - foreach ($compilations as $compilation) { - } - - Assert::assertFalse( - $this->getCompilations($documentClass)->isEmpty(), - 'The TeX Document "'.$documentClass.'" has not been compiled.' - ); - } - - /** - * @param class-string $documentClass - * - * @return Collection - */ - protected function getCompilations(string $documentClass): Collection - { - return collect($this->compiledDocuments)->filter(fn ($rendered) => get_class($rendered) === $documentClass); - } - - public function compile(Document $document): Compiler + public function compile(Document $document): BaseCompiler { $compiler = static::$actualCompiler->compile($document); - $this->compiledDocuments[] = $document; + $this->registerCompilation($document); return $compiler; } diff --git a/src/Document.php b/src/Document.php index 3469aeb..efe33d6 100644 --- a/src/Document.php +++ b/src/Document.php @@ -2,11 +2,9 @@ namespace Zoomyboy\Tex; -use PHPUnit\Framework\Assert; - abstract class Document { - abstract public function filename(): string; + abstract public function basename(): string; abstract public function view(): string; @@ -14,18 +12,25 @@ abstract class Document abstract public function getEngine(): Engine; - public function assertHasContent(string $content): void - { - Assert::assertStringContainsString( - $content, - $this->renderBody(), - ); - } - public function renderBody(): string { return view() ->make($this->view(), get_object_vars($this)) ->render(); } + + public function hasContent(string $content): bool + { + return str_contains($this->renderBody(), $content); + } + + public function filename(): string + { + return $this->basename().'.tex'; + } + + public function compiledFilename(): string + { + return $this->basename().'.pdf'; + } } diff --git a/src/FakesCompilation.php b/src/FakesCompilation.php new file mode 100644 index 0000000..ddbb478 --- /dev/null +++ b/src/FakesCompilation.php @@ -0,0 +1,47 @@ + + */ + private array $compiledDocuments = []; + + /** + * @param class-string $documentClass + * @param callable(Document): bool $check + */ + public function assertCompiled(string $documentClass, callable $check): void + { + $compilations = $this->getCompilations($documentClass); + + Assert::assertFalse( + $compilations->isEmpty(), + 'The TeX Document "'.$documentClass.'" has not been compiled.' + ); + + $validDocuments = $compilations->filter(fn ($compilation) => $check($compilation)); + + Assert::assertNotEmpty($validDocuments, 'Failed that TeX Document "'.$documentClass.'" has been compiled with given check.'); + } + + /** + * @param class-string $documentClass + * + * @return Collection + */ + protected function getCompilations(string $documentClass): Collection + { + return collect($this->compiledDocuments)->filter(fn ($rendered) => get_class($rendered) === $documentClass); + } + + protected function registerCompilation(Document $document): void + { + $this->compiledDocuments[] = $document; + } +}