From 2fbbbe7260ac2330caa2a0e5cfc5be28ea6bfdb7 Mon Sep 17 00:00:00 2001 From: Alexander Pankow Date: Sun, 4 Sep 2022 12:15:47 +0200 Subject: [PATCH] added inline disposition for PDF previews (#3486) --- src/Controller/ExportController.php | 6 ++++ src/Controller/InvoiceController.php | 2 +- .../Base/DispositionInlineInterface.php | 18 ++++++++++ src/Export/Base/DispositionInlineTrait.php | 34 +++++++++++++++++++ src/Export/Base/PDFRenderer.php | 6 ++-- src/Invoice/Renderer/PdfRenderer.php | 9 +++-- src/Invoice/ServiceInvoice.php | 7 +++- tests/Export/Renderer/PdfRendererTest.php | 17 ++++++++++ tests/Invoice/Renderer/PdfRendererTest.php | 18 ++++++++-- 9 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 src/Export/Base/DispositionInlineInterface.php create mode 100644 src/Export/Base/DispositionInlineTrait.php diff --git a/src/Controller/ExportController.php b/src/Controller/ExportController.php index d989567d..556a34b4 100644 --- a/src/Controller/ExportController.php +++ b/src/Controller/ExportController.php @@ -9,6 +9,7 @@ namespace App\Controller; +use App\Export\Base\DispositionInlineInterface; use App\Export\ExportItemInterface; use App\Export\ServiceExport; use App\Export\TooManyItemsExportException; @@ -117,6 +118,11 @@ class ExportController extends AbstractController throw $this->createNotFoundException('Unknown export renderer'); } + // display file inline if supported and `markAsExported` is not set + if ($renderer instanceof DispositionInlineInterface && !$query->isMarkAsExported()) { + $renderer->setDispositionInline(true); + } + $entries = $this->getEntries($query); $response = $renderer->render($entries, $query); diff --git a/src/Controller/InvoiceController.php b/src/Controller/InvoiceController.php index c2c9255d..5a91bd03 100644 --- a/src/Controller/InvoiceController.php +++ b/src/Controller/InvoiceController.php @@ -168,7 +168,7 @@ final class InvoiceController extends AbstractController $query->setCustomers([$customer]); $model = $this->service->createModel($query); - return $this->service->renderInvoiceWithModel($model, $this->dispatcher); + return $this->service->renderInvoiceWithModel($model, $this->dispatcher, true); } catch (Exception $ex) { $this->logException($ex); $this->flashError('action.update.error', ['%reason%' => $ex->getMessage()]); diff --git a/src/Export/Base/DispositionInlineInterface.php b/src/Export/Base/DispositionInlineInterface.php new file mode 100644 index 00000000..54940697 --- /dev/null +++ b/src/Export/Base/DispositionInlineInterface.php @@ -0,0 +1,18 @@ +disposition; + } + + public function setDispositionInline(bool $useInlineDisposition): void + { + if ($useInlineDisposition) { + $this->disposition = ResponseHeaderBag::DISPOSITION_INLINE; + } else { + $this->disposition = ResponseHeaderBag::DISPOSITION_ATTACHMENT; + } + } +} diff --git a/src/Export/Base/PDFRenderer.php b/src/Export/Base/PDFRenderer.php index ea09a460..bd494a67 100644 --- a/src/Export/Base/PDFRenderer.php +++ b/src/Export/Base/PDFRenderer.php @@ -17,12 +17,12 @@ use App\Repository\Query\TimesheetQuery; use App\Utils\FileHelper; use App\Utils\HtmlToPdfConverter; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Twig\Environment; -class PDFRenderer +class PDFRenderer implements DispositionInlineInterface { use RendererTrait; + use DispositionInlineTrait; /** * @var Environment @@ -125,7 +125,7 @@ class PDFRenderer $filename = FileHelper::convertToAsciiFilename($filename); - $disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename . '.pdf'); + $disposition = $response->headers->makeDisposition($this->getDisposition(), $filename . '.pdf'); $response->headers->set('Content-Type', 'application/pdf'); $response->headers->set('Content-Disposition', $disposition); diff --git a/src/Invoice/Renderer/PdfRenderer.php b/src/Invoice/Renderer/PdfRenderer.php index 4bf87172..fd58bc6a 100644 --- a/src/Invoice/Renderer/PdfRenderer.php +++ b/src/Invoice/Renderer/PdfRenderer.php @@ -10,16 +10,19 @@ namespace App\Invoice\Renderer; use App\Entity\InvoiceDocument; +use App\Export\Base\DispositionInlineInterface; +use App\Export\Base\DispositionInlineTrait; use App\Export\ExportContext; use App\Invoice\InvoiceFilename; use App\Invoice\InvoiceModel; use App\Utils\HtmlToPdfConverter; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Twig\Environment; -final class PdfRenderer extends AbstractTwigRenderer +final class PdfRenderer extends AbstractTwigRenderer implements DispositionInlineInterface { + use DispositionInlineTrait; + /** * @var HtmlToPdfConverter */ @@ -58,7 +61,7 @@ final class PdfRenderer extends AbstractTwigRenderer $response = new Response($content); - $disposition = $response->headers->makeDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename . '.pdf'); + $disposition = $response->headers->makeDisposition($this->getDisposition(), $filename . '.pdf'); $response->headers->set('Content-Type', 'application/pdf'); $response->headers->set('Content-Disposition', $disposition); diff --git a/src/Invoice/ServiceInvoice.php b/src/Invoice/ServiceInvoice.php index daeedcf1..7a3fea28 100644 --- a/src/Invoice/ServiceInvoice.php +++ b/src/Invoice/ServiceInvoice.php @@ -17,6 +17,7 @@ use App\Event\InvoiceCreatedEvent; use App\Event\InvoiceDeleteEvent; use App\Event\InvoicePostRenderEvent; use App\Event\InvoicePreRenderEvent; +use App\Export\Base\DispositionInlineInterface; use App\Repository\InvoiceDocumentRepository; use App\Repository\InvoiceRepository; use App\Repository\Query\InvoiceQuery; @@ -309,7 +310,7 @@ final class ServiceInvoice } } - public function renderInvoiceWithModel(InvoiceModel $model, EventDispatcherInterface $dispatcher): Response + public function renderInvoiceWithModel(InvoiceModel $model, EventDispatcherInterface $dispatcher, bool $dispositionInline = false): Response { $document = $this->getDocumentByName($model->getTemplate()->getRenderer()); if (null === $document) { @@ -320,6 +321,10 @@ final class ServiceInvoice if ($renderer->supports($document)) { $dispatcher->dispatch(new InvoicePreRenderEvent($model, $document, $renderer)); + if ($renderer instanceof DispositionInlineInterface) { + $renderer->setDispositionInline($dispositionInline); + } + $response = $renderer->render($document, $model); $dispatcher->dispatch(new InvoicePostRenderEvent($model, $document, $renderer, $response)); diff --git a/tests/Export/Renderer/PdfRendererTest.php b/tests/Export/Renderer/PdfRendererTest.php index f5d545d5..7d010960 100644 --- a/tests/Export/Renderer/PdfRendererTest.php +++ b/tests/Export/Renderer/PdfRendererTest.php @@ -15,6 +15,7 @@ use App\Tests\Mocks\FileHelperFactory; use App\Utils\HtmlToPdfConverter; use App\Utils\MPdfConverter; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Twig\Environment; /** @@ -25,6 +26,22 @@ use Twig\Environment; */ class PdfRendererTest extends AbstractRendererTest { + public function testDisposition() + { + $sut = new PDFRenderer( + $this->createMock(Environment::class), + $this->createMock(HtmlToPdfConverter::class), + $this->createMock(ProjectStatisticService::class) + ); + $this->assertEquals(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $sut->getDisposition()); + $sut->setDispositionInline(false); + $this->assertEquals(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $sut->getDisposition()); + $sut->setDispositionInline(true); + $this->assertEquals(ResponseHeaderBag::DISPOSITION_INLINE, $sut->getDisposition()); + $sut->setDispositionInline(false); + $this->assertEquals(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $sut->getDisposition()); + } + public function testConfiguration() { $sut = new PDFRenderer( diff --git a/tests/Invoice/Renderer/PdfRendererTest.php b/tests/Invoice/Renderer/PdfRendererTest.php index 172a12bf..5d831065 100644 --- a/tests/Invoice/Renderer/PdfRendererTest.php +++ b/tests/Invoice/Renderer/PdfRendererTest.php @@ -14,7 +14,9 @@ use App\Tests\Mocks\FileHelperFactory; use App\Utils\MPdfConverter; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Twig\Environment; +use Twig\Loader\ArrayLoader; use Twig\Loader\FilesystemLoader; /** @@ -26,10 +28,22 @@ class PdfRendererTest extends KernelTestCase { use RendererTestTrait; + public function testDisposition() + { + $env = new Environment(new ArrayLoader([])); + $sut = new PdfRenderer($env, $this->createMock(MPdfConverter::class)); + $this->assertEquals(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $sut->getDisposition()); + $sut->setDispositionInline(false); + $this->assertEquals(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $sut->getDisposition()); + $sut->setDispositionInline(true); + $this->assertEquals(ResponseHeaderBag::DISPOSITION_INLINE, $sut->getDisposition()); + $sut->setDispositionInline(false); + $this->assertEquals(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $sut->getDisposition()); + } + public function testSupports() { - $loader = new FilesystemLoader(); - $env = new Environment($loader); + $env = new Environment(new ArrayLoader([])); $sut = new PdfRenderer($env, $this->createMock(MPdfConverter::class)); $this->assertTrue($sut->supports($this->getInvoiceDocument('default.pdf.twig', true))); $this->assertTrue($sut->supports($this->getInvoiceDocument('freelancer.pdf.twig')));