From 83782f4d92822958caf998386c5798a188b75a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20=C5=A0korpil?= Date: Tue, 4 Jun 2019 23:37:43 +0200 Subject: [PATCH] Support for nette 3.0 and php 7.3 (#26) * Updated dependencies, migrated to PSR-4, Updated to PHP 7.1 * Updated pdf test output files --- .gitignore | 1 + .travis.yml | 3 +- composer.json | 14 +- .../InvalidArgumentException.php | 0 .../Responses => }/InvalidStateException.php | 0 .../MissingServiceException.php | 0 .../Responses => }/PdfResponse.php | 170 ++++++++++-------- .../PdfResponse/PdfResponse.page.format.phpt | 7 +- tests/PdfResponse/PdfResponse.setters.phpt | 5 +- tests/PdfResponse/expected/full.pdf | Bin 28319 -> 28319 bytes tests/PdfResponse/expected/page.format.pdf | Bin 28309 -> 28309 bytes .../PdfResponse/expected/symfony.crawler.pdf | Bin 28238 -> 28238 bytes 12 files changed, 113 insertions(+), 87 deletions(-) rename src/{Joseki/Application/Responses => }/InvalidArgumentException.php (100%) rename src/{Joseki/Application/Responses => }/InvalidStateException.php (100%) rename src/{Joseki/Application/Responses => }/MissingServiceException.php (100%) rename src/{Joseki/Application/Responses => }/PdfResponse.php (76%) diff --git a/.gitignore b/.gitignore index 49dbaea..5fc020f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /vendor/ /.idea/ /composer.lock +*.iml diff --git a/.travis.yml b/.travis.yml index 41b9c3e..7b96d1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,8 @@ language: php php: - - 5.6 - - 7.0 - 7.1 - 7.2 + - 7.3 matrix: allow_failures: - php: hhvm diff --git a/composer.json b/composer.json index 94fa329..a0ff4cc 100644 --- a/composer.json +++ b/composer.json @@ -15,15 +15,15 @@ } ], "require": { - "php": ">=5.6 || ~7.0.0 || ~7.1.0 || ~7.2.0", - "mpdf/mpdf": "~7.0.0" + "php": "~7.1.0 || ~7.2.0 || ~7.3.0", + "mpdf/mpdf": "~8.0.0" }, "require-dev": { - "nette/application": "~2.2", - "nette/tester": "~2.0", + "nette/application": "~3.0", + "nette/tester": "~2.2", "symfony/dom-crawler": "~2.5", "symfony/css-selector": "~2.5", - "latte/latte": "~2.2" + "latte/latte": "~2.5" }, "extra": { "branch-alias": { @@ -36,6 +36,8 @@ }, "license": "LGPL-3.0", "autoload": { - "classmap": ["src"] + "psr-4": { + "Joseki\\Application\\Responses\\": "src/" + } } } diff --git a/src/Joseki/Application/Responses/InvalidArgumentException.php b/src/InvalidArgumentException.php similarity index 100% rename from src/Joseki/Application/Responses/InvalidArgumentException.php rename to src/InvalidArgumentException.php diff --git a/src/Joseki/Application/Responses/InvalidStateException.php b/src/InvalidStateException.php similarity index 100% rename from src/Joseki/Application/Responses/InvalidStateException.php rename to src/InvalidStateException.php diff --git a/src/Joseki/Application/Responses/MissingServiceException.php b/src/MissingServiceException.php similarity index 100% rename from src/Joseki/Application/Responses/MissingServiceException.php rename to src/MissingServiceException.php diff --git a/src/Joseki/Application/Responses/PdfResponse.php b/src/PdfResponse.php similarity index 76% rename from src/Joseki/Application/Responses/PdfResponse.php rename to src/PdfResponse.php index 0c1bb3c..69160a6 100644 --- a/src/Joseki/Application/Responses/PdfResponse.php +++ b/src/PdfResponse.php @@ -2,14 +2,19 @@ namespace Joseki\Application\Responses; +use Mpdf\HTMLParserMode; use Mpdf\Mpdf; +use Mpdf\MpdfException; +use Mpdf\Output\Destination; use Nette; use Nette\Bridges\ApplicationLatte\Template; use Nette\FileNotFoundException; use Nette\Http\IRequest; use Nette\Http\IResponse; use Nette\Utils\Strings; +use setasign\Fpdi\PdfParser\PdfParserException as PdfParserExceptionAlias; use Symfony\Component\DomCrawler\Crawler; +use Throwable; /** * PdfResponse @@ -109,56 +114,52 @@ class PdfResponse implements Nette\Application\IResponse /** @var string margins: top, right, bottom, left, header, footer */ private $pageMargins = "16,15,16,15,9,9"; - /** @var Mpdf */ + /** @var Mpdf|null */ private $mPDF = null; - /** @var mPDF */ - private $generatedFile; + /** @var Mpdf|null */ + private $generatedFile = null; /************************************ properties **************************************/ /** * @return string */ - public function getDocumentAuthor() + public function getDocumentAuthor(): string { return $this->documentAuthor; } - /** * @param string $documentAuthor */ - public function setDocumentAuthor($documentAuthor) + public function setDocumentAuthor(string $documentAuthor): void { $this->documentAuthor = (string)$documentAuthor; } - /** * @return string */ - public function getDocumentTitle() + public function getDocumentTitle(): string { return $this->documentTitle; } - /** * @param string $documentTitle */ - public function setDocumentTitle($documentTitle) + public function setDocumentTitle(string $documentTitle): void { $this->documentTitle = (string)$documentTitle; } - /** - * @return string + * @return string|int */ public function getDisplayZoom() { @@ -166,22 +167,25 @@ public function getDisplayZoom() } - /** - * @param string $displayZoom + * @param string|int $displayZoom */ - public function setDisplayZoom($displayZoom) + public function setDisplayZoom($displayZoom): void { - if (!in_array($displayZoom, array(self::ZOOM_DEFAULT, self::ZOOM_FULLPAGE, self::ZOOM_FULLWIDTH, self::ZOOM_REAL)) && $displayZoom <= 0) { + if (!in_array($displayZoom, array( + self::ZOOM_DEFAULT, + self::ZOOM_FULLPAGE, + self::ZOOM_FULLWIDTH, + self::ZOOM_REAL + )) && $displayZoom <= 0) { throw new InvalidArgumentException("Invalid zoom '$displayZoom', use PdfResponse::ZOOM_* constants or o positive integer."); } $this->displayZoom = $displayZoom; } - /** - * @return mixed + * @return string */ public function getDisplayLayout() { @@ -189,15 +193,22 @@ public function getDisplayLayout() } - /** - * @param mixed $displayLayout + * @param string $displayLayout + * @throws InvalidArgumentException */ - public function setDisplayLayout($displayLayout) + public function setDisplayLayout(string $displayLayout): void { if (!in_array( $displayLayout, - array(self::LAYOUT_DEFAULT, self::LAYOUT_CONTINUOUS, self::LAYOUT_SINGLE, self::LAYOUT_TWO, self::LAYOUT_TWOLEFT, self::LAYOUT_TWORIGHT) + array( + self::LAYOUT_DEFAULT, + self::LAYOUT_CONTINUOUS, + self::LAYOUT_SINGLE, + self::LAYOUT_TWO, + self::LAYOUT_TWOLEFT, + self::LAYOUT_TWORIGHT + ) ) && $displayLayout <= 0 ) { throw new InvalidArgumentException("Invalid layout '$displayLayout', use PdfResponse::LAYOUT* constants."); @@ -206,57 +217,51 @@ public function setDisplayLayout($displayLayout) } - /** * @return boolean */ - public function isMultiLanguage() + public function isMultiLanguage(): bool { return $this->multiLanguage; } - /** * @param boolean $multiLanguage */ - public function setMultiLanguage($multiLanguage) + public function setMultiLanguage(bool $multiLanguage): void { $this->multiLanguage = (bool)$multiLanguage; } - /** * @return boolean */ - public function isIgnoreStylesInHTMLDocument() + public function isIgnoreStylesInHTMLDocument(): bool { return $this->ignoreStylesInHTMLDocument; } - /** * @param boolean $ignoreStylesInHTMLDocument */ - public function setIgnoreStylesInHTMLDocument($ignoreStylesInHTMLDocument) + public function setIgnoreStylesInHTMLDocument(bool $ignoreStylesInHTMLDocument): void { $this->ignoreStylesInHTMLDocument = (bool)$ignoreStylesInHTMLDocument; } - /** * @return string */ - public function getSaveMode() + public function getSaveMode(): string { return $this->saveMode; } - /** * To force download, use PdfResponse::DOWNLOAD * To show pdf in browser, use PdfResponse::INLINE @@ -264,7 +269,7 @@ public function getSaveMode() * @param string $saveMode * @throws InvalidArgumentException */ - public function setSaveMode($saveMode) + public function setSaveMode(string $saveMode): void { if (!in_array($saveMode, array(self::DOWNLOAD, self::INLINE))) { throw new InvalidArgumentException("Invalid mode '$saveMode', use PdfResponse::INLINE or PdfResponse::DOWNLOAD instead."); @@ -273,23 +278,21 @@ public function setSaveMode($saveMode) } - /** * @return string */ - public function getPageOrientation() + public function getPageOrientation(): string { return $this->pageOrientation; } - /** * @param string $pageOrientation * @throws InvalidStateException * @throws InvalidArgumentException */ - public function setPageOrientation($pageOrientation) + public function setPageOrientation(string $pageOrientation): void { if ($this->mPDF) { throw new InvalidStateException('mPDF instance already created. Set page orientation before calling getMPDF'); @@ -301,22 +304,20 @@ public function setPageOrientation($pageOrientation) } - /** * @return string */ - public function getPageFormat() + public function getPageFormat(): string { return $this->pageFormat; } - /** * @param string $pageFormat * @throws InvalidStateException */ - public function setPageFormat($pageFormat) + public function setPageFormat(string $pageFormat): void { if ($this->mPDF) { throw new InvalidStateException('mPDF instance already created. Set page format before calling getMPDF'); @@ -325,22 +326,20 @@ public function setPageFormat($pageFormat) } - /** * @return string */ - public function getPageMargins() + public function getPageMargins(): string { return $this->pageMargins; } - /** * Gets margins as array * @return array */ - public function getMargins() + public function getMargins(): array { $margins = explode(",", $this->pageMargins); @@ -355,13 +354,12 @@ public function getMargins() } - /** * @param string $pageMargins * @throws InvalidStateException * @throws InvalidArgumentException */ - public function setPageMargins($pageMargins) + public function setPageMargins(string $pageMargins): void { if ($this->mPDF) { throw new InvalidStateException('mPDF instance already created. Set page margins before calling getMPDF'); @@ -383,15 +381,15 @@ public function setPageMargins($pageMargins) } - /** * WARNING: internally creates mPDF instance, setting some properties after calling this method * may cause an Exception * * @param string $pathToBackgroundTemplate * @throws FileNotFoundException + * @throws PdfParserExceptionAlias */ - public function setBackgroundTemplate($pathToBackgroundTemplate) + public function setBackgroundTemplate(string $pathToBackgroundTemplate): void { if (!file_exists($pathToBackgroundTemplate)) { throw new FileNotFoundException("File '$pathToBackgroundTemplate' not found."); @@ -400,10 +398,9 @@ public function setBackgroundTemplate($pathToBackgroundTemplate) // if background exists, then add it as a background $mpdf = $this->getMPDF(); - $mpdf->SetImportUse(); - $pagecount = $mpdf->SetSourceFile($this->backgroundTemplate); + $pagecount = $mpdf->setSourceFile($this->backgroundTemplate); for ($i = 1; $i <= $pagecount; $i++) { - $tplId = $mpdf->ImportPage($i); + $tplId = $mpdf->importPage($i); $mpdf->UseTemplate($tplId); if ($i < $pagecount) { @@ -414,11 +411,10 @@ public function setBackgroundTemplate($pathToBackgroundTemplate) } - /** * @return array */ - protected function getMPDFConfig() + protected function getMPDFConfig(): array { $margins = $this->getMargins(); return [ @@ -435,16 +431,19 @@ protected function getMPDFConfig() } - /** - * @throws InvalidStateException * @return Mpdf + * @throws InvalidStateException */ - public function getMPDF() + public function getMPDF(): Mpdf { if (!$this->mPDF instanceof Mpdf) { - $mpdf = new Mpdf($this->getMPDFConfig()); + try { + $mpdf = new Mpdf($this->getMPDFConfig()); + } catch (MpdfException $e) { + throw new InvalidStateException("Unable to create Mpdf object", 0, $e); + } $mpdf->showImageErrors = true; @@ -483,12 +482,14 @@ public function __construct($source) * Builds final pdf * * @return mPDF - * @throws \Exception + * @throws InvalidStateException + * @throws MissingServiceException + * @throws MpdfException */ - private function build() + private function build(): Mpdf { if (empty($this->documentTitle)) { - throw new \Exception ("Var 'documentTitle' cannot be empty."); + throw new InvalidStateException("Var 'documentTitle' cannot be empty."); } if ($this->ignoreStylesInHTMLDocument) { if (!class_exists('Symfony\Component\DomCrawler\Crawler')) { @@ -508,14 +509,19 @@ private function build() } if ($this->source instanceof Template) { - $html = $this->source->__toString(); + try { + /** @noinspection PhpMethodParametersCountMismatchInspection */ + $html = $this->source->__toString(true); + } catch (Throwable $e) { + throw new InvalidStateException("Template rendering failed", 0, $e); + } } else { $html = $this->source; } // Fix: $html can't be empty (mPDF generates Fatal error) if (empty($html)) { - $html = ''; + $html = ''; } $mpdf = $this->getMPDF(); @@ -526,7 +532,7 @@ private function build() // Add styles if (!empty($this->styles)) { - $mpdf->WriteHTML($this->styles, 1); + $mpdf->WriteHTML($this->styles, HTMLParserMode::HEADER_CSS); } // copied from mPDF -> removes comments @@ -544,9 +550,9 @@ private function build() } $html = $crawler->html(); - $mode = 2; // If tags are found, all html outside these tags are discarded, and the rest is parsed as content for the document. If no tags are found, all html is parsed as content. Prior to mPDF 4.2 the default CSS was not parsed when using mode #2 + $mode = HTMLParserMode::HTML_BODY; // If tags are found, all html outside these tags are discarded, and the rest is parsed as content for the document. If no tags are found, all html is parsed as content. Prior to mPDF 4.2 the default CSS was not parsed when using mode #2 } else { - $mode = 0; // Parse all: HTML + CSS + $mode = HTMLParserMode::DEFAULT_MODE; // Parse all: HTML + CSS } // Add content @@ -569,26 +575,27 @@ private function build() * @param IRequest $httpRequest * @param IResponse $httpResponse * @return void + * @throws MpdfException */ - public function send(IRequest $httpRequest, IResponse $httpResponse) + public function send(IRequest $httpRequest, IResponse $httpResponse): void { $mpdf = $this->build(); $mpdf->Output(Strings::webalize($this->documentTitle) . ".pdf", $this->saveMode); } - /** * Save file to target location * Note: $name overrides property $documentTitle * * @param string $dir path to directory - * @param string $filename + * @param string|null $filename * @return string + * @throws MpdfException */ - public function save($dir, $filename = null) + public function save(string $dir, ?string $filename = null): string { - $content = $this->__toString(); + $content = $this->toString(); $filename = Strings::lower($filename ?: $this->documentTitle); if (Strings::endsWith($filename, ".pdf")) { @@ -603,6 +610,15 @@ public function save($dir, $filename = null) return $dir . $filename; } + /** + * @return string + * @throws MpdfException + */ + public function toString() + { + $pdf = $this->build(); + return $pdf->Output("", Destination::STRING_RETURN); + } /** @@ -612,8 +628,14 @@ public function save($dir, $filename = null) */ public function __toString() { - $pdf = $this->build(); - return $pdf->Output("", "S"); + $string = ""; + try { + $string = $this->toString(); + } catch (MpdfException $e) { + trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", + E_USER_ERROR); + } + return $string; } } diff --git a/tests/PdfResponse/PdfResponse.page.format.phpt b/tests/PdfResponse/PdfResponse.page.format.phpt index cd766ef..e872e0c 100644 --- a/tests/PdfResponse/PdfResponse.page.format.phpt +++ b/tests/PdfResponse/PdfResponse.page.format.phpt @@ -6,6 +6,7 @@ */ use Joseki\Application\Responses\PdfResponse; +use Joseki\Application\Responses\InvalidStateException; use Nette\Http; use Tester\Assert; @@ -41,7 +42,7 @@ test( function () use ($fileResponse) { $fileResponse->pageOrientation = PdfResponse::ORIENTATION_LANDSCAPE; }, - 'Joseki\Application\Responses\InvalidStateException', + InvalidStateException::class, 'mPDF instance already created. Set page orientation before calling getMPDF' ); } @@ -56,7 +57,7 @@ test( function () use ($fileResponse) { $fileResponse->pageFormat = 'A4-L'; }, - 'Joseki\Application\Responses\InvalidStateException', + InvalidStateException::class, 'mPDF instance already created. Set page format before calling getMPDF' ); } @@ -71,7 +72,7 @@ test( function () use ($fileResponse) { $fileResponse->pageMargins = $fileResponse->getPageMargins(); }, - 'Joseki\Application\Responses\InvalidStateException', + InvalidStateException::class, 'mPDF instance already created. Set page margins before calling getMPDF' ); } diff --git a/tests/PdfResponse/PdfResponse.setters.phpt b/tests/PdfResponse/PdfResponse.setters.phpt index 3ca08cd..c40ccd2 100644 --- a/tests/PdfResponse/PdfResponse.setters.phpt +++ b/tests/PdfResponse/PdfResponse.setters.phpt @@ -5,6 +5,7 @@ */ use Joseki\Application\Responses\PdfResponse; +use Joseki\Application\Responses\InvalidArgumentException; use Tester\Assert; require __DIR__ . '/../bootstrap.php'; @@ -21,7 +22,7 @@ test( function () use ($fileResponse) { $fileResponse->displayZoom = "invalid"; }, - 'Joseki\Application\Responses\InvalidArgumentException' + InvalidArgumentException::class ); // layout @@ -30,7 +31,7 @@ test( function () use ($fileResponse) { $fileResponse->displayLayout = "invalid"; }, - 'Joseki\Application\Responses\InvalidArgumentException' + InvalidArgumentException::class ); } ); diff --git a/tests/PdfResponse/expected/full.pdf b/tests/PdfResponse/expected/full.pdf index c3ede8d31c32adf4f0cf6fb572a654526ef1ef7a..1f7848d2c55f040a94ad8c804812c86f8e60a510 100644 GIT binary patch delta 24 dcmbP#mvR1G#tl2NIV~9U7z{vo^TF(UOaOFD2#Npz delta 24 ecmbP#mvR1G#tl2NIn5dL7z}{ec=N&RdrSayPza0w diff --git a/tests/PdfResponse/expected/page.format.pdf b/tests/PdfResponse/expected/page.format.pdf index 22283b32eb3ccecf78f51310f1ce2768979f4c91..5b68185a11a6916c7c2b1ec5926c5f91186658cd 100644 GIT binary patch delta 24 dcmbPwmvQP{#trMTIV~9U7z{vo^Y-j}OaO7X2x0&L delta 24 ecmbPwmvQP{#trMTIn5dL7z}{ec=Pt`drSavya;3f diff --git a/tests/PdfResponse/expected/symfony.crawler.pdf b/tests/PdfResponse/expected/symfony.crawler.pdf index a724abbea5ae6397a2b841c9102a06bdcc80d51c..3b2f9790121e2772b4b17a47091af7ad74d17dc2 100644 GIT binary patch delta 24 dcmX?ihw