From df33b38b6348ba96e2bf2207d7b0ca6ce3e506f4 Mon Sep 17 00:00:00 2001 From: codemasher Date: Wed, 4 Dec 2019 22:31:05 +0100 Subject: [PATCH] :octocat: allow overriding data mode detection --- src/QRCode.php | 14 ++++++++++++-- src/QROptions.php | 1 + src/QROptionsTrait.php | 32 +++++++++++++++++++++----------- tests/QRCodeTest.php | 28 +++++++++++++++++++++++++++- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/QRCode.php b/src/QRCode.php index 4923c8b62..790736927 100755 --- a/src/QRCode.php +++ b/src/QRCode.php @@ -197,9 +197,19 @@ class QRCode{ * @throws \chillerlan\QRCode\Data\QRCodeDataException */ public function initDataInterface(string $data):QRDataInterface{ + $dataModes = ['Number', 'AlphaNum', 'Kanji', 'Byte']; + $dataNamespace = __NAMESPACE__.'\\Data\\'; - foreach(['Number', 'AlphaNum', 'Kanji', 'Byte'] as $mode){ - $dataInterface = __NAMESPACE__.'\\Data\\'.$mode; + // allow forcing the data mode + // see https://github.com/chillerlan/php-qrcode/issues/39 + if(in_array($this->options->dataMode, $dataModes, true)){ + $dataInterface = $dataNamespace.$this->options->dataMode; + + return new $dataInterface($this->options, $data); + } + + foreach($dataModes as $mode){ + $dataInterface = $dataNamespace.$mode; if(call_user_func_array([$this, 'is'.$mode], [$data]) && class_exists($dataInterface)){ return new $dataInterface($this->options, $data); diff --git a/src/QROptions.php b/src/QROptions.php index bb6f186e0..9a8b03d9c 100644 --- a/src/QROptions.php +++ b/src/QROptions.php @@ -23,6 +23,7 @@ use chillerlan\Settings\SettingsContainerAbstract; * @property bool $addQuietzone * @property bool $quietzoneSize * + * @property string $dataMode * @property string $outputType * @property string $outputInterface * @property string $cachefile diff --git a/src/QROptionsTrait.php b/src/QROptionsTrait.php index 40d935feb..4d4f84497 100644 --- a/src/QROptionsTrait.php +++ b/src/QROptionsTrait.php @@ -77,6 +77,16 @@ trait QROptionsTrait{ */ protected $quietzoneSize = 4; + /** + * Use this to circumvent the data mode detection and force the usage of the given mode. + * valid modes are: Number, AlphaNum, Kanji, Byte + * + * @see https://github.com/chillerlan/php-qrcode/issues/39 + * + * @var string|null + */ + protected $dataMode = null; + /** * QRCode::OUTPUT_MARKUP_XXXX where XXXX = HTML, SVG * QRCode::OUTPUT_IMAGE_XXX where XXX = PNG, GIF, JPG @@ -90,16 +100,16 @@ trait QROptionsTrait{ /** * the FQCN of the custom QROutputInterface if $outputType is set to QRCode::OUTPUT_CUSTOM * - * @var string + * @var string|null */ - protected $outputInterface; + protected $outputInterface = null; /** * /path/to/cache.file * - * @var string + * @var string|null */ - protected $cachefile; + protected $cachefile = null; /** * newline string [HTML, SVG, TEXT] @@ -121,7 +131,7 @@ trait QROptionsTrait{ * * @var string */ - protected $cssClass; + protected $cssClass = ''; /** * SVG opacity @@ -146,9 +156,9 @@ trait QROptionsTrait{ * * @see https://css-tricks.com/scale-svg/#article-header-id-3 * - * @var int + * @var int|null */ - protected $svgViewBoxSize; + protected $svgViewBoxSize = null; /** * string substitute for dark @@ -227,9 +237,9 @@ trait QROptionsTrait{ * * @see \ImagickPixel::__construct() * - * @var string + * @var string|null */ - protected $imagickBG; + protected $imagickBG = null; /** * Module values map @@ -237,9 +247,9 @@ trait QROptionsTrait{ * HTML, IMAGICK: #ABCDEF, cssname, rgb(), rgba()... * IMAGE: [63, 127, 255] // R, G, B * - * @var array + * @var array|null */ - protected $moduleValues; + protected $moduleValues = null; /** * clamp min/max version number diff --git a/tests/QRCodeTest.php b/tests/QRCodeTest.php index ce311edf5..452cfacba 100755 --- a/tests/QRCodeTest.php +++ b/tests/QRCodeTest.php @@ -13,10 +13,12 @@ namespace chillerlan\QRCodeTest; use chillerlan\QRCode\{QROptions, QRCode}; -use chillerlan\QRCode\Data\QRCodeDataException; +use chillerlan\QRCode\Data\{AlphaNum, Byte, Number, QRCodeDataException}; use chillerlan\QRCode\Output\QRCodeOutputException; use chillerlan\QRCodeExamples\MyCustomOutput; +use function random_bytes; + class QRCodeTest extends QRTestAbstract{ protected $FQCN = QRCode::class; @@ -111,4 +113,28 @@ class QRCodeTest extends QRTestAbstract{ $this->assertSame($expected, $this->reflection->newInstanceArgs([$options])->render('test')); } + + public function testDataModeOverride(){ + $this->qrcode = $this->reflection->newInstance(); + + $this->assertInstanceOf(Number::class, $this->qrcode->initDataInterface('123')); + $this->assertInstanceOf(AlphaNum::class, $this->qrcode->initDataInterface('ABC123')); + $this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface(random_bytes(32))); + + $this->qrcode = $this->reflection->newInstanceArgs([new QROptions(['dataMode' => 'Byte'])]); + + $this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface('123')); + $this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface('ABC123')); + $this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface(random_bytes(32))); + } + + public function testDataModeOverrideError(){ + $this->expectException(QRCodeDataException::class); + $this->expectExceptionMessage('illegal char:'); + + $this->qrcode = $this->reflection->newInstanceArgs([new QROptions(['dataMode' => 'AlphaNum'])]); + + $this->qrcode->initDataInterface(random_bytes(32)); + } + }