Add tex compilation
This commit is contained in:
parent
8892b11dc7
commit
fb9d7a660c
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\Tex;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Support\Responsable;
|
||||||
|
use Illuminate\Http\File;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
abstract class BaseCompiler implements Responsable
|
||||||
|
{
|
||||||
|
protected File $file;
|
||||||
|
|
||||||
|
public function compile(Document $document): self
|
||||||
|
{
|
||||||
|
$this->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(' && ');
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,52 +2,6 @@
|
||||||
|
|
||||||
namespace Zoomyboy\Tex;
|
namespace Zoomyboy\Tex;
|
||||||
|
|
||||||
use Illuminate\Contracts\Support\Responsable;
|
class Compiler extends BaseCompiler
|
||||||
use Illuminate\Http\File;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class Compiler implements Responsable
|
|
||||||
{
|
{
|
||||||
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()}\"",
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,60 +2,22 @@
|
||||||
|
|
||||||
namespace Zoomyboy\Tex;
|
namespace Zoomyboy\Tex;
|
||||||
|
|
||||||
use Illuminate\Http\File;
|
|
||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Illuminate\Support\Collection;
|
|
||||||
use PHPUnit\Framework\Assert;
|
|
||||||
|
|
||||||
class CompilerFake extends Compiler
|
class CompilerFake extends Compiler
|
||||||
{
|
{
|
||||||
/**
|
use FakesCompilation;
|
||||||
* @var array<int, Document>
|
|
||||||
*/
|
|
||||||
private array $compiledDocuments = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param class-string<Document> $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<Document> $documentClass
|
|
||||||
*
|
|
||||||
* @return Collection<int, Document>
|
|
||||||
*/
|
|
||||||
protected function getCompilations(string $documentClass): Collection
|
|
||||||
{
|
|
||||||
return collect($this->compiledDocuments)->filter(fn ($rendered) => get_class($rendered) === $documentClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function compile(Document $document): self
|
public function compile(Document $document): self
|
||||||
{
|
{
|
||||||
$path = '/tmp/'.$document->filename().'.pdf';
|
$this->prepareForCompilation($document);
|
||||||
$file = UploadedFile::fake()->create($document->filename().'.pdf', 100, 'application/pdf');
|
|
||||||
|
|
||||||
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->registerCompilation($document);
|
||||||
|
|
||||||
$this->compiledDocuments[] = $document;
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,58 +2,17 @@
|
||||||
|
|
||||||
namespace Zoomyboy\Tex;
|
namespace Zoomyboy\Tex;
|
||||||
|
|
||||||
use Illuminate\Support\Collection;
|
class CompilerSpy extends BaseCompiler
|
||||||
use PHPUnit\Framework\Assert;
|
|
||||||
|
|
||||||
class CompilerSpy
|
|
||||||
{
|
{
|
||||||
|
use FakesCompilation;
|
||||||
|
|
||||||
public static Compiler $actualCompiler;
|
public static Compiler $actualCompiler;
|
||||||
/**
|
|
||||||
* @var array<int, Document>
|
|
||||||
*/
|
|
||||||
private array $compiledDocuments = [];
|
|
||||||
|
|
||||||
/**
|
public function compile(Document $document): BaseCompiler
|
||||||
* @param class-string<Document> $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<Document> $documentClass
|
|
||||||
*
|
|
||||||
* @return Collection<int, Document>
|
|
||||||
*/
|
|
||||||
protected function getCompilations(string $documentClass): Collection
|
|
||||||
{
|
|
||||||
return collect($this->compiledDocuments)->filter(fn ($rendered) => get_class($rendered) === $documentClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function compile(Document $document): Compiler
|
|
||||||
{
|
{
|
||||||
$compiler = static::$actualCompiler->compile($document);
|
$compiler = static::$actualCompiler->compile($document);
|
||||||
|
|
||||||
$this->compiledDocuments[] = $document;
|
$this->registerCompilation($document);
|
||||||
|
|
||||||
return $compiler;
|
return $compiler;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,9 @@
|
||||||
|
|
||||||
namespace Zoomyboy\Tex;
|
namespace Zoomyboy\Tex;
|
||||||
|
|
||||||
use PHPUnit\Framework\Assert;
|
|
||||||
|
|
||||||
abstract class Document
|
abstract class Document
|
||||||
{
|
{
|
||||||
abstract public function filename(): string;
|
abstract public function basename(): string;
|
||||||
|
|
||||||
abstract public function view(): string;
|
abstract public function view(): string;
|
||||||
|
|
||||||
|
@ -14,18 +12,25 @@ abstract class Document
|
||||||
|
|
||||||
abstract public function getEngine(): Engine;
|
abstract public function getEngine(): Engine;
|
||||||
|
|
||||||
public function assertHasContent(string $content): void
|
|
||||||
{
|
|
||||||
Assert::assertStringContainsString(
|
|
||||||
$content,
|
|
||||||
$this->renderBody(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function renderBody(): string
|
public function renderBody(): string
|
||||||
{
|
{
|
||||||
return view()
|
return view()
|
||||||
->make($this->view(), get_object_vars($this))
|
->make($this->view(), get_object_vars($this))
|
||||||
->render();
|
->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';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Zoomyboy\Tex;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use PHPUnit\Framework\Assert;
|
||||||
|
|
||||||
|
trait FakesCompilation
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array<int, Document>
|
||||||
|
*/
|
||||||
|
private array $compiledDocuments = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param class-string<Document> $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<Document> $documentClass
|
||||||
|
*
|
||||||
|
* @return Collection<int, Document>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue