From b213e6b24f16dddb33a3ec51f849cb8d253552fe Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Mon, 7 Jun 2021 13:27:14 +0200 Subject: [PATCH 01/16] Add an option to generate the QR code for every active route --- src/Controller/QrCodeController.php | 196 ++++++++++++++++++ .../RewriteContainerListener.php | 19 ++ src/QrCodeGenerator.php | 94 +++++++++ src/Resources/config/listener.yml | 1 + src/Resources/config/services.yml | 13 ++ src/Resources/contao/config/config.php | 5 +- src/Resources/contao/dca/tl_url_rewrite.php | 6 + .../contao/languages/en/tl_url_rewrite.xlf | 29 +++ .../backend/be_url_rewrite_qr_code.html5 | 49 +++++ src/Resources/public/icon-qr.svg | 1 + src/Resources/public/icon-qr_.svg | 1 + 11 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 src/Controller/QrCodeController.php create mode 100644 src/QrCodeGenerator.php create mode 100644 src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 create mode 100644 src/Resources/public/icon-qr.svg create mode 100644 src/Resources/public/icon-qr_.svg diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php new file mode 100644 index 0000000..b572dc7 --- /dev/null +++ b/src/Controller/QrCodeController.php @@ -0,0 +1,196 @@ +connection = $connection; + $this->qrCodeGenerator = $qrCodeGenerator; + $this->requestStack = $requestStack; + } + + /** + * Index view. + */ + public function index(): Response + { + if (($request = $this->requestStack->getCurrentRequest()) === null + || !($id = $request->query->getInt('id')) + || ($rewriteData = $this->connection->fetchAssociative('SELECT * FROM tl_url_rewrite WHERE id=?', [$id])) === false + || !$this->qrCodeGenerator->validate($rewriteData) + ) { + throw new PageNotFoundException(); + } + + $routeParameters = [ + 'scheme' => $request->getScheme(), + 'host' => null, + ]; + + $template = new BackendTemplate('be_url_rewrite_qr_code'); + $template->backUrl = Backend::getReferer(); + + // Add form to the template + $this->addFormToTemplate($template, $request, $rewriteData, $routeParameters); + + // Generate the QR code only if ALL parameters are set + if (!in_array(null, $routeParameters, true)) { + $this->addQrCodeToTemplate($template, $rewriteData, $routeParameters); + } + + return $template->getResponse(); + } + + /** + * Add QR code to the template. + */ + private function addQrCodeToTemplate(BackendTemplate $template, array $rewriteData, array $routeParameters): void + { + try { + $data = $this->qrCodeGenerator->generate($rewriteData, $routeParameters); + + // Create an image out of QR code so it can be easily downloaded + $file = new File(sprintf('assets/images/q/qr-%s.svg', md5($data['url']))); + $file->truncate(); + $file->write($data['qrCode']); + $file->close(); + + $template->qrCode = $file->path; + $template->url = $data['url']; + } catch (MissingMandatoryParametersException | InvalidParameterException $e) { + $template->error = $e->getMessage(); + } + } + + /** + * Add form to the template. + */ + private function addFormToTemplate(BackendTemplate $template, Request $request, array $rewriteData, array &$routeParameters): array + { + $formFields = []; + + // Add the scheme form field + $formFields['scheme'] = new $GLOBALS['BE_FFL']['select'](Widget::getAttributesFromDca([ + 'label' => &$GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['scheme'], + 'options' => ['http', 'https'], + ], 'scheme', Input::post('scheme') ?: $request->getScheme())); + + // Determine the host + if (is_array($hosts = StringUtil::deserialize($rewriteData['requestHosts'])) && count($hosts = array_filter($hosts)) > 0) { + // Set the host immediately if there's only one + if (count($hosts) === 1) { + $routeParameters['host'] = $hosts[0]; + } else { + // Generate a select menu field for host + $formFields['host'] = new $GLOBALS['BE_FFL']['select'](Widget::getAttributesFromDca([ + 'label' => &$GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['host'], + 'options' => $hosts, + 'eval' => ['mandatory' => true, 'includeBlankOption' => true], + ], 'host', Input::post('host'))); + } + } else { + // Generate a text field for host + $formFields['host'] = new $GLOBALS['BE_FFL']['text'](Widget::getAttributesFromDca([ + 'label' => &$GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['host'], + 'eval' => ['mandatory' => true, 'decodeEntities' => true, 'rgxp' => 'url'], + ], 'host', Input::post('host'))); + } + + $requirements = StringUtil::deserialize($rewriteData['requestRequirements']); + + // Generate the requirement fields + if (is_array($requirements) && count($requirements) > 0) { + foreach ($requirements as $requirement) { + if ('' !== $requirement['key'] && '' !== $requirement['value']) { + $fieldName = 'requirement_' . $requirement['key']; + + $formFields[$fieldName] = new $GLOBALS['BE_FFL']['text'](Widget::getAttributesFromDca([ + 'label' => sprintf($GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['requirement'], $requirement['key'], $requirement['value']), + 'eval' => ['mandatory' => true, 'urlRewriteRequirement' => $requirement], + ], $fieldName, Input::post($fieldName))); + + // Set route parameter to null value to indicate it's mandatory + $routeParameters[$requirement['key']] = null; + } + } + } + + // Add form to template + if (count($formFields) > 0) { + $formSubmit = 'contao-url-rewrite-qr-code'; + + $template->formFields = $formFields; + $template->formSubmit = $formSubmit; + + // Process the form + if ($request->request->get('FORM_SUBMIT') === $formSubmit) { + $this->processForm($formFields, $routeParameters); + } + } + + return $formFields; + } + + /** + * Process the form. + */ + private function processForm(array $formFields, array &$routeParameters): array + { + /** @var Widget $formField */ + foreach ($formFields as $formField) { + $formField->validate(); + + // Validate the requirement regexp, if any + if ($formField->urlRewriteRequirement && !preg_match('/' . $formField->urlRewriteRequirement['value'] . '/', $formField->value)) { + $formField->addError(sprintf($GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['requirementError'], $formField->urlRewriteRequirement['value'])); + } + + // Return an empty array if at least one field has an error + if ($formField->hasErrors()) { + return []; + } + + $routeParameters[$formField->urlRewriteRequirement ? $formField->urlRewriteRequirement['key'] : $formField->name] = $formField->value; + } + + return $routeParameters; + } +} diff --git a/src/EventListener/RewriteContainerListener.php b/src/EventListener/RewriteContainerListener.php index d1761ef..fcd8193 100644 --- a/src/EventListener/RewriteContainerListener.php +++ b/src/EventListener/RewriteContainerListener.php @@ -10,19 +10,28 @@ namespace Terminal42\UrlRewriteBundle\EventListener; +use Contao\Backend; use Contao\CoreBundle\Framework\ContaoFramework; use Contao\DataContainer; +use Contao\Image; use Contao\Input; +use Contao\StringUtil; use Symfony\Cmf\Component\Routing\ChainRouterInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; use Symfony\Component\Routing\Router; use Symfony\Component\Routing\RouterInterface; +use Terminal42\UrlRewriteBundle\QrCodeGenerator; use Terminal42\UrlRewriteBundle\RewriteConfigInterface; class RewriteContainerListener { + /** + * @var QrCodeGenerator + */ + private $qrCodeGenerator; + /** * @var RouterInterface */ @@ -44,6 +53,7 @@ class RewriteContainerListener private $fs; public function __construct( + QrCodeGenerator $qrCodeGenerator, RouterInterface $router, string $cacheDir, ContaoFramework $framework, @@ -53,6 +63,7 @@ public function __construct( $fs = new Filesystem(); } + $this->qrCodeGenerator = $qrCodeGenerator; $this->router = $router; $this->cacheDir = $cacheDir; $this->fs = $fs; @@ -156,6 +167,14 @@ public function generateExamples(): string return sprintf('
%s
', $buffer); } + /** + * On QR code button callback. + */ + public function onQrCodeButtonCallback(array $row, string $href, string $label, string $title, string $icon, string $attributes): string + { + return $this->qrCodeGenerator->validate($row) ? ''.Image::getHtml($icon, $label).' ' : Image::getHtml(preg_replace('/\.svg$/i', '_.svg', $icon)).' '; + } + /** * Clear the router cache. */ diff --git a/src/QrCodeGenerator.php b/src/QrCodeGenerator.php new file mode 100644 index 0000000..7f84b8a --- /dev/null +++ b/src/QrCodeGenerator.php @@ -0,0 +1,94 @@ +router = $router; + } + + /** + * Return true if QR code can be generated from given rewrite record. + */ + public function validate(array $data): bool + { + return $data['requestPath'] !== '' && !$data['inactive']; + } + + /** + * Generate the QR code and the URL. + */ + public function generate(array $data, array $parameters = []): array + { + if (!isset($parameters['host'])) { + throw new MissingMandatoryParametersException('The parameter "host" is mandatory'); + } + + $routeId = null; + $rewriteId = DatabaseConfigProvider::class . ':' . $data['id']; + + foreach ($this->router->getRouteCollection() as $id => $route) { + // Skip the routes not matching the URL rewrite default + if (!$route->hasDefault('_url_rewrite') || $route->getDefault('_url_rewrite') !== $rewriteId) { + continue; + } + + $routeHost = $route->getHost(); + + // Match the route host + if ($routeHost === '' || $parameters['host'] === $routeHost) { + $routeId = $id; + + // Unset the host from parameters, if it's already in the route settings + if ($routeHost !== '') { + unset($parameters['host']); + } + + break; + } + } + + if ($routeId === null) { + throw new \RuntimeException(sprintf('Unable to determine route ID for rewrite ID %s', $data['id'])); + } + + $renderer = new ImageRenderer(new RendererStyle(180, 0), new SvgImageBackEnd()); + $writer = new Writer($renderer); + $context = $this->router->getContext(); + + // Set the scheme + if (isset($parameters['scheme'])) { + $context->setScheme($parameters['scheme']); + unset($parameters['scheme']); + } + + // Override the route host, if it's a route without restriction + if (isset($parameters['host'])) { + $context->setHost($parameters['host']); + unset($parameters['host']); + } + + $url = $this->router->generate($routeId, $parameters, RouterInterface::ABSOLUTE_URL); + + return ['qrCode' => $writer->writeString($url), 'url' => $url]; + } +} diff --git a/src/Resources/config/listener.yml b/src/Resources/config/listener.yml index 78a0408..eb02831 100644 --- a/src/Resources/config/listener.yml +++ b/src/Resources/config/listener.yml @@ -9,6 +9,7 @@ services: class: Terminal42\UrlRewriteBundle\EventListener\RewriteContainerListener public: true arguments: + - "@terminal42_url_rewrite.qr_code_generator" - "@router" - "%kernel.cache_dir%" - "@contao.framework" diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index a884d5b..e75f8a4 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -6,6 +6,19 @@ services: - "@terminal42_url_rewrite.provider" - "@contao.framework" + terminal42_url_rewrite.qr_code_controller: + class: Terminal42\UrlRewriteBundle\Controller\QrCodeController + public: true + arguments: + - "@database_connection" + - "@terminal42_url_rewrite.qr_code_generator" + - "@request_stack" + + terminal42_url_rewrite.qr_code_generator: + class: Terminal42\UrlRewriteBundle\QrCodeGenerator + arguments: + - "@router" + terminal42_url_rewrite.rewrite_loader: class: Terminal42\UrlRewriteBundle\Routing\UrlRewriteLoader arguments: diff --git a/src/Resources/contao/config/config.php b/src/Resources/contao/config/config.php index bc617b0..a680900 100644 --- a/src/Resources/contao/config/config.php +++ b/src/Resources/contao/config/config.php @@ -12,7 +12,10 @@ * Add the backend module if allowed. */ if (\System::getContainer()->getParameter('terminal42_url_rewrite.backend_management')) { - $GLOBALS['BE_MOD']['system']['url_rewrites'] = ['tables' => ['tl_url_rewrite']]; + $GLOBALS['BE_MOD']['system']['url_rewrites'] = [ + 'tables' => ['tl_url_rewrite'], + 'qrCode' => ['terminal42_url_rewrite.qr_code_controller', 'index'], + ]; } /* diff --git a/src/Resources/contao/dca/tl_url_rewrite.php b/src/Resources/contao/dca/tl_url_rewrite.php index 8d4e3e0..2b468c2 100644 --- a/src/Resources/contao/dca/tl_url_rewrite.php +++ b/src/Resources/contao/dca/tl_url_rewrite.php @@ -86,6 +86,12 @@ ], ], ], + 'qrCode' => [ + 'label' => &$GLOBALS['TL_LANG']['tl_url_rewrite']['qrCode'], + 'href' => 'key=qrCode', + 'icon' => 'bundles/terminal42urlrewrite/icon-qr.svg', + 'button_callback' => ['terminal42_url_rewrite.listener.rewrite_container', 'onQrCodeButtonCallback'], + ], ], ], diff --git a/src/Resources/contao/languages/en/tl_url_rewrite.xlf b/src/Resources/contao/languages/en/tl_url_rewrite.xlf index 5a52d2a..b1ca806 100644 --- a/src/Resources/contao/languages/en/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/en/tl_url_rewrite.xlf @@ -118,6 +118,12 @@ Activate/deactivate rewrite rule ID %s + + Generate QR code + + + Generate QR code for rule ID %s + Basic @@ -132,6 +138,29 @@ Allows to define the request condition using the <a href="https://symfony.com/doc/current/components/expression_language.html" target="_blank">Expression Language</a>. For more information please <a href="https://symfony.com/doc/current/routing/conditions.html" target="_blank">visit this link</a>. + + + Generate QR code + + + Use the form below to generate the QR code for this route. You may need to provide the necessary parameters if the route requires them. + + + Generate + + + Scheme + + + Host + + + Requirement: %s (%s) + + + The value does not match pattern "%s"! + + Find address on Google Maps: diff --git a/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 new file mode 100644 index 0000000..676f097 --- /dev/null +++ b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 @@ -0,0 +1,49 @@ + +
+ +
+ +
+

trans('tl_url_rewrite.qrCodeRef.headline') ?>

+ +
+

trans('tl_url_rewrite.qrCodeRef.explanation') ?>

+
+ + error): ?> +
+

trans('ERR.general') ?>

+

error ?>

+
+ qrCode): ?> +
+
+ +
url ?>
+
+
+ + + formFields && $this->formSubmit): ?> +
+
+ + + +
+ formFields as $formField): ?> +
+ parse() ?> +
+ +
+ +
+
+ +
+
+
+
+ +
diff --git a/src/Resources/public/icon-qr.svg b/src/Resources/public/icon-qr.svg new file mode 100644 index 0000000..3a69103 --- /dev/null +++ b/src/Resources/public/icon-qr.svg @@ -0,0 +1 @@ + diff --git a/src/Resources/public/icon-qr_.svg b/src/Resources/public/icon-qr_.svg new file mode 100644 index 0000000..9254e4d --- /dev/null +++ b/src/Resources/public/icon-qr_.svg @@ -0,0 +1 @@ + From 103e1d84f6dc92b52b293a2cb67491eb7655d3cf Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Mon, 7 Jun 2021 13:29:08 +0200 Subject: [PATCH 02/16] Require the bacon/bacon-qr-code package --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f977ad3..bc49727 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ "symfony/filesystem": "^3.3 || ^4.0 || ^5.0", "symfony/http-foundation": "^3.3 || ^4.0 || ^5.0", "symfony/http-kernel": "^3.3 || ^4.0 || ^5.0", - "symfony/routing": "^3.3 || ^4.0 || ^5.0" + "symfony/routing": "^3.3 || ^4.0 || ^5.0", + "bacon/bacon-qr-code": "^2.0" }, "require-dev": { "contao/manager-plugin": "^2.0", From e08e978d3a23a7659039b7ea5870e19403084dda Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Mon, 7 Jun 2021 13:29:53 +0200 Subject: [PATCH 03/16] CS --- src/Controller/QrCodeController.php | 25 +++++++++++++++---------- src/QrCodeGenerator.php | 19 +++++++++++++------ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php index b572dc7..2bf01d0 100644 --- a/src/Controller/QrCodeController.php +++ b/src/Controller/QrCodeController.php @@ -1,5 +1,13 @@ + * @license MIT + */ + namespace Terminal42\UrlRewriteBundle\Controller; use Contao\Backend; @@ -36,9 +44,6 @@ class QrCodeController /** * QrCodeController constructor. - * @param Connection $connection - * @param QrCodeGenerator $qrCodeGenerator - * @param RequestStack $requestStack */ public function __construct(Connection $connection, QrCodeGenerator $qrCodeGenerator, RequestStack $requestStack) { @@ -72,7 +77,7 @@ public function index(): Response $this->addFormToTemplate($template, $request, $rewriteData, $routeParameters); // Generate the QR code only if ALL parameters are set - if (!in_array(null, $routeParameters, true)) { + if (!\in_array(null, $routeParameters, true)) { $this->addQrCodeToTemplate($template, $rewriteData, $routeParameters); } @@ -114,9 +119,9 @@ private function addFormToTemplate(BackendTemplate $template, Request $request, ], 'scheme', Input::post('scheme') ?: $request->getScheme())); // Determine the host - if (is_array($hosts = StringUtil::deserialize($rewriteData['requestHosts'])) && count($hosts = array_filter($hosts)) > 0) { + if (\is_array($hosts = StringUtil::deserialize($rewriteData['requestHosts'])) && \count($hosts = array_filter($hosts)) > 0) { // Set the host immediately if there's only one - if (count($hosts) === 1) { + if (1 === \count($hosts)) { $routeParameters['host'] = $hosts[0]; } else { // Generate a select menu field for host @@ -137,10 +142,10 @@ private function addFormToTemplate(BackendTemplate $template, Request $request, $requirements = StringUtil::deserialize($rewriteData['requestRequirements']); // Generate the requirement fields - if (is_array($requirements) && count($requirements) > 0) { + if (\is_array($requirements) && \count($requirements) > 0) { foreach ($requirements as $requirement) { if ('' !== $requirement['key'] && '' !== $requirement['value']) { - $fieldName = 'requirement_' . $requirement['key']; + $fieldName = 'requirement_'.$requirement['key']; $formFields[$fieldName] = new $GLOBALS['BE_FFL']['text'](Widget::getAttributesFromDca([ 'label' => sprintf($GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['requirement'], $requirement['key'], $requirement['value']), @@ -154,7 +159,7 @@ private function addFormToTemplate(BackendTemplate $template, Request $request, } // Add form to template - if (count($formFields) > 0) { + if (\count($formFields) > 0) { $formSubmit = 'contao-url-rewrite-qr-code'; $template->formFields = $formFields; @@ -179,7 +184,7 @@ private function processForm(array $formFields, array &$routeParameters): array $formField->validate(); // Validate the requirement regexp, if any - if ($formField->urlRewriteRequirement && !preg_match('/' . $formField->urlRewriteRequirement['value'] . '/', $formField->value)) { + if ($formField->urlRewriteRequirement && !preg_match('/'.$formField->urlRewriteRequirement['value'].'/', $formField->value)) { $formField->addError(sprintf($GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['requirementError'], $formField->urlRewriteRequirement['value'])); } diff --git a/src/QrCodeGenerator.php b/src/QrCodeGenerator.php index 7f84b8a..5fa919e 100644 --- a/src/QrCodeGenerator.php +++ b/src/QrCodeGenerator.php @@ -1,5 +1,13 @@ + * @license MIT + */ + namespace Terminal42\UrlRewriteBundle; use BaconQrCode\Renderer\Image\SvgImageBackEnd; @@ -19,7 +27,6 @@ class QrCodeGenerator /** * QrCodeGenerator constructor. - * @param RouterInterface $router */ public function __construct(RouterInterface $router) { @@ -31,7 +38,7 @@ public function __construct(RouterInterface $router) */ public function validate(array $data): bool { - return $data['requestPath'] !== '' && !$data['inactive']; + return '' !== $data['requestPath'] && !$data['inactive']; } /** @@ -44,7 +51,7 @@ public function generate(array $data, array $parameters = []): array } $routeId = null; - $rewriteId = DatabaseConfigProvider::class . ':' . $data['id']; + $rewriteId = DatabaseConfigProvider::class.':'.$data['id']; foreach ($this->router->getRouteCollection() as $id => $route) { // Skip the routes not matching the URL rewrite default @@ -55,11 +62,11 @@ public function generate(array $data, array $parameters = []): array $routeHost = $route->getHost(); // Match the route host - if ($routeHost === '' || $parameters['host'] === $routeHost) { + if ('' === $routeHost || $parameters['host'] === $routeHost) { $routeId = $id; // Unset the host from parameters, if it's already in the route settings - if ($routeHost !== '') { + if ('' !== $routeHost) { unset($parameters['host']); } @@ -67,7 +74,7 @@ public function generate(array $data, array $parameters = []): array } } - if ($routeId === null) { + if (null === $routeId) { throw new \RuntimeException(sprintf('Unable to determine route ID for rewrite ID %s', $data['id'])); } From 32eec5cd929d1e47a6c6e230d5d80bdd8f0f1ad7 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Mon, 7 Jun 2021 13:33:54 +0200 Subject: [PATCH 04/16] Introduce some constants and static methods --- src/ConfigProvider/ChainConfigProvider.php | 12 ++++++++++-- src/Controller/RewriteController.php | 7 ++++--- src/QrCodeGenerator.php | 6 ++++-- src/Routing/UrlRewriteLoader.php | 7 ++++++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/ConfigProvider/ChainConfigProvider.php b/src/ConfigProvider/ChainConfigProvider.php index aa602b0..9569a7f 100644 --- a/src/ConfigProvider/ChainConfigProvider.php +++ b/src/ConfigProvider/ChainConfigProvider.php @@ -32,7 +32,7 @@ public function addProvider(ConfigProviderInterface $provider): void */ public function find(string $id): ?RewriteConfigInterface { - list($class, $id) = explode(':', $id); + [$class, $id] = explode(':', $id); /** @var ConfigProviderInterface $provider */ foreach ($this->providers as $provider) { @@ -57,7 +57,7 @@ public function findAll(): array /** @var RewriteConfigInterface $config */ foreach ($providerConfigs as $config) { - $config->setIdentifier($this->getProviderIdentifier($provider).':'.$config->getIdentifier()); + $config->setIdentifier(static::getConfigIdentifier($this->getProviderIdentifier($provider), $config->getIdentifier())); } $configs = array_merge($configs, $providerConfigs); @@ -66,6 +66,14 @@ public function findAll(): array return $configs; } + /** + * Get the config identifier. + */ + public static function getConfigIdentifier(string $providerIdentifier, string $configIdentifier): string + { + return $providerIdentifier.':'.$configIdentifier; + } + /** * Get the provider identifier. */ diff --git a/src/Controller/RewriteController.php b/src/Controller/RewriteController.php index f854c13..468066d 100644 --- a/src/Controller/RewriteController.php +++ b/src/Controller/RewriteController.php @@ -19,6 +19,7 @@ use Terminal42\UrlRewriteBundle\ConfigProvider\ConfigProviderInterface; use Terminal42\UrlRewriteBundle\Exception\TemporarilyUnavailableConfigProviderException; use Terminal42\UrlRewriteBundle\RewriteConfigInterface; +use Terminal42\UrlRewriteBundle\Routing\UrlRewriteLoader; class RewriteController { @@ -48,11 +49,11 @@ public function __construct(ConfigProviderInterface $configProvider, ContaoFrame */ public function indexAction(Request $request): Response { - if (!$request->attributes->has('_url_rewrite')) { - throw new RouteNotFoundException('The _url_rewrite attribute is missing'); + if (!$request->attributes->has(UrlRewriteLoader::ATTRIBUTE_NAME)) { + throw new RouteNotFoundException(sprintf('The "%s" attribute is missing', UrlRewriteLoader::ATTRIBUTE_NAME)); } - $rewriteId = $request->attributes->get('_url_rewrite'); + $rewriteId = $request->attributes->get(UrlRewriteLoader::ATTRIBUTE_NAME); try { $config = $this->configProvider->find($rewriteId); diff --git a/src/QrCodeGenerator.php b/src/QrCodeGenerator.php index 5fa919e..9425a58 100644 --- a/src/QrCodeGenerator.php +++ b/src/QrCodeGenerator.php @@ -16,7 +16,9 @@ use BaconQrCode\Writer; use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; use Symfony\Component\Routing\RouterInterface; +use Terminal42\UrlRewriteBundle\ConfigProvider\ChainConfigProvider; use Terminal42\UrlRewriteBundle\ConfigProvider\DatabaseConfigProvider; +use Terminal42\UrlRewriteBundle\Routing\UrlRewriteLoader; class QrCodeGenerator { @@ -51,11 +53,11 @@ public function generate(array $data, array $parameters = []): array } $routeId = null; - $rewriteId = DatabaseConfigProvider::class.':'.$data['id']; + $rewriteId = ChainConfigProvider::getConfigIdentifier(DatabaseConfigProvider::class, $data['id']); foreach ($this->router->getRouteCollection() as $id => $route) { // Skip the routes not matching the URL rewrite default - if (!$route->hasDefault('_url_rewrite') || $route->getDefault('_url_rewrite') !== $rewriteId) { + if (!$route->hasDefault(UrlRewriteLoader::ATTRIBUTE_NAME) || $route->getDefault(UrlRewriteLoader::ATTRIBUTE_NAME) !== $rewriteId) { continue; } diff --git a/src/Routing/UrlRewriteLoader.php b/src/Routing/UrlRewriteLoader.php index e9e63c3..e72227a 100644 --- a/src/Routing/UrlRewriteLoader.php +++ b/src/Routing/UrlRewriteLoader.php @@ -20,6 +20,11 @@ class UrlRewriteLoader extends Loader { + /** + * Attribute name + */ + public const ATTRIBUTE_NAME = '_url_rewrite'; + /** * @var ConfigProviderInterface */ @@ -107,7 +112,7 @@ private function createRoute(RewriteConfigInterface $config, string $host = null $route = new Route(rawurldecode($config->getRequestPath())); $route->setDefault('_controller', 'terminal42_url_rewrite.rewrite_controller:indexAction'); - $route->setDefault('_url_rewrite', $config->getIdentifier()); + $route->setDefault(self::ATTRIBUTE_NAME, $config->getIdentifier()); $route->setOption('utf8', true); $route->setRequirements($config->getRequestRequirements()); From 35b19134bdb9316950108713d9303d43783f7a2b Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Tue, 8 Jun 2021 10:17:21 +0200 Subject: [PATCH 05/16] QR code controller improvements --- src/Controller/QrCodeController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php index 2bf01d0..e6453a9 100644 --- a/src/Controller/QrCodeController.php +++ b/src/Controller/QrCodeController.php @@ -167,7 +167,7 @@ private function addFormToTemplate(BackendTemplate $template, Request $request, // Process the form if ($request->request->get('FORM_SUBMIT') === $formSubmit) { - $this->processForm($formFields, $routeParameters); + $routeParameters = $this->processForm($formFields, $routeParameters); } } @@ -177,7 +177,7 @@ private function addFormToTemplate(BackendTemplate $template, Request $request, /** * Process the form. */ - private function processForm(array $formFields, array &$routeParameters): array + private function processForm(array $formFields, array $routeParameters): array { /** @var Widget $formField */ foreach ($formFields as $formField) { From 00a479b39c65820a14d0eb8a92b170cc505d8314 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Tue, 8 Jun 2021 15:55:28 +0200 Subject: [PATCH 06/16] Do not store QR code as a real file on the disk, but rather generate it on the fly with a controller --- src/Controller/QrCodeController.php | 41 +++++++++++++++++++++-------- src/QrCodeGenerator.php | 21 ++++++++++----- src/Resources/config/routing.yml | 4 +++ src/Resources/config/services.yml | 5 ++++ 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php index e6453a9..c29b4f1 100644 --- a/src/Controller/QrCodeController.php +++ b/src/Controller/QrCodeController.php @@ -13,16 +13,18 @@ use Contao\Backend; use Contao\BackendTemplate; use Contao\CoreBundle\Exception\PageNotFoundException; -use Contao\File; use Contao\Input; use Contao\StringUtil; +use Contao\Validator; use Contao\Widget; use Doctrine\DBAL\Connection; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Exception\InvalidParameterException; use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; +use Symfony\Component\Routing\RouterInterface; use Terminal42\UrlRewriteBundle\QrCodeGenerator; class QrCodeController @@ -42,14 +44,20 @@ class QrCodeController */ private $requestStack; + /** + * @var RouterInterface + */ + private $router; + /** * QrCodeController constructor. */ - public function __construct(Connection $connection, QrCodeGenerator $qrCodeGenerator, RequestStack $requestStack) + public function __construct(Connection $connection, QrCodeGenerator $qrCodeGenerator, RequestStack $requestStack, RouterInterface $router) { $this->connection = $connection; $this->qrCodeGenerator = $qrCodeGenerator; $this->requestStack = $requestStack; + $this->router = $router; } /** @@ -84,22 +92,33 @@ public function index(): Response return $template->getResponse(); } + /** + * @Route("/url_rewrite_qr_code/{url}", name="url_rewrite_qr_code", methods={"GET"}) + */ + public function qrCode(string $url): Response + { + $url = base64_decode($url); + + if (!Validator::isUrl($url) || !preg_match('/https?:\/\//', $url)) { + return new Response(Response::$statusTexts[Response::HTTP_BAD_REQUEST], Response::HTTP_BAD_REQUEST); + } + + $response = new Response($this->qrCodeGenerator->generateImage($url)); + $response->headers->set('content-type', 'image/svg+xml'); + + return $response; + } + /** * Add QR code to the template. */ private function addQrCodeToTemplate(BackendTemplate $template, array $rewriteData, array $routeParameters): void { try { - $data = $this->qrCodeGenerator->generate($rewriteData, $routeParameters); - - // Create an image out of QR code so it can be easily downloaded - $file = new File(sprintf('assets/images/q/qr-%s.svg', md5($data['url']))); - $file->truncate(); - $file->write($data['qrCode']); - $file->close(); + $url = $this->qrCodeGenerator->generateUrl($rewriteData, $routeParameters); - $template->qrCode = $file->path; - $template->url = $data['url']; + $template->qrCode = $this->router->generate('url_rewrite_qr_code', ['url' => base64_encode($url)]); + $template->url = $url; } catch (MissingMandatoryParametersException | InvalidParameterException $e) { $template->error = $e->getMessage(); } diff --git a/src/QrCodeGenerator.php b/src/QrCodeGenerator.php index 9425a58..67d21f4 100644 --- a/src/QrCodeGenerator.php +++ b/src/QrCodeGenerator.php @@ -44,9 +44,20 @@ public function validate(array $data): bool } /** - * Generate the QR code and the URL. + * Generate the image. */ - public function generate(array $data, array $parameters = []): array + public function generateImage(string $url): string + { + $renderer = new ImageRenderer(new RendererStyle(180, 0), new SvgImageBackEnd()); + $writer = new Writer($renderer); + + return $writer->writeString($url); + } + + /** + * Generate the URL. + */ + public function generateUrl(array $data, array $parameters = []): string { if (!isset($parameters['host'])) { throw new MissingMandatoryParametersException('The parameter "host" is mandatory'); @@ -80,8 +91,6 @@ public function generate(array $data, array $parameters = []): array throw new \RuntimeException(sprintf('Unable to determine route ID for rewrite ID %s', $data['id'])); } - $renderer = new ImageRenderer(new RendererStyle(180, 0), new SvgImageBackEnd()); - $writer = new Writer($renderer); $context = $this->router->getContext(); // Set the scheme @@ -96,8 +105,6 @@ public function generate(array $data, array $parameters = []): array unset($parameters['host']); } - $url = $this->router->generate($routeId, $parameters, RouterInterface::ABSOLUTE_URL); - - return ['qrCode' => $writer->writeString($url), 'url' => $url]; + return $this->router->generate($routeId, $parameters, RouterInterface::ABSOLUTE_URL); } } diff --git a/src/Resources/config/routing.yml b/src/Resources/config/routing.yml index a8c46ff..1252c04 100644 --- a/src/Resources/config/routing.yml +++ b/src/Resources/config/routing.yml @@ -1,3 +1,7 @@ +controllers: + resource: ../../Controller/ + type: annotation + terminal42_url_rewrite: resource: . type: terminal42_url_rewrite diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index e75f8a4..812489c 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -13,6 +13,11 @@ services: - "@database_connection" - "@terminal42_url_rewrite.qr_code_generator" - "@request_stack" + - "@router" + + Terminal42\UrlRewriteBundle\Controller\QrCodeController: + alias: terminal42_url_rewrite.qr_code_controller + public: true terminal42_url_rewrite.qr_code_generator: class: Terminal42\UrlRewriteBundle\QrCodeGenerator From f93aee61ede813befb62806a60c2693146253557 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Tue, 8 Jun 2021 16:05:52 +0200 Subject: [PATCH 07/16] Backend UI improvements --- src/Resources/contao/languages/en/tl_url_rewrite.xlf | 3 +++ .../templates/backend/be_url_rewrite_qr_code.html5 | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Resources/contao/languages/en/tl_url_rewrite.xlf b/src/Resources/contao/languages/en/tl_url_rewrite.xlf index b1ca806..39e4a6f 100644 --- a/src/Resources/contao/languages/en/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/en/tl_url_rewrite.xlf @@ -160,6 +160,9 @@ The value does not match pattern "%s"! + + Copy the image URL: + Find address on Google Maps: diff --git a/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 index 676f097..0bd6d9c 100644 --- a/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 +++ b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 @@ -16,11 +16,15 @@

error ?>

qrCode): ?> -
-
+
+
-
url ?>
+
url ?>
+
+

trans('tl_url_rewrite.qrCodeRef.copy') ?>

+ +
From 5cd057b9e38c2e7b013fc12ce4ca02c6e0112c01 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Tue, 8 Jun 2021 16:19:39 +0200 Subject: [PATCH 08/16] Use the URI signer to secure the QR code image URL --- src/Controller/QrCodeController.php | 17 ++++++++++++++--- src/Resources/config/services.yml | 1 + .../backend/be_url_rewrite_qr_code.html5 | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php index c29b4f1..41ec12a 100644 --- a/src/Controller/QrCodeController.php +++ b/src/Controller/QrCodeController.php @@ -21,6 +21,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\UriSigner; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Exception\InvalidParameterException; use Symfony\Component\Routing\Exception\MissingMandatoryParametersException; @@ -49,15 +50,21 @@ class QrCodeController */ private $router; + /** + * @var UriSigner + */ + private $uriSigner; + /** * QrCodeController constructor. */ - public function __construct(Connection $connection, QrCodeGenerator $qrCodeGenerator, RequestStack $requestStack, RouterInterface $router) + public function __construct(Connection $connection, QrCodeGenerator $qrCodeGenerator, RequestStack $requestStack, RouterInterface $router, UriSigner $uriSigner) { $this->connection = $connection; $this->qrCodeGenerator = $qrCodeGenerator; $this->requestStack = $requestStack; $this->router = $router; + $this->uriSigner = $uriSigner; } /** @@ -95,8 +102,12 @@ public function index(): Response /** * @Route("/url_rewrite_qr_code/{url}", name="url_rewrite_qr_code", methods={"GET"}) */ - public function qrCode(string $url): Response + public function qrCode(Request $request, string $url): Response { + if (!$this->uriSigner->check($request->getSchemeAndHttpHost() . $request->getBaseUrl() . $request->getPathInfo() . (null !== ($qs = $request->server->get('QUERY_STRING')) ? '?' . $qs : ''))) { + return new Response(Response::$statusTexts[Response::HTTP_BAD_REQUEST], Response::HTTP_BAD_REQUEST); + } + $url = base64_decode($url); if (!Validator::isUrl($url) || !preg_match('/https?:\/\//', $url)) { @@ -117,7 +128,7 @@ private function addQrCodeToTemplate(BackendTemplate $template, array $rewriteDa try { $url = $this->qrCodeGenerator->generateUrl($rewriteData, $routeParameters); - $template->qrCode = $this->router->generate('url_rewrite_qr_code', ['url' => base64_encode($url)]); + $template->qrCode = $this->uriSigner->sign($this->router->generate('url_rewrite_qr_code', ['url' => base64_encode($url)], RouterInterface::ABSOLUTE_URL)); $template->url = $url; } catch (MissingMandatoryParametersException | InvalidParameterException $e) { $template->error = $e->getMessage(); diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index 812489c..c6a1bcf 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -14,6 +14,7 @@ services: - "@terminal42_url_rewrite.qr_code_generator" - "@request_stack" - "@router" + - "@uri_signer" Terminal42\UrlRewriteBundle\Controller\QrCodeController: alias: terminal42_url_rewrite.qr_code_controller diff --git a/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 index 0bd6d9c..1773f6d 100644 --- a/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 +++ b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 @@ -23,7 +23,7 @@

trans('tl_url_rewrite.qrCodeRef.copy') ?>

- +
From 7f7c5154c29f8606a34de4c75cd3fc14e2857981 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Wed, 9 Jun 2021 09:39:21 +0200 Subject: [PATCH 09/16] Add foundation for German translation --- .../contao/languages/de/tl_url_rewrite.xlf | 31 +++++++++++++++++++ .../contao/languages/en/tl_url_rewrite.xlf | 1 - 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Resources/contao/languages/de/tl_url_rewrite.xlf b/src/Resources/contao/languages/de/tl_url_rewrite.xlf index e550b54..6a51eb6 100644 --- a/src/Resources/contao/languages/de/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/de/tl_url_rewrite.xlf @@ -156,6 +156,12 @@ Activate/deactivate rewrite rule ID %s Regel ID %s aktivieren/deaktivieren
+ + Generate QR code + + + Generate QR code for rule ID %s + Basic @@ -174,6 +180,31 @@ Erlaubt die Anfrage-Zuordnung auf Basis der Symfony <a href="https://symfony.com/doc/current/components/expression_language.html" target="_blank">Expression Language</a>. Für weitere Informationen <a href="https://symfony.com/doc/current/routing/conditions.html" target="_blank">besuchen Sie bitte diese Seite</a>. + + Generate QR code + + + Use the form below to generate the QR code for this route. You may need to provide the necessary parameters if the route requires them. + + + Generate + + + Scheme + + + Host + + + Requirement: %s (%s) + + + The value does not match pattern "%s"! + + + Copy the image URL: + + Find address on Google Maps: Adresse auf Google Maps finden: diff --git a/src/Resources/contao/languages/en/tl_url_rewrite.xlf b/src/Resources/contao/languages/en/tl_url_rewrite.xlf index 39e4a6f..5222fc9 100644 --- a/src/Resources/contao/languages/en/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/en/tl_url_rewrite.xlf @@ -138,7 +138,6 @@ Allows to define the request condition using the <a href="https://symfony.com/doc/current/components/expression_language.html" target="_blank">Expression Language</a>. For more information please <a href="https://symfony.com/doc/current/routing/conditions.html" target="_blank">visit this link</a>. - Generate QR code From 17f858c8ef781256ff642c5cd98949abec5c400a Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Wed, 9 Jun 2021 09:42:16 +0200 Subject: [PATCH 10/16] Improve backend UI --- .../contao/templates/backend/be_url_rewrite_qr_code.html5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 index 1773f6d..371594d 100644 --- a/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 +++ b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 @@ -36,7 +36,7 @@
formFields as $formField): ?> -
+
parse() ?>
From a39562365347ca4212a6bd56dc813ffb6e3f0425 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Wed, 9 Jun 2021 10:19:12 +0200 Subject: [PATCH 11/16] Fix the requirement regexp check on our side --- src/Controller/QrCodeController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php index 41ec12a..2afd565 100644 --- a/src/Controller/QrCodeController.php +++ b/src/Controller/QrCodeController.php @@ -214,7 +214,7 @@ private function processForm(array $formFields, array $routeParameters): array $formField->validate(); // Validate the requirement regexp, if any - if ($formField->urlRewriteRequirement && !preg_match('/'.$formField->urlRewriteRequirement['value'].'/', $formField->value)) { + if ($formField->urlRewriteRequirement && !preg_match('/^'.$formField->urlRewriteRequirement['value'].'$/', $formField->value)) { $formField->addError(sprintf($GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['requirementError'], $formField->urlRewriteRequirement['value'])); } From cf83a4e577ee832f0cc7c0600e0408567cc6b0e6 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Wed, 9 Jun 2021 10:21:30 +0200 Subject: [PATCH 12/16] Display an error if route could not generate a URL --- src/Controller/QrCodeController.php | 8 ++++++-- src/Resources/contao/languages/de/tl_url_rewrite.xlf | 3 +++ src/Resources/contao/languages/en/tl_url_rewrite.xlf | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php index 2afd565..5b09045 100644 --- a/src/Controller/QrCodeController.php +++ b/src/Controller/QrCodeController.php @@ -128,8 +128,12 @@ private function addQrCodeToTemplate(BackendTemplate $template, array $rewriteDa try { $url = $this->qrCodeGenerator->generateUrl($rewriteData, $routeParameters); - $template->qrCode = $this->uriSigner->sign($this->router->generate('url_rewrite_qr_code', ['url' => base64_encode($url)], RouterInterface::ABSOLUTE_URL)); - $template->url = $url; + if ($url !== '') { + $template->qrCode = $this->uriSigner->sign($this->router->generate('url_rewrite_qr_code', ['url' => base64_encode($url)], RouterInterface::ABSOLUTE_URL)); + $template->url = $url; + } else { + $template->error = $GLOBALS['TL_LANG']['tl_url_rewrite']['qrCodeRef']['routeError']; + } } catch (MissingMandatoryParametersException | InvalidParameterException $e) { $template->error = $e->getMessage(); } diff --git a/src/Resources/contao/languages/de/tl_url_rewrite.xlf b/src/Resources/contao/languages/de/tl_url_rewrite.xlf index 6a51eb6..a17df97 100644 --- a/src/Resources/contao/languages/de/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/de/tl_url_rewrite.xlf @@ -201,6 +201,9 @@ The value does not match pattern "%s"! + + Router could not generate the URL. + Copy the image URL: diff --git a/src/Resources/contao/languages/en/tl_url_rewrite.xlf b/src/Resources/contao/languages/en/tl_url_rewrite.xlf index 5222fc9..58e0bfe 100644 --- a/src/Resources/contao/languages/en/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/en/tl_url_rewrite.xlf @@ -159,6 +159,9 @@ The value does not match pattern "%s"! + + Router could not generate the URL. + Copy the image URL: From 9326d6b7af5ac3869fad42eecaff3cb10a747707 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Wed, 9 Jun 2021 10:24:44 +0200 Subject: [PATCH 13/16] Improve the error handling --- src/Controller/QrCodeController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/QrCodeController.php b/src/Controller/QrCodeController.php index 5b09045..4dc7c0d 100644 --- a/src/Controller/QrCodeController.php +++ b/src/Controller/QrCodeController.php @@ -92,7 +92,7 @@ public function index(): Response $this->addFormToTemplate($template, $request, $rewriteData, $routeParameters); // Generate the QR code only if ALL parameters are set - if (!\in_array(null, $routeParameters, true)) { + if (count($routeParameters) > 0 && !\in_array(null, $routeParameters, true)) { $this->addQrCodeToTemplate($template, $rewriteData, $routeParameters); } From 1df189535cc3e5e2885ca53186c4b77eb70a1d8e Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Wed, 9 Jun 2021 10:47:45 +0200 Subject: [PATCH 14/16] Update the labels --- .../contao/languages/de/tl_url_rewrite.xlf | 15 +++++++++++++-- .../contao/languages/en/tl_url_rewrite.xlf | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Resources/contao/languages/de/tl_url_rewrite.xlf b/src/Resources/contao/languages/de/tl_url_rewrite.xlf index a17df97..3b657a2 100644 --- a/src/Resources/contao/languages/de/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/de/tl_url_rewrite.xlf @@ -158,9 +158,11 @@ Generate QR code + QR-Code generieren Generate QR code for rule ID %s + QR-Code für Regel ID %s generieren @@ -182,30 +184,39 @@ Generate QR code + QR-Code generieren - Use the form below to generate the QR code for this route. You may need to provide the necessary parameters if the route requires them. + Use the form below to generate the QR code for this rule. You may need to provide the necessary parameters if the rule requires them. + Verwenden Sie das folgende Formular, um den QR-Code für diese Regel zu generieren. Möglicherweise müssen Sie die erforderlichen Parameter angeben, wenn die Regel sie erfordert. Generate + Generieren Scheme + Protokoll Host + Host Requirement: %s (%s) + Parameter: %s (%s) The value does not match pattern "%s"! + Der Wert stimmt nicht mit der Anforderung überein "%s"! - Router could not generate the URL. + System was unable to generate the URL, please verify your configuration. + Das System konnte keine valide URL generieren, bitte überprüfen Sie die Konfiguration. Copy the image URL: + Bild-URL kopieren: diff --git a/src/Resources/contao/languages/en/tl_url_rewrite.xlf b/src/Resources/contao/languages/en/tl_url_rewrite.xlf index 58e0bfe..74f3741 100644 --- a/src/Resources/contao/languages/en/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/en/tl_url_rewrite.xlf @@ -142,7 +142,7 @@ Generate QR code - Use the form below to generate the QR code for this route. You may need to provide the necessary parameters if the route requires them. + Use the form below to generate the QR code for this rule. You may need to provide the necessary parameters if the rule requires them. Generate @@ -160,7 +160,7 @@ The value does not match pattern "%s"! - Router could not generate the URL. + System was unable to generate the URL, please verify your configuration. Copy the image URL: From 4e0e76e104e4297af3054f8e120cfa308260934a Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Thu, 22 Jul 2021 11:15:51 +0200 Subject: [PATCH 15/16] Fix unit tests --- tests/EventListener/AbstractContainerListenerTest.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/EventListener/AbstractContainerListenerTest.php b/tests/EventListener/AbstractContainerListenerTest.php index d1dc03b..b180a98 100644 --- a/tests/EventListener/AbstractContainerListenerTest.php +++ b/tests/EventListener/AbstractContainerListenerTest.php @@ -11,6 +11,7 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Routing\RouterInterface; use Terminal42\UrlRewriteBundle\EventListener\RewriteContainerListener; +use Terminal42\UrlRewriteBundle\QrCodeGenerator; abstract class AbstractContainerListenerTest extends ContaoTestCase { @@ -29,6 +30,11 @@ abstract class AbstractContainerListenerTest extends ContaoTestCase */ protected $cacheDir; + /** + * @var QrCodeGenerator + */ + protected $qrCodeGenerator; + /** * @var RouterInterface */ @@ -46,12 +52,14 @@ protected function setUp(): void $this->fs = new Filesystem(); $this->fs->mkdir($this->cacheDir); + $this->qrCodeGenerator = $this->createMock(QrCodeGenerator::class); + $this->router = $this->getRouter(); $this->inputAdapter = $this->mockAdapter(['post']); $framework = $this->mockContaoFramework([Input::class => $this->inputAdapter]); - $this->listener = new RewriteContainerListener($this->router, $this->cacheDir, $framework); + $this->listener = new RewriteContainerListener($this->qrCodeGenerator, $this->router, $this->cacheDir, $framework); } abstract protected function getRouter(); From 0d9d3d395fe72d8d609b15697e8beecab73225b9 Mon Sep 17 00:00:00 2001 From: Kamil Kuzminski Date: Thu, 22 Jul 2021 12:02:07 +0200 Subject: [PATCH 16/16] Add QrCodeGenerator unit tests --- tests/Fixtures/qr-code.svg | 2 + tests/QrCodeGeneratorTest.php | 89 +++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 tests/Fixtures/qr-code.svg create mode 100644 tests/QrCodeGeneratorTest.php diff --git a/tests/Fixtures/qr-code.svg b/tests/Fixtures/qr-code.svg new file mode 100644 index 0000000..aec27f8 --- /dev/null +++ b/tests/Fixtures/qr-code.svg @@ -0,0 +1,2 @@ + + diff --git a/tests/QrCodeGeneratorTest.php b/tests/QrCodeGeneratorTest.php new file mode 100644 index 0000000..62f64ff --- /dev/null +++ b/tests/QrCodeGeneratorTest.php @@ -0,0 +1,89 @@ +router = $this->createMock(Router::class); + $this->qrCodeGenerator = new QrCodeGenerator($this->router); + } + + public function testInstantiation() + { + $this->assertInstanceOf(QrCodeGenerator::class, $this->qrCodeGenerator); + } + + public function testValidate() + { + $this->assertTrue($this->qrCodeGenerator->validate(['requestPath' => 'foo/bar', 'inactive' => false])); + + $this->assertFalse($this->qrCodeGenerator->validate(['requestPath' => 'foo/bar', 'inactive' => true])); + $this->assertFalse($this->qrCodeGenerator->validate(['requestPath' => '', 'inactive' => true])); + $this->assertFalse($this->qrCodeGenerator->validate(['requestPath' => '', 'inactive' => false])); + } + + public function testGenerateImage() + { + $image = $this->qrCodeGenerator->generateImage('https://domain.tld/foo/bar?test=1'); + + $this->assertSame(file_get_contents(__DIR__ . '/Fixtures/qr-code.svg'), $image); + } + + public function testGenerateUrl() + { + $routeIncorrect = new Route('foo/baz'); + + $routeCorrect1 = new Route('foo/bar'); + $routeCorrect1->setHost('domain.tld'); + $routeCorrect1->setDefault(UrlRewriteLoader::ATTRIBUTE_NAME, DatabaseConfigProvider::class . ':123'); + + $routeCorrect2 = new Route('foo/bar'); + $routeCorrect2->setDefault(UrlRewriteLoader::ATTRIBUTE_NAME, DatabaseConfigProvider::class . ':456'); + + $this->router->method('getRouteCollection')->willReturn([666 => $routeIncorrect, 123 => $routeCorrect1, 456 => $routeCorrect2]); + $this->router->method('getContext')->willReturn(new RequestContext); + $this->router->method('generate')->willReturn('https://domain.tld/foo/bar'); + + $this->assertEquals('https://domain.tld/foo/bar', $this->qrCodeGenerator->generateUrl(['id' => 123], ['host' => 'domain.tld', 'scheme' => 'https'])); + $this->assertEquals('https://domain.tld/foo/bar', $this->qrCodeGenerator->generateUrl(['id' => 456], ['host' => 'domain.tld'])); + } + + public function testGenerateUrlMissingMandatoryParametersException() + { + $this->expectException(MissingMandatoryParametersException::class); + $this->expectExceptionMessage('The parameter "host" is mandatory'); + + $this->qrCodeGenerator->generateUrl([]); + } + + public function testGenerateUrlRuntimeException() + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Unable to determine route ID for rewrite ID 456'); + + $this->router->method('getRouteCollection')->willReturn([]); + $this->qrCodeGenerator->generateUrl(['id' => 456], ['host' => 'domain.tld']); + } +}