diff --git a/examples/imageWithLogo.php b/examples/imageWithLogo.php index 201d8ea8e..f86d901e3 100644 --- a/examples/imageWithLogo.php +++ b/examples/imageWithLogo.php @@ -59,9 +59,7 @@ class QRImageWithLogo extends QRGdImage{ $imageData = $this->dumpImage(); - if($file !== null){ - $this->saveToFile($imageData, $file); - } + $this->saveToFile($imageData, $file); if($this->options->imageBase64){ $imageData = $this->toBase64DataURI($imageData, 'image/'.$this->options->outputType); diff --git a/examples/imageWithText.php b/examples/imageWithText.php index c32a66965..2f9c740af 100644 --- a/examples/imageWithText.php +++ b/examples/imageWithText.php @@ -39,9 +39,7 @@ class QRImageWithText extends QRGdImage{ $imageData = $this->dumpImage(); - if($file !== null){ - $this->saveToFile($imageData, $file); - } + $this->saveToFile($imageData, $file); if($this->options->imageBase64){ $imageData = $this->toBase64DataURI($imageData, 'image/'.$this->options->outputType); diff --git a/src/Output/QREps.php b/src/Output/QREps.php index 2c0145c41..39880645e 100644 --- a/src/Output/QREps.php +++ b/src/Output/QREps.php @@ -66,7 +66,6 @@ class QREps extends QROutputAbstract{ * @inheritDoc */ public function dump(string $file = null):string{ - $file ??= $this->options->cachefile; $eps = [ // main header @@ -103,9 +102,7 @@ class QREps extends QROutputAbstract{ $data = implode("\n", $eps); - if($file !== null){ - $this->saveToFile($data, $file); - } + $this->saveToFile($data, $file); return $data; } diff --git a/src/Output/QRFpdf.php b/src/Output/QRFpdf.php index 09d201e36..8273b3493 100644 --- a/src/Output/QRFpdf.php +++ b/src/Output/QRFpdf.php @@ -90,7 +90,6 @@ class QRFpdf extends QROutputAbstract{ * @return string|\FPDF */ public function dump(string $file = null){ - $file ??= $this->options->cachefile; $fpdf = new FPDF('P', $this->options->fpdfMeasureUnit, [$this->length, $this->length]); $fpdf->AddPage(); @@ -132,9 +131,7 @@ class QRFpdf extends QROutputAbstract{ $pdfData = $fpdf->Output('S'); - if($file !== null){ - $this->saveToFile($pdfData, $file); - } + $this->saveToFile($pdfData, $file); if($this->options->imageBase64){ $pdfData = $this->toBase64DataURI($pdfData, 'application/pdf'); diff --git a/src/Output/QRGdImage.php b/src/Output/QRGdImage.php index 8febc8cc4..08b522a68 100644 --- a/src/Output/QRGdImage.php +++ b/src/Output/QRGdImage.php @@ -104,8 +104,6 @@ class QRGdImage extends QROutputAbstract{ throw new ErrorException($msg, 0, $severity, $file, $line); }); - $file ??= $this->options->cachefile; - // we're scaling the image up in order to draw crisp round circles, otherwise they appear square-y on small scales if($this->options->drawCircularModules && $this->options->scale <= 20){ $this->length = ($this->length + 2) * 10; @@ -156,9 +154,7 @@ class QRGdImage extends QROutputAbstract{ $imageData = $this->dumpImage(); - if($file !== null){ - $this->saveToFile($imageData, $file); - } + $this->saveToFile($imageData, $file); if($this->options->imageBase64){ $imageData = $this->toBase64DataURI($imageData, 'image/'.$this->options->outputType); diff --git a/src/Output/QRImagick.php b/src/Output/QRImagick.php index 7a6bf30c6..2b66a60cd 100644 --- a/src/Output/QRImagick.php +++ b/src/Output/QRImagick.php @@ -70,7 +70,6 @@ class QRImagick extends QROutputAbstract{ * @return string|\Imagick */ public function dump(string $file = null){ - $file ??= $this->options->cachefile; $this->imagick = new Imagick; $bgColor = $this->options->imageTransparent ? 'transparent' : 'white'; @@ -92,9 +91,7 @@ class QRImagick extends QROutputAbstract{ $this->imagick->destroy(); - if($file !== null){ - $this->saveToFile($imageData, $file); - } + $this->saveToFile($imageData, $file); return $imageData; } diff --git a/src/Output/QRMarkup.php b/src/Output/QRMarkup.php index ed61a7a77..d25ccbc20 100644 --- a/src/Output/QRMarkup.php +++ b/src/Output/QRMarkup.php @@ -42,14 +42,9 @@ abstract class QRMarkup extends QROutputAbstract{ * @inheritDoc */ public function dump(string $file = null):string{ - $file ??= $this->options->cachefile; - $saveToFile = $file !== null; + $data = $this->createMarkup($file !== null); - $data = $this->createMarkup($saveToFile); - - if($saveToFile){ - $this->saveToFile($data, $file); - } + $this->saveToFile($data, $file); return $data; } diff --git a/src/Output/QROutputAbstract.php b/src/Output/QROutputAbstract.php index 985d59829..cc6541ddf 100644 --- a/src/Output/QROutputAbstract.php +++ b/src/Output/QROutputAbstract.php @@ -122,14 +122,18 @@ abstract class QROutputAbstract implements QROutputInterface{ } /** - * saves the qr data to a file + * Saves the qr $data to a $file. If $file is null, nothing happens. * * @see file_put_contents() - * @see \chillerlan\QRCode\QROptions::cachefile + * @see \chillerlan\QRCode\QROptions::$cachefile * * @throws \chillerlan\QRCode\Output\QRCodeOutputException */ - protected function saveToFile(string $data, string $file):void{ + protected function saveToFile(string $data, string $file = null):void{ + + if($file === null){ + return; + } if(!is_writable(dirname($file))){ throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s', $file)); diff --git a/src/Output/QROutputInterface.php b/src/Output/QROutputInterface.php index dae431b7f..5ad23990c 100644 --- a/src/Output/QROutputInterface.php +++ b/src/Output/QROutputInterface.php @@ -89,6 +89,12 @@ interface QROutputInterface{ /** * generates the output, optionally dumps it to a file, and returns it * + * please note that the value of QROptions::$cachefile is already evaluated at this point. + * if the output module is invoked manually, it has no effect at all. + * you need to supply the $file parameter here in that case (or handle the option value in your custom output module). + * + * @see \chillerlan\QRCode\QRCode::renderMatrix() + * * @return mixed */ public function dump(string $file = null); diff --git a/src/Output/QRString.php b/src/Output/QRString.php index efb335d26..7ffc655da 100644 --- a/src/Output/QRString.php +++ b/src/Output/QRString.php @@ -45,7 +45,6 @@ class QRString extends QROutputAbstract{ * @inheritDoc */ public function dump(string $file = null):string{ - $file ??= $this->options->cachefile; switch($this->options->outputType){ case QROutputInterface::STRING_TEXT: @@ -56,9 +55,7 @@ class QRString extends QROutputAbstract{ $data = $this->json(); } - if($file !== null){ - $this->saveToFile($data, $file); - } + $this->saveToFile($data, $file); return $data; } diff --git a/src/QRCode.php b/src/QRCode.php index f027cadf3..b30c8ee1b 100755 --- a/src/QRCode.php +++ b/src/QRCode.php @@ -223,7 +223,7 @@ class QRCode{ * @return mixed */ public function renderMatrix(QRMatrix $matrix, string $file = null){ - return $this->initOutputInterface($matrix)->dump($file); + return $this->initOutputInterface($matrix)->dump($file ?? $this->options->cachefile); } /** @@ -284,6 +284,7 @@ class QRCode{ if(!in_array(QROutputInterface::class, class_implements($outputInterface))){ throw new QRCodeOutputException('output module does not implement QROutputInterface'); } + return new $outputInterface($this->options, $matrix); } diff --git a/src/QROptionsTrait.php b/src/QROptionsTrait.php index cf6bd6dd0..88f24bce3 100644 --- a/src/QROptionsTrait.php +++ b/src/QROptionsTrait.php @@ -93,6 +93,8 @@ trait QROptionsTrait{ /** * /path/to/cache.file + * + * please note that the $file parameter in QRCode::render*() takes precedence over the $cachefile value */ protected ?string $cachefile = null; diff --git a/tests/Output/QROutputTestAbstract.php b/tests/Output/QROutputTestAbstract.php index 49b4ae72e..a8c3b6b7a 100644 --- a/tests/Output/QROutputTestAbstract.php +++ b/tests/Output/QROutputTestAbstract.php @@ -63,9 +63,8 @@ abstract class QROutputTestAbstract extends TestCase{ $this->expectException(QRCodeOutputException::class); $this->expectExceptionMessage('Cannot write data to cache file: /foo/bar.test'); - $this->options->cachefile = '/foo/bar.test'; $this->outputInterface = new $this->FQN($this->options, $this->matrix); - $this->outputInterface->dump(); + $this->outputInterface->dump('/foo/bar.test'); } /** @@ -81,12 +80,13 @@ abstract class QROutputTestAbstract extends TestCase{ * coverage of the built-in output modules */ public function testRenderToCacheFile():void{ - $this->options->cachefile = $this->builddir.'/test.'.$this->type; $this->options->imageBase64 = false; $this->outputInterface = new $this->FQN($this->options, $this->matrix); - $data = $this->outputInterface->dump(); // creates the cache file + // create the cache file + $file = $this->builddir.'/test.output.'.$this->type; + $data = $this->outputInterface->dump($file); - $this::assertSame($data, file_get_contents($this->options->cachefile)); + $this::assertSame($data, file_get_contents($file)); } } diff --git a/tests/QRCodeTest.php b/tests/QRCodeTest.php index 9bcd3860d..eadee5fb2 100755 --- a/tests/QRCodeTest.php +++ b/tests/QRCodeTest.php @@ -14,6 +14,7 @@ use chillerlan\QRCode\{QROptions, QRCode}; use chillerlan\QRCode\Output\{QRCodeOutputException, QROutputInterface}; use PHPUnit\Framework\TestCase; use stdClass; +use function file_get_contents; /** * Tests basic functions of the QRCode class @@ -22,6 +23,7 @@ final class QRCodeTest extends TestCase{ private QRCode $qrcode; private QROptions $options; + private string $builddir = __DIR__.'/../.build/output_test'; /** * invoke test instances @@ -68,4 +70,28 @@ final class QRCodeTest extends TestCase{ $this->qrcode->setOptions($this->options)->render('test'); } + /** + * Tests if an exception is thrown when trying to write a cache file to an invalid destination + */ + public function testSaveException():void{ + $this->expectException(QRCodeOutputException::class); + $this->expectExceptionMessage('Cannot write data to cache file: /foo/bar.test'); + + $this->options->cachefile = '/foo/bar.test'; + + $this->qrcode->setOptions($this->options)->render('test'); + } + + /** + * Tests if a cache file is properly saved in the given path + */ + public function testRenderToCacheFile():void{ + $this->options->cachefile = $this->builddir.'/test.cache.svg'; + $this->options->imageBase64 = false; + // create the cache file + $data = $this->qrcode->setOptions($this->options)->render('test'); + + $this::assertSame($data, file_get_contents($this->options->cachefile)); + } + }