Просмотр исходного кода

:octocat: allow overriding data mode detection

codemasher 6 лет назад
Родитель
Сommit
df33b38b63
4 измененных файлов с 61 добавлено и 14 удалено
  1. 12 2
      src/QRCode.php
  2. 1 0
      src/QROptions.php
  3. 21 11
      src/QROptionsTrait.php
  4. 27 1
      tests/QRCodeTest.php

+ 12 - 2
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);

+ 1 - 0
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

+ 21 - 11
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

+ 27 - 1
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));
+	}
+
 }