From c062001e737a7fa9abd908189168d02ed546562e Mon Sep 17 00:00:00 2001 From: PedroTroller Date: Wed, 16 Oct 2024 16:12:27 +0200 Subject: [PATCH] feat(core): implement frontends for all backends --- .gitignore | 7 +- phpunit.xml.dist | 10 +- src/Backend/Dompdf/DompdfAdapter.php | 4 +- src/Core/Backend/Adapter/DOMDocumentToPdf.php | 2 +- src/Core/Backend/Adapter/StreamToPdf.php | 13 ++ src/Core/Backend/Options.php | 5 +- src/Core/Bridge/FromHtmlFileToHtmlToPdf.php | 31 ----- src/Core/Bridge/FromHtmlToHtmlFileToPdf.php | 37 ------ src/Core/Exception.php | 7 ++ src/Core/Exception/DOMDocumentException.php | 9 ++ src/Core/Exception/FileNotFoundException.php | 9 ++ src/Core/Exception/FileReadException.php | 17 +++ .../FrontendUnsupportedBackendException.php | 21 ++++ .../Exception/StreamDetachedException.php | 15 +++ src/Core/Filesystem/SplResourceInfo.php | 21 ++++ src/Core/Frontend/DOMDocumentToPdf.php | 62 +++++++++ src/Core/Frontend/HtmlFileToPdf.php | 64 ++++++++++ src/Core/Frontend/HtmlToPdf.php | 58 +++++++++ src/Core/Frontend/StreamToPdf.php | 60 +++++++++ src/Core/Stream/FileStream.php | 1 - .../Tests/Filesystem/SplResourceInfoTest.php | 29 +++++ .../Tests/Frontend/DOMDocumentToPdfTest.php | 111 ++++++++++++++++ src/Core/Tests/Frontend/HtmlFileToPdfTest.php | 118 ++++++++++++++++++ src/Core/Tests/Frontend/HtmlToPdfTest.php | 116 +++++++++++++++++ src/Core/Tests/Frontend/StreamToPdfTest.php | 115 +++++++++++++++++ src/Core/Tests/Stream/FileStreamTest.php | 9 ++ src/Core/composer.json | 3 +- src/Core/phpunit.xml.dist | 20 +++ .../DependencyInjection/SnappyExtension.php | 73 ++++++++++- .../SnappyExtensionTest.php | 54 +++++++- 30 files changed, 1006 insertions(+), 95 deletions(-) create mode 100644 src/Core/Backend/Adapter/StreamToPdf.php delete mode 100644 src/Core/Bridge/FromHtmlFileToHtmlToPdf.php delete mode 100644 src/Core/Bridge/FromHtmlToHtmlFileToPdf.php create mode 100644 src/Core/Exception.php create mode 100644 src/Core/Exception/DOMDocumentException.php create mode 100644 src/Core/Exception/FileNotFoundException.php create mode 100644 src/Core/Exception/FileReadException.php create mode 100644 src/Core/Exception/FrontendUnsupportedBackendException.php create mode 100644 src/Core/Exception/StreamDetachedException.php create mode 100644 src/Core/Filesystem/SplResourceInfo.php create mode 100644 src/Core/Frontend/DOMDocumentToPdf.php create mode 100644 src/Core/Frontend/HtmlFileToPdf.php create mode 100644 src/Core/Frontend/HtmlToPdf.php create mode 100644 src/Core/Frontend/StreamToPdf.php create mode 100644 src/Core/Tests/Filesystem/SplResourceInfoTest.php create mode 100644 src/Core/Tests/Frontend/DOMDocumentToPdfTest.php create mode 100644 src/Core/Tests/Frontend/HtmlFileToPdfTest.php create mode 100644 src/Core/Tests/Frontend/HtmlToPdfTest.php create mode 100644 src/Core/Tests/Frontend/StreamToPdfTest.php create mode 100644 src/Core/phpunit.xml.dist diff --git a/.gitignore b/.gitignore index f05530d5..3c04f0ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -**/composer.lock -**/vendor -**cache** +/.php-cs-fixer.cache +/.phpunit.result.cache +/composer.lock +/vendor diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f42624f3..d0ec867c 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,17 +13,11 @@ - - ./src/Backend/Dompdf - - - ./src/Backend/WkHtmlToPdf - - ./src/Core/ + ./src/Core/Tests/ - ./src/Framework/Symfony/ + ./src/Framework/Symfony/Tests/ diff --git a/src/Backend/Dompdf/DompdfAdapter.php b/src/Backend/Dompdf/DompdfAdapter.php index fbb5451b..e63a894c 100644 --- a/src/Backend/Dompdf/DompdfAdapter.php +++ b/src/Backend/Dompdf/DompdfAdapter.php @@ -26,10 +26,10 @@ public function __construct(DompdfFactory $factory, Options $options, private St $this->options = $options; } - public function generateFromDOMDocument(\DOMDocument $DOMDocument): StreamInterface + public function generateFromDOMDocument(\DOMDocument $document): StreamInterface { $dompdf = $this->buildDompdf(); - $dompdf->loadDOM($DOMDocument); + $dompdf->loadDOM($document); return $this->createStream($dompdf); } diff --git a/src/Core/Backend/Adapter/DOMDocumentToPdf.php b/src/Core/Backend/Adapter/DOMDocumentToPdf.php index e6040137..553cd5f1 100644 --- a/src/Core/Backend/Adapter/DOMDocumentToPdf.php +++ b/src/Core/Backend/Adapter/DOMDocumentToPdf.php @@ -9,5 +9,5 @@ interface DOMDocumentToPdf extends Adapter { - public function generateFromDOMDocument(\DOMDocument $DOMDocument): StreamInterface; + public function generateFromDOMDocument(\DOMDocument $document): StreamInterface; } diff --git a/src/Core/Backend/Adapter/StreamToPdf.php b/src/Core/Backend/Adapter/StreamToPdf.php new file mode 100644 index 00000000..466e3ffd --- /dev/null +++ b/src/Core/Backend/Adapter/StreamToPdf.php @@ -0,0 +1,13 @@ + $extraOptions */ - public function __construct(public readonly ?PageOrientation $pageOrientation, public readonly array $extraOptions) {} + public function __construct( + public readonly ?PageOrientation $pageOrientation, + public readonly array $extraOptions + ) {} public static function create(): self { diff --git a/src/Core/Bridge/FromHtmlFileToHtmlToPdf.php b/src/Core/Bridge/FromHtmlFileToHtmlToPdf.php deleted file mode 100644 index a701b9d2..00000000 --- a/src/Core/Bridge/FromHtmlFileToHtmlToPdf.php +++ /dev/null @@ -1,31 +0,0 @@ -getPathname()); - - if (false === $html) { - throw new \RuntimeException('Unable to read file.'); - } - - return $this->adapter->generateFromHtml($html); - } - - public function withOptions(callable|Options $options): self - { - return new self($this->adapter->withOptions($options)); - } -} diff --git a/src/Core/Bridge/FromHtmlToHtmlFileToPdf.php b/src/Core/Bridge/FromHtmlToHtmlFileToPdf.php deleted file mode 100644 index b33935f6..00000000 --- a/src/Core/Bridge/FromHtmlToHtmlFileToPdf.php +++ /dev/null @@ -1,37 +0,0 @@ -streamFactory); - - file_put_contents($temporary->file->getPathname(), $html); - - return $this->adapter->generateFromHtmlFile($temporary->file); - } - - public function withOptions(callable|Options $options): self - { - return new self( - $this->adapter->withOptions($options), - $this->streamFactory, - ); - } -} diff --git a/src/Core/Exception.php b/src/Core/Exception.php new file mode 100644 index 00000000..0d4badf5 --- /dev/null +++ b/src/Core/Exception.php @@ -0,0 +1,7 @@ +getPathname()) + ? parent::__construct("File {$file->getPathname()} can't be read.") + : parent::__construct("File {$file->getPathname()} not found."); + } +} diff --git a/src/Core/Exception/FrontendUnsupportedBackendException.php b/src/Core/Exception/FrontendUnsupportedBackendException.php new file mode 100644 index 00000000..4cbd4ea2 --- /dev/null +++ b/src/Core/Exception/FrontendUnsupportedBackendException.php @@ -0,0 +1,21 @@ +resource)['uri']); + } + + public static function fromTmpFile(): self + { + return new self(tmpfile()); + } +} diff --git a/src/Core/Frontend/DOMDocumentToPdf.php b/src/Core/Frontend/DOMDocumentToPdf.php new file mode 100644 index 00000000..e3402a45 --- /dev/null +++ b/src/Core/Frontend/DOMDocumentToPdf.php @@ -0,0 +1,62 @@ +adapter->withOptions($options), + $this->streamFactory, + ); + } + + public function generateFromDOMDocument(\DOMDocument $document): StreamInterface + { + if ($this->adapter instanceof Adapter\DOMDocumentToPdf) { + return $this->adapter->generateFromDOMDocument($document); + } + + $html = $document->saveHTML(); + + if (false === $html) { + throw new DOMDocumentException('Unable to read HTML from DOMDocument.'); + } + + if ($this->adapter instanceof Adapter\HtmlToPdf) { + return $this->adapter->generateFromHtml($html); + } + + if ($this->adapter instanceof Adapter\StreamToPdf) { + return $this->adapter->generateFromStream( + $this->streamFactory->createStream($html) + ); + } + + if ($this->adapter instanceof Adapter\HtmlFileToPdf) { + $file = SplResourceInfo::fromTmpFile(); + + fwrite($file->resource, $html); + + return $this->adapter->generateFromHtmlFile($file); + } + + throw new FrontendUnsupportedBackendException( + self::class, + $this->adapter::class, + ); + } +} diff --git a/src/Core/Frontend/HtmlFileToPdf.php b/src/Core/Frontend/HtmlFileToPdf.php new file mode 100644 index 00000000..ba6b2fea --- /dev/null +++ b/src/Core/Frontend/HtmlFileToPdf.php @@ -0,0 +1,64 @@ +adapter->withOptions($options), + $this->streamFactory + ); + } + + public function generateFromHtmlFile(\SplFileInfo $file): StreamInterface + { + if ($this->adapter instanceof Adapter\HtmlFileToPdf) { + return $this->adapter->generateFromHtmlFile($file); + } + + if ($this->adapter instanceof Adapter\StreamToPdf) { + return $this->adapter->generateFromStream( + new FileStream( + $file, + $this->streamFactory->createStreamFromFile($file->getPathname()), + ), + ); + } + + if ($this->adapter instanceof Adapter\HtmlToPdf) { + $html = file_get_contents($file->getPathname()); + + if (false === $html) { + throw new FileReadException($file); + } + + return $this->adapter->generateFromHtml($html); + } + + if ($this->adapter instanceof Adapter\DOMDocumentToPdf) { + $document = new \DOMDocument(); + $document->loadHTMLFile($file->getPathname()); + + return $this->adapter->generateFromDOMDocument($document); + } + + throw new FrontendUnsupportedBackendException( + self::class, + $this->adapter::class, + ); + } +} diff --git a/src/Core/Frontend/HtmlToPdf.php b/src/Core/Frontend/HtmlToPdf.php new file mode 100644 index 00000000..123cdac0 --- /dev/null +++ b/src/Core/Frontend/HtmlToPdf.php @@ -0,0 +1,58 @@ +adapter->withOptions($options), + $this->streamFactory + ); + } + + public function generateFromHtml(string $html): StreamInterface + { + if ($this->adapter instanceof Adapter\HtmlToPdf) { + return $this->adapter->generateFromHtml($html); + } + + if ($this->adapter instanceof Adapter\DOMDocumentToPdf) { + $document = new \DOMDocument(); + $document->loadHTML($html); + + return $this->adapter->generateFromDOMDocument($document); + } + + if ($this->adapter instanceof Adapter\StreamToPdf) { + return $this->adapter->generateFromStream( + $this->streamFactory->createStream($html), + ); + } + + if ($this->adapter instanceof Adapter\HtmlFileToPdf) { + $file = SplResourceInfo::fromTmpFile(); + + fwrite($file->resource, $html); + + return $this->adapter->generateFromHtmlFile($file); + } + + throw new FrontendUnsupportedBackendException( + self::class, + $this->adapter::class, + ); + } +} diff --git a/src/Core/Frontend/StreamToPdf.php b/src/Core/Frontend/StreamToPdf.php new file mode 100644 index 00000000..58e7a904 --- /dev/null +++ b/src/Core/Frontend/StreamToPdf.php @@ -0,0 +1,60 @@ +adapter->withOptions($options), + $this->streamFactory + ); + } + + public function generateFromStream(StreamInterface $stream): StreamInterface + { + if ($this->adapter instanceof Adapter\StreamToPdf) { + return $this->adapter->generateFromStream($stream); + } + + if ($this->adapter instanceof Adapter\HtmlToPdf) { + return $this->adapter->generateFromHtml((string) $stream); + } + + if ($this->adapter instanceof Adapter\HtmlFileToPdf) { + $file = SplResourceInfo::fromTmpFile(); + + $input = $stream->detach(); + + if (null === $input) { + throw new StreamDetachedException(); + } + + stream_copy_to_stream($input, $file->resource); + + return $this->adapter->generateFromHtmlFile($file); + } + + if ($this->adapter instanceof Adapter\DOMDocumentToPdf) { + $document = new \DOMDocument(); + $document->loadHTML((string) $stream); + + return $this->adapter->generateFromDOMDocument($document); + } + + throw new FrontendUnsupportedBackendException(self::class, $this->adapter::class); + } +} diff --git a/src/Core/Stream/FileStream.php b/src/Core/Stream/FileStream.php index c2491347..27083702 100644 --- a/src/Core/Stream/FileStream.php +++ b/src/Core/Stream/FileStream.php @@ -4,7 +4,6 @@ namespace KNPLabs\Snappy\Core\Stream; -use Psr\Http\Message\StreamFactoryInterface; use Psr\Http\Message\StreamInterface; final class FileStream implements StreamInterface diff --git a/src/Core/Tests/Filesystem/SplResourceInfoTest.php b/src/Core/Tests/Filesystem/SplResourceInfoTest.php new file mode 100644 index 00000000..c3f7c380 --- /dev/null +++ b/src/Core/Tests/Filesystem/SplResourceInfoTest.php @@ -0,0 +1,29 @@ +getPathname(); + + self::assertFileExists($path); + + unset($file); + + self::assertFileDoesNotExist($path); + } +} diff --git a/src/Core/Tests/Frontend/DOMDocumentToPdfTest.php b/src/Core/Tests/Frontend/DOMDocumentToPdfTest.php new file mode 100644 index 00000000..65f1dcfe --- /dev/null +++ b/src/Core/Tests/Frontend/DOMDocumentToPdfTest.php @@ -0,0 +1,111 @@ +output = $this->createStub(StreamInterface::class); + $this->streamFactory = new Psr17Factory(); + $this->document = new \DOMDocument(); + $this->document->loadHTML(''); + } + + public function testWithDOMDocumentToPdf(): void + { + $backend = $this->createMock(Adapter\DOMDocumentToPdf::class); + $frontend = new DOMDocumentToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromDOMDocument') + ->with($this->document) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromDOMDocument($this->document), + $this->output, + ); + } + + public function testWithHtmlToPdf(): void + { + $backend = $this->createMock(Adapter\HtmlToPdf::class); + $frontend = new DOMDocumentToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromHtml') + ->with($this->document->saveHTML()) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromDOMDocument($this->document), + $this->output, + ); + } + + public function testWithHtmlFileToPdf(): void + { + $backend = $this->createMock(Adapter\HtmlFileToPdf::class); + $frontend = new DOMDocumentToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromHtmlFile') + ->with( + new Constraint\Callback( + fn (\SplFileInfo $file) => $this->document->saveHTML() === file_get_contents($file->getPathname()) + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromDOMDocument($this->document), + $this->output, + ); + } + + public function testWithStreamToPdf(): void + { + $backend = $this->createMock(Adapter\StreamToPdf::class); + $frontend = new DOMDocumentToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromStream') + ->with( + new Constraint\Callback( + fn (StreamInterface $stream) => $this->document->saveHTML() === (string) $stream + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromDOMDocument($this->document), + $this->output, + ); + } +} diff --git a/src/Core/Tests/Frontend/HtmlFileToPdfTest.php b/src/Core/Tests/Frontend/HtmlFileToPdfTest.php new file mode 100644 index 00000000..59b363b4 --- /dev/null +++ b/src/Core/Tests/Frontend/HtmlFileToPdfTest.php @@ -0,0 +1,118 @@ +output = $this->createStub(StreamInterface::class); + $this->streamFactory = new Psr17Factory(); + $this->file = SplResourceInfo::fromTmpFile(); + + fwrite($this->file->resource, ''); + } + + public function testWithDOMDocumentToPdf(): void + { + $backend = $this->createMock(Adapter\DOMDocumentToPdf::class); + $frontend = new HtmlFileToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromDOMDocument') + ->with( + new Constraint\Callback( + static function (\DOMDocument $document) { + $expected = new \DOMDocument(); + $expected->loadHTML(''); + + return $document->saveHTML() === $expected->saveHTML(); + } + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromHtmlFile($this->file), + $this->output, + ); + } + + public function testWithHtmlToPdf(): void + { + $backend = $this->createMock(Adapter\HtmlToPdf::class); + $frontend = new HtmlFileToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromHtml') + ->with('') + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromHtmlFile($this->file), + $this->output, + ); + } + + public function testWithHtmlFileToPdf(): void + { + $backend = $this->createMock(Adapter\HtmlFileToPdf::class); + $frontend = new HtmlFileToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromHtmlFile') + ->with($this->file) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromHtmlFile($this->file), + $this->output, + ); + } + + public function testWithStreamToPdf(): void + { + $backend = $this->createMock(Adapter\StreamToPdf::class); + $frontend = new HtmlFileToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromStream') + ->with( + new Constraint\Callback( + static fn (StreamInterface $stream) => '' === (string) $stream, + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromHtmlFile($this->file), + $this->output, + ); + } +} diff --git a/src/Core/Tests/Frontend/HtmlToPdfTest.php b/src/Core/Tests/Frontend/HtmlToPdfTest.php new file mode 100644 index 00000000..d26bbf21 --- /dev/null +++ b/src/Core/Tests/Frontend/HtmlToPdfTest.php @@ -0,0 +1,116 @@ +output = $this->createStub(StreamInterface::class); + $this->streamFactory = new Psr17Factory(); + } + + public function testWithDOMDocumentToPdf(): void + { + $backend = $this->createMock(Adapter\DOMDocumentToPdf::class); + $frontend = new HtmlToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromDOMDocument') + ->with( + new Constraint\Callback( + static function (\DOMDocument $document) { + $expected = new \DOMDocument(); + $expected->loadHTML(''); + + return $document->saveHTML() === $expected->saveHTML(); + } + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromHtml(''), + $this->output, + ); + } + + public function testWithHtmlToPdf(): void + { + $backend = $this->createMock(Adapter\HtmlToPdf::class); + $frontend = new HtmlToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromHtml') + ->with('') + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromHtml(''), + $this->output, + ); + } + + public function testWithHtmlFileToPdf(): void + { + $backend = $this->createMock(Adapter\HtmlFileToPdf::class); + $frontend = new HtmlToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromHtmlFile') + ->with( + new Constraint\Callback( + static fn (\SplFileInfo $file) => '' === file_get_contents($file->getPathname()) + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromHtml(''), + $this->output, + ); + } + + public function testWithStreamToPdf(): void + { + $backend = $this->createMock(Adapter\StreamToPdf::class); + $frontend = new HtmlToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromStream') + ->with( + new Constraint\Callback( + static fn (StreamInterface $stream) => '' === (string) $stream, + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromHtml(''), + $this->output, + ); + } +} diff --git a/src/Core/Tests/Frontend/StreamToPdfTest.php b/src/Core/Tests/Frontend/StreamToPdfTest.php new file mode 100644 index 00000000..c304f2c1 --- /dev/null +++ b/src/Core/Tests/Frontend/StreamToPdfTest.php @@ -0,0 +1,115 @@ +output = $this->createStub(StreamInterface::class); + $this->streamFactory = new Psr17Factory(); + $this->stream = $this->streamFactory->createStream(''); + } + + public function testWithDOMDocumentToPdf(): void + { + $backend = $this->createMock(Adapter\DOMDocumentToPdf::class); + $frontend = new StreamToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromDOMDocument') + ->with( + new Constraint\Callback( + static function (\DOMDocument $document) { + $expected = new \DOMDocument(); + $expected->loadHTML(''); + + return $document->saveHTML() === $expected->saveHTML(); + } + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromStream($this->stream), + $this->output, + ); + } + + public function testWithHtmlToPdf(): void + { + $backend = $this->createMock(Adapter\HtmlToPdf::class); + $frontend = new StreamToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromHtml') + ->with((string) $this->stream) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromStream($this->stream), + $this->output, + ); + } + + public function testWithHtmlFileToPdf(): void + { + $backend = $this->createMock(Adapter\HtmlFileToPdf::class); + $frontend = new StreamToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromHtmlFile') + ->with( + new Constraint\Callback( + static fn (\SplFileInfo $file) => '' === file_get_contents($file->getPathname()) + ) + ) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromStream($this->stream), + $this->output, + ); + } + + public function testWithStreamToPdf(): void + { + $backend = $this->createMock(Adapter\StreamToPdf::class); + $frontend = new StreamToPdf($backend, $this->streamFactory); + + $backend + ->method('generateFromStream') + ->with($this->stream) + ->willReturn($this->output) + ; + + self::assertSame( + $frontend->generateFromStream($this->stream), + $this->output, + ); + } +} diff --git a/src/Core/Tests/Stream/FileStreamTest.php b/src/Core/Tests/Stream/FileStreamTest.php index 7d0d9f42..ca888cb2 100644 --- a/src/Core/Tests/Stream/FileStreamTest.php +++ b/src/Core/Tests/Stream/FileStreamTest.php @@ -4,6 +4,7 @@ namespace KNPLabs\Snappy\Core\Tests\Stream; +use KNPLabs\Snappy\Core\Filesystem\SplResourceInfo; use KNPLabs\Snappy\Core\Stream\FileStream; use Nyholm\Psr7\Factory\Psr17Factory; use PHPUnit\Framework\TestCase; @@ -19,8 +20,16 @@ final class FileStreamTest extends TestCase protected function setUp(): void { +<<<<<<< HEAD $this->stream = FileStream::createTmpFile( new Psr17Factory(), +======= + $file = SplResourceInfo::fromTmpFile(); + + $this->stream = new FileStream( + $file, + (new Psr17Factory())->createStreamFromResource($file->resource), +>>>>>>> c873af3 (feat(core): implement frontends for all backends) ); } diff --git a/src/Core/composer.json b/src/Core/composer.json index 7616157e..5d0fdf6b 100644 --- a/src/Core/composer.json +++ b/src/Core/composer.json @@ -2,6 +2,7 @@ "name": "knplabs/snappy-core", "require": { "php": ">=8.1", + "psr/http-factory": "^1.1", "psr/http-message": "^2.0" }, "require-dev": { @@ -13,4 +14,4 @@ "KNPLabs\\Snappy\\Core\\": "./" } } -} \ No newline at end of file +} diff --git a/src/Core/phpunit.xml.dist b/src/Core/phpunit.xml.dist new file mode 100644 index 00000000..efb18ef8 --- /dev/null +++ b/src/Core/phpunit.xml.dist @@ -0,0 +1,20 @@ + + + + + + + + + + ./Tests/ + + + diff --git a/src/Framework/Symfony/DependencyInjection/SnappyExtension.php b/src/Framework/Symfony/DependencyInjection/SnappyExtension.php index 69753df7..7694b290 100644 --- a/src/Framework/Symfony/DependencyInjection/SnappyExtension.php +++ b/src/Framework/Symfony/DependencyInjection/SnappyExtension.php @@ -4,18 +4,30 @@ namespace KNPLabs\Snappy\Framework\Symfony\DependencyInjection; +use KNPLabs\Snappy\Core\Backend\Adapter; +use KNPLabs\Snappy\Core\Backend\Factory; use KNPLabs\Snappy\Core\Backend\Options; use KNPLabs\Snappy\Core\Backend\Options\PageOrientation; +use KNPLabs\Snappy\Core\Frontend; use KNPLabs\Snappy\Framework\Symfony\DependencyInjection\Configuration\BackendConfigurationFactory; use KNPLabs\Snappy\Framework\Symfony\DependencyInjection\Configuration\DompdfConfigurationFactory; use KNPLabs\Snappy\Framework\Symfony\DependencyInjection\Configuration\WkHtmlToPdfConfigurationFactory; +use Psr\Http\Message\StreamFactoryInterface; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Extension\Extension; +use Symfony\Component\DependencyInjection\Reference; final class SnappyExtension extends Extension { + private const FRONTENDS = [ + Adapter\DOMDocumentToPdf::class => Frontend\DOMDocumentToPdf::class, + Adapter\HtmlFileToPdf::class => Frontend\HtmlFileToPdf::class, + Adapter\HtmlToPdf::class => Frontend\HtmlToPdf::class, + Adapter\StreamToPdf::class => Frontend\StreamToPdf::class, + ]; + public function load(array $configuration, ContainerBuilder $container): void { $configuration = $this->processConfiguration( @@ -46,6 +58,25 @@ public function load(array $configuration, ContainerBuilder $container): void $options, ) ; + + foreach (self::FRONTENDS as $adapterClass => $frontendClass) { + $frontendId = $this->buildFrontendServiceId($backendName, $frontendClass); + + $container + ->setDefinition( + $frontendId, + new Definition( + $frontendClass, + [ + '$adapter' => new Reference($backendId), + '$streamFactory' => new Reference(StreamFactoryInterface::class), + ], + ), + ) + ; + } + + $container->registerAliasForArgument($frontendId, $adapterClass, $backendName); } } } @@ -77,7 +108,7 @@ private function getFactories(): array */ private function buildBackendServiceId(string $name): string { - return "snappy.backend.{$name}"; + return $this->normalizeId(Adapter::class).'.'.$name; } /** @@ -85,7 +116,27 @@ private function buildBackendServiceId(string $name): string */ private function buildFactoryServiceId(string $name): string { - return "snappy.backend.{$name}.factory"; + return $this->normalizeId(Factory::class).'.'.$name; + } + + /** + * @param class-string $class + * + * @return non-empty-string + */ + private function buildFrontendServiceId(string $name, string $class): string + { + return $this->normalizeId($class).'.'.$name; + } + + /** + * @param non-empty-string $id + * + * @return non-empty-string + */ + private function normalizeId(string $id): string + { + return strtolower(str_replace('\\', '.', $id)); } /** @@ -100,7 +151,14 @@ private function buildOptions(string $backendName, string $backendType, array $c if (isset($configuration['pageOrientation'])) { if (false === \is_string($configuration['pageOrientation'])) { - throw new InvalidConfigurationException(\sprintf('Invalid “%s” type for “snappy.backends.%s.%s.options.pageOrientation”. The expected type is “string”.', $backendName, $backendType, \gettype($configuration['pageOrientation']))); + throw new InvalidConfigurationException( + \sprintf( + 'Invalid “%s” type for “snappy.backends.%s.%s.options.pageOrientation”. The expected type is “string”.', + $backendName, + $backendType, + \gettype($configuration['pageOrientation']) + ), + ); } $arguments['$pageOrientation'] = PageOrientation::from($configuration['pageOrientation']); @@ -108,7 +166,14 @@ private function buildOptions(string $backendName, string $backendType, array $c if (isset($configuration['extraOptions'])) { if (false === \is_array($configuration['extraOptions'])) { - throw new InvalidConfigurationException(\sprintf('Invalid “%s” type for “snappy.backends.%s.%s.options.extraOptions”. The expected type is “array”.', $backendName, $backendType, \gettype($configuration['extraOptions']))); + throw new InvalidConfigurationException( + \sprintf( + 'Invalid “%s” type for “snappy.backends.%s.%s.options.extraOptions”. The expected type is “array”.', + $backendName, + $backendType, + \gettype($configuration['extraOptions']) + ), + ); } $arguments['$extraOptions'] = $configuration['extraOptions']; diff --git a/src/Framework/Symfony/Tests/DependencyInjection/SnappyExtensionTest.php b/src/Framework/Symfony/Tests/DependencyInjection/SnappyExtensionTest.php index 90b213c9..ff25f07d 100644 --- a/src/Framework/Symfony/Tests/DependencyInjection/SnappyExtensionTest.php +++ b/src/Framework/Symfony/Tests/DependencyInjection/SnappyExtensionTest.php @@ -8,6 +8,7 @@ use KNPLabs\Snappy\Backend\Dompdf\DompdfFactory; use KNPLabs\Snappy\Core\Backend\Options; use KNPLabs\Snappy\Core\Backend\Options\PageOrientation; +use KNPLabs\Snappy\Core\Frontend; use KNPLabs\Snappy\Framework\Symfony\DependencyInjection\SnappyExtension; use Nyholm\Psr7\Factory\Psr17Factory; use PHPUnit\Framework\TestCase; @@ -46,7 +47,7 @@ public function testLoadEmptyConfiguration(): void $this->container, ); - self::assertSame( + self::assertEquals( array_keys($this->container->getDefinitions()), [ 'service_container', @@ -81,13 +82,17 @@ public function testDompdfBackendConfiguration(): void $this->extension->load($configuration, $this->container); - self::assertSame( + self::assertEquals( array_keys($this->container->getDefinitions()), [ 'service_container', StreamFactoryInterface::class, - 'snappy.backend.myBackend.factory', - 'snappy.backend.myBackend', + 'knplabs.snappy.core.backend.factory.myBackend', + 'knplabs.snappy.core.backend.adapter.myBackend', + 'knplabs.snappy.core.frontend.domdocumenttopdf.myBackend', + 'knplabs.snappy.core.frontend.htmlfiletopdf.myBackend', + 'knplabs.snappy.core.frontend.htmltopdf.myBackend', + 'knplabs.snappy.core.frontend.streamtopdf.myBackend', ] ); @@ -95,7 +100,7 @@ public function testDompdfBackendConfiguration(): void self::assertInstanceOf(StreamFactoryInterface::class, $streamFactory); - $factory = $this->container->get('snappy.backend.myBackend.factory'); + $factory = $this->container->get('knplabs.snappy.core.backend.factory.myBackend'); self::assertInstanceOf(DompdfFactory::class, $factory); self::assertEquals( @@ -103,9 +108,14 @@ public function testDompdfBackendConfiguration(): void new DompdfFactory($streamFactory) ); - $backend = $this->container->get('snappy.backend.myBackend'); + $backend = $this->container->get('knplabs.snappy.core.backend.adapter.myBackend'); self::assertInstanceOf(DompdfAdapter::class, $backend); + self::assertEquals( + $factory, + new DompdfFactory($streamFactory), + ); + self::assertEquals( $backend, new DompdfAdapter( @@ -120,5 +130,37 @@ public function testDompdfBackendConfiguration(): void $streamFactory, ), ); + + self::assertEquals( + $this->container->get('knplabs.snappy.core.frontend.domdocumenttopdf.myBackend'), + new Frontend\DOMDocumentToPdf( + $backend, + $streamFactory, + ), + ); + + self::assertEquals( + $this->container->get('knplabs.snappy.core.frontend.htmlfiletopdf.myBackend'), + new Frontend\HtmlFileToPdf( + $backend, + $streamFactory, + ), + ); + + self::assertEquals( + $this->container->get('knplabs.snappy.core.frontend.htmltopdf.myBackend'), + new Frontend\HtmlToPdf( + $backend, + $streamFactory, + ), + ); + + self::assertEquals( + $this->container->get('knplabs.snappy.core.frontend.streamtopdf.myBackend'), + new Frontend\StreamToPdf( + $backend, + $streamFactory, + ), + ); } }