Skip to content

Commit df33b38

Browse files
committed
:octocat: allow overriding data mode detection
1 parent c5da58e commit df33b38

File tree

4 files changed

+61
-14
lines changed

4 files changed

+61
-14
lines changed

src/QRCode.php

+12-2
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,19 @@ protected function getBestMaskPattern():int{
197197
* @throws \chillerlan\QRCode\Data\QRCodeDataException
198198
*/
199199
public function initDataInterface(string $data):QRDataInterface{
200+
$dataModes = ['Number', 'AlphaNum', 'Kanji', 'Byte'];
201+
$dataNamespace = __NAMESPACE__.'\\Data\\';
200202

201-
foreach(['Number', 'AlphaNum', 'Kanji', 'Byte'] as $mode){
202-
$dataInterface = __NAMESPACE__.'\\Data\\'.$mode;
203+
// allow forcing the data mode
204+
// see https://github.com/chillerlan/php-qrcode/issues/39
205+
if(in_array($this->options->dataMode, $dataModes, true)){
206+
$dataInterface = $dataNamespace.$this->options->dataMode;
207+
208+
return new $dataInterface($this->options, $data);
209+
}
210+
211+
foreach($dataModes as $mode){
212+
$dataInterface = $dataNamespace.$mode;
203213

204214
if(call_user_func_array([$this, 'is'.$mode], [$data]) && class_exists($dataInterface)){
205215
return new $dataInterface($this->options, $data);

src/QROptions.php

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
* @property bool $addQuietzone
2424
* @property bool $quietzoneSize
2525
*
26+
* @property string $dataMode
2627
* @property string $outputType
2728
* @property string $outputInterface
2829
* @property string $cachefile

src/QROptionsTrait.php

+21-11
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ trait QROptionsTrait{
7777
*/
7878
protected $quietzoneSize = 4;
7979

80+
/**
81+
* Use this to circumvent the data mode detection and force the usage of the given mode.
82+
* valid modes are: Number, AlphaNum, Kanji, Byte
83+
*
84+
* @see https://github.com/chillerlan/php-qrcode/issues/39
85+
*
86+
* @var string|null
87+
*/
88+
protected $dataMode = null;
89+
8090
/**
8191
* QRCode::OUTPUT_MARKUP_XXXX where XXXX = HTML, SVG
8292
* QRCode::OUTPUT_IMAGE_XXX where XXX = PNG, GIF, JPG
@@ -90,16 +100,16 @@ trait QROptionsTrait{
90100
/**
91101
* the FQCN of the custom QROutputInterface if $outputType is set to QRCode::OUTPUT_CUSTOM
92102
*
93-
* @var string
103+
* @var string|null
94104
*/
95-
protected $outputInterface;
105+
protected $outputInterface = null;
96106

97107
/**
98108
* /path/to/cache.file
99109
*
100-
* @var string
110+
* @var string|null
101111
*/
102-
protected $cachefile;
112+
protected $cachefile = null;
103113

104114
/**
105115
* newline string [HTML, SVG, TEXT]
@@ -121,7 +131,7 @@ trait QROptionsTrait{
121131
*
122132
* @var string
123133
*/
124-
protected $cssClass;
134+
protected $cssClass = '';
125135

126136
/**
127137
* SVG opacity
@@ -146,9 +156,9 @@ trait QROptionsTrait{
146156
*
147157
* @see https://css-tricks.com/scale-svg/#article-header-id-3
148158
*
149-
* @var int
159+
* @var int|null
150160
*/
151-
protected $svgViewBoxSize;
161+
protected $svgViewBoxSize = null;
152162

153163
/**
154164
* string substitute for dark
@@ -227,19 +237,19 @@ trait QROptionsTrait{
227237
*
228238
* @see \ImagickPixel::__construct()
229239
*
230-
* @var string
240+
* @var string|null
231241
*/
232-
protected $imagickBG;
242+
protected $imagickBG = null;
233243

234244
/**
235245
* Module values map
236246
*
237247
* HTML, IMAGICK: #ABCDEF, cssname, rgb(), rgba()...
238248
* IMAGE: [63, 127, 255] // R, G, B
239249
*
240-
* @var array
250+
* @var array|null
241251
*/
242-
protected $moduleValues;
252+
protected $moduleValues = null;
243253

244254
/**
245255
* clamp min/max version number

tests/QRCodeTest.php

+27-1
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
namespace chillerlan\QRCodeTest;
1414

1515
use chillerlan\QRCode\{QROptions, QRCode};
16-
use chillerlan\QRCode\Data\QRCodeDataException;
16+
use chillerlan\QRCode\Data\{AlphaNum, Byte, Number, QRCodeDataException};
1717
use chillerlan\QRCode\Output\QRCodeOutputException;
1818
use chillerlan\QRCodeExamples\MyCustomOutput;
1919

20+
use function random_bytes;
21+
2022
class QRCodeTest extends QRTestAbstract{
2123

2224
protected $FQCN = QRCode::class;
@@ -111,4 +113,28 @@ public function testCustomOutput(){
111113

112114
$this->assertSame($expected, $this->reflection->newInstanceArgs([$options])->render('test'));
113115
}
116+
117+
public function testDataModeOverride(){
118+
$this->qrcode = $this->reflection->newInstance();
119+
120+
$this->assertInstanceOf(Number::class, $this->qrcode->initDataInterface('123'));
121+
$this->assertInstanceOf(AlphaNum::class, $this->qrcode->initDataInterface('ABC123'));
122+
$this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface(random_bytes(32)));
123+
124+
$this->qrcode = $this->reflection->newInstanceArgs([new QROptions(['dataMode' => 'Byte'])]);
125+
126+
$this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface('123'));
127+
$this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface('ABC123'));
128+
$this->assertInstanceOf(Byte::class, $this->qrcode->initDataInterface(random_bytes(32)));
129+
}
130+
131+
public function testDataModeOverrideError(){
132+
$this->expectException(QRCodeDataException::class);
133+
$this->expectExceptionMessage('illegal char:');
134+
135+
$this->qrcode = $this->reflection->newInstanceArgs([new QROptions(['dataMode' => 'AlphaNum'])]);
136+
137+
$this->qrcode->initDataInterface(random_bytes(32));
138+
}
139+
114140
}

0 commit comments

Comments
 (0)