mirror of
https://github.com/shlinkio/shlink.git
synced 2025-03-14 04:00:57 +03:00
Merge pull request #1250 from acelaya-forks/feature/qr-round-block-size
Feature/qr round block size
This commit is contained in:
commit
d8735e6a91
10 changed files with 89 additions and 5 deletions
|
@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this
|
|||
### Added
|
||||
* [#1204](https://github.com/shlinkio/shlink/issues/1204) Added support for `openswoole` and migrated official docker image to `openswoole`.
|
||||
* [#1242](https://github.com/shlinkio/shlink/issues/1242) Added support to import urls and visits from YOURLS.
|
||||
* [#1235](https://github.com/shlinkio/shlink/issues/1235) Added support to disable rounding QR codes block sizing via config option, env var or query param.
|
||||
|
||||
### Changed
|
||||
* [#1218](https://github.com/shlinkio/shlink/issues/1218) Updated to symfony/mercure 0.6.
|
||||
|
|
|
@ -47,11 +47,11 @@
|
|||
"pugx/shortid-php": "^0.7",
|
||||
"ramsey/uuid": "^3.9",
|
||||
"rlanvin/php-ip": "3.0.0-rc2",
|
||||
"shlinkio/shlink-common": "dev-main#2f3ac05 as 4.2",
|
||||
"shlinkio/shlink-common": "dev-main#7cc36a6 as 4.2",
|
||||
"shlinkio/shlink-config": "^1.4",
|
||||
"shlinkio/shlink-event-dispatcher": "dev-main#3925299 as 2.3",
|
||||
"shlinkio/shlink-importer": "dev-main#d099072 as 2.5",
|
||||
"shlinkio/shlink-installer": "dev-develop#e3f2e64 as 6.3",
|
||||
"shlinkio/shlink-installer": "dev-develop#7dd00fb as 6.3",
|
||||
"shlinkio/shlink-ip-geolocation": "^2.2",
|
||||
"symfony/console": "^5.4",
|
||||
"symfony/filesystem": "^5.4",
|
||||
|
|
|
@ -56,6 +56,7 @@ return [
|
|||
Option\QrCode\DefaultMarginConfigOption::class,
|
||||
Option\QrCode\DefaultFormatConfigOption::class,
|
||||
Option\QrCode\DefaultErrorCorrectionConfigOption::class,
|
||||
Option\QrCode\DefaultRoundBlockSizeConfigOption::class,
|
||||
],
|
||||
|
||||
'installation_commands' => [
|
||||
|
|
|
@ -7,6 +7,7 @@ use function Shlinkio\Shlink\Common\env;
|
|||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_ERROR_CORRECTION;
|
||||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_FORMAT;
|
||||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_MARGIN;
|
||||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_ROUND_BLOCK_SIZE;
|
||||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_SIZE;
|
||||
|
||||
return [
|
||||
|
@ -16,6 +17,7 @@ return [
|
|||
'margin' => (int) env('DEFAULT_QR_CODE_MARGIN', DEFAULT_QR_CODE_MARGIN),
|
||||
'format' => env('DEFAULT_QR_CODE_FORMAT', DEFAULT_QR_CODE_FORMAT),
|
||||
'error_correction' => env('DEFAULT_QR_CODE_ERROR_CORRECTION', DEFAULT_QR_CODE_ERROR_CORRECTION),
|
||||
'round_block_size' => (bool) env('DEFAULT_QR_CODE_ROUND_BLOCK_SIZE', DEFAULT_QR_CODE_ROUND_BLOCK_SIZE),
|
||||
],
|
||||
|
||||
];
|
||||
|
|
|
@ -13,11 +13,17 @@ use Mezzio\Swoole;
|
|||
use function class_exists;
|
||||
use function Shlinkio\Shlink\Common\env;
|
||||
|
||||
use const PHP_SAPI;
|
||||
|
||||
$isCli = PHP_SAPI === 'cli';
|
||||
|
||||
return (new ConfigAggregator\ConfigAggregator([
|
||||
Mezzio\ConfigProvider::class,
|
||||
Mezzio\Router\ConfigProvider::class,
|
||||
Mezzio\Router\FastRouteRouter\ConfigProvider::class,
|
||||
class_exists(Swoole\ConfigProvider::class) ? Swoole\ConfigProvider::class : new ConfigAggregator\ArrayProvider([]),
|
||||
$isCli && class_exists(Swoole\ConfigProvider::class)
|
||||
? Swoole\ConfigProvider::class
|
||||
: new ConfigAggregator\ArrayProvider([]),
|
||||
ProblemDetails\ConfigProvider::class,
|
||||
Diactoros\ConfigProvider::class,
|
||||
Common\ConfigProvider::class,
|
||||
|
|
|
@ -18,4 +18,5 @@ const DEFAULT_QR_CODE_SIZE = 300;
|
|||
const DEFAULT_QR_CODE_MARGIN = 0;
|
||||
const DEFAULT_QR_CODE_FORMAT = 'png';
|
||||
const DEFAULT_QR_CODE_ERROR_CORRECTION = 'l';
|
||||
const DEFAULT_QR_CODE_ROUND_BLOCK_SIZE = true;
|
||||
const MIN_TASK_WORKERS = 4;
|
||||
|
|
|
@ -9,6 +9,9 @@ use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelInterface;
|
|||
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelLow;
|
||||
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelMedium;
|
||||
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelQuartile;
|
||||
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeInterface;
|
||||
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin;
|
||||
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeNone;
|
||||
use Endroid\QrCode\Writer\PngWriter;
|
||||
use Endroid\QrCode\Writer\SvgWriter;
|
||||
use Endroid\QrCode\Writer\WriterInterface;
|
||||
|
@ -31,6 +34,7 @@ final class QrCodeParams
|
|||
private int $margin,
|
||||
private WriterInterface $writer,
|
||||
private ErrorCorrectionLevelInterface $errorCorrectionLevel,
|
||||
private RoundBlockSizeModeInterface $roundBlockSizeMode,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@ -43,6 +47,7 @@ final class QrCodeParams
|
|||
self::resolveMargin($query, $defaults),
|
||||
self::resolveWriter($query, $defaults),
|
||||
self::resolveErrorCorrection($query, $defaults),
|
||||
self::resolveRoundBlockSize($query, $defaults),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -90,6 +95,14 @@ final class QrCodeParams
|
|||
};
|
||||
}
|
||||
|
||||
private static function resolveRoundBlockSize(array $query, QrCodeOptions $defaults): RoundBlockSizeModeInterface
|
||||
{
|
||||
$doNotRoundBlockSize = isset($query['roundBlockSize'])
|
||||
? $query['roundBlockSize'] === 'false'
|
||||
: ! $defaults->roundBlockSize();
|
||||
return $doNotRoundBlockSize ? new RoundBlockSizeModeNone() : new RoundBlockSizeModeMargin();
|
||||
}
|
||||
|
||||
private static function normalizeParam(string $param): string
|
||||
{
|
||||
return strtolower(trim($param));
|
||||
|
@ -114,4 +127,9 @@ final class QrCodeParams
|
|||
{
|
||||
return $this->errorCorrectionLevel;
|
||||
}
|
||||
|
||||
public function roundBlockSizeMode(): RoundBlockSizeModeInterface
|
||||
{
|
||||
return $this->roundBlockSizeMode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,8 @@ class QrCodeAction implements MiddlewareInterface
|
|||
->size($params->size())
|
||||
->margin($params->margin())
|
||||
->writer($params->writer())
|
||||
->errorCorrectionLevel($params->errorCorrectionLevel());
|
||||
->errorCorrectionLevel($params->errorCorrectionLevel())
|
||||
->roundBlockSizeMode($params->roundBlockSizeMode());
|
||||
|
||||
return new QrCodeResponse($qrCodeBuilder->build());
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use Laminas\Stdlib\AbstractOptions;
|
|||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_ERROR_CORRECTION;
|
||||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_FORMAT;
|
||||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_MARGIN;
|
||||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_ROUND_BLOCK_SIZE;
|
||||
use const Shlinkio\Shlink\DEFAULT_QR_CODE_SIZE;
|
||||
|
||||
class QrCodeOptions extends AbstractOptions
|
||||
|
@ -17,6 +18,7 @@ class QrCodeOptions extends AbstractOptions
|
|||
private int $margin = DEFAULT_QR_CODE_MARGIN;
|
||||
private string $format = DEFAULT_QR_CODE_FORMAT;
|
||||
private string $errorCorrection = DEFAULT_QR_CODE_ERROR_CORRECTION;
|
||||
private bool $roundBlockSize = DEFAULT_QR_CODE_ROUND_BLOCK_SIZE;
|
||||
|
||||
public function size(): int
|
||||
{
|
||||
|
@ -57,4 +59,14 @@ class QrCodeOptions extends AbstractOptions
|
|||
{
|
||||
$this->errorCorrection = $errorCorrection;
|
||||
}
|
||||
|
||||
public function roundBlockSize(): bool
|
||||
{
|
||||
return $this->roundBlockSize;
|
||||
}
|
||||
|
||||
protected function setRoundBlockSize(bool $roundBlockSize): void
|
||||
{
|
||||
$this->roundBlockSize = $roundBlockSize;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,16 @@ use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
|||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifier;
|
||||
|
||||
use function getimagesizefromstring;
|
||||
use function imagecolorat;
|
||||
use function imagecreatefromstring;
|
||||
|
||||
class QrCodeActionTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
private const WHITE = 0xFFFFFF;
|
||||
private const BLACK = 0x0;
|
||||
|
||||
private QrCodeAction $action;
|
||||
private ObjectProphecy $urlResolver;
|
||||
private QrCodeOptions $options;
|
||||
|
@ -135,7 +140,7 @@ class QrCodeActionTest extends TestCase
|
|||
$delegate = $this->prophesize(RequestHandlerInterface::class);
|
||||
|
||||
$resp = $this->action->process($req->withAttribute('shortCode', $code), $delegate->reveal());
|
||||
[$size] = getimagesizefromstring((string) $resp->getBody());
|
||||
[$size] = getimagesizefromstring($resp->getBody()->__toString());
|
||||
|
||||
self::assertEquals($expectedSize, $size);
|
||||
}
|
||||
|
@ -199,4 +204,41 @@ class QrCodeActionTest extends TestCase
|
|||
538,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider provideRoundBlockSize
|
||||
*/
|
||||
public function imageCanRemoveExtraMarginWhenBlockRoundIsDisabled(
|
||||
array $defaults,
|
||||
?string $roundBlockSize,
|
||||
int $expectedColor,
|
||||
): void {
|
||||
$this->options->setFromArray($defaults);
|
||||
$code = 'abc123';
|
||||
$req = ServerRequestFactory::fromGlobals()
|
||||
->withQueryParams(['size' => 250, 'roundBlockSize' => $roundBlockSize])
|
||||
->withAttribute('shortCode', $code);
|
||||
|
||||
$this->urlResolver->resolveEnabledShortUrl(new ShortUrlIdentifier($code, ''))->willReturn(
|
||||
ShortUrl::withLongUrl('https://shlink.io'),
|
||||
);
|
||||
$delegate = $this->prophesize(RequestHandlerInterface::class);
|
||||
|
||||
$resp = $this->action->process($req, $delegate->reveal());
|
||||
$image = imagecreatefromstring($resp->getBody()->__toString());
|
||||
$color = imagecolorat($image, 1, 1);
|
||||
|
||||
self::assertEquals($color, $expectedColor);
|
||||
}
|
||||
|
||||
public function provideRoundBlockSize(): iterable
|
||||
{
|
||||
yield 'no round block param' => [[], null, self::WHITE];
|
||||
yield 'no round block param, but disabled by default' => [['round_block_size' => false], null, self::BLACK];
|
||||
yield 'round block: "true"' => [[], 'true', self::WHITE];
|
||||
yield 'round block: "true", but disabled by default' => [['round_block_size' => false], 'true', self::WHITE];
|
||||
yield 'round block: "false"' => [[], 'false', self::BLACK];
|
||||
yield 'round block: "false", but enabled by default' => [['round_block_size' => true], 'false', self::BLACK];
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue