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", 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/QrCodeController.php b/src/Controller/QrCodeController.php new file mode 100644 index 0000000..4dc7c0d --- /dev/null +++ b/src/Controller/QrCodeController.php @@ -0,0 +1,235 @@ + + * @license MIT + */ + +namespace Terminal42\UrlRewriteBundle\Controller; + +use Contao\Backend; +use Contao\BackendTemplate; +use Contao\CoreBundle\Exception\PageNotFoundException; +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\HttpKernel\UriSigner; +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 +{ + /** + * @var Connection + */ + private $connection; + + /** + * @var QrCodeGenerator + */ + private $qrCodeGenerator; + + /** + * @var RequestStack + */ + private $requestStack; + + /** + * @var RouterInterface + */ + private $router; + + /** + * @var UriSigner + */ + private $uriSigner; + + /** + * QrCodeController constructor. + */ + 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; + } + + /** + * 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 (count($routeParameters) > 0 && !\in_array(null, $routeParameters, true)) { + $this->addQrCodeToTemplate($template, $rewriteData, $routeParameters); + } + + return $template->getResponse(); + } + + /** + * @Route("/url_rewrite_qr_code/{url}", name="url_rewrite_qr_code", methods={"GET"}) + */ + 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)) { + 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 { + $url = $this->qrCodeGenerator->generateUrl($rewriteData, $routeParameters); + + 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(); + } + } + + /** + * 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 (1 === \count($hosts)) { + $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) { + $routeParameters = $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/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/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..67d21f4 --- /dev/null +++ b/src/QrCodeGenerator.php @@ -0,0 +1,110 @@ + + * @license MIT + */ + +namespace Terminal42\UrlRewriteBundle; + +use BaconQrCode\Renderer\Image\SvgImageBackEnd; +use BaconQrCode\Renderer\ImageRenderer; +use BaconQrCode\Renderer\RendererStyle\RendererStyle; +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 +{ + /** + * @var RouterInterface + */ + private $router; + + /** + * QrCodeGenerator constructor. + */ + public function __construct(RouterInterface $router) + { + $this->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 image. + */ + 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'); + } + + $routeId = null; + $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(UrlRewriteLoader::ATTRIBUTE_NAME) || $route->getDefault(UrlRewriteLoader::ATTRIBUTE_NAME) !== $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 (null === $routeId) { + throw new \RuntimeException(sprintf('Unable to determine route ID for rewrite ID %s', $data['id'])); + } + + $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']); + } + + return $this->router->generate($routeId, $parameters, RouterInterface::ABSOLUTE_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/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 a884d5b..c6a1bcf 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -6,6 +6,25 @@ 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" + - "@router" + - "@uri_signer" + + Terminal42\UrlRewriteBundle\Controller\QrCodeController: + alias: terminal42_url_rewrite.qr_code_controller + public: true + + 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/de/tl_url_rewrite.xlf b/src/Resources/contao/languages/de/tl_url_rewrite.xlf index e550b54..3b657a2 100644 --- a/src/Resources/contao/languages/de/tl_url_rewrite.xlf +++ b/src/Resources/contao/languages/de/tl_url_rewrite.xlf @@ -156,6 +156,14 @@ Activate/deactivate rewrite rule ID %s Regel ID %s aktivieren/deaktivieren + + Generate QR code + QR-Code generieren + + + Generate QR code for rule ID %s + QR-Code für Regel ID %s generieren + Basic @@ -174,6 +182,43 @@ 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 + QR-Code generieren + + + 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"! + + + 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: + + 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 5a52d2a..74f3741 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,34 @@ 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 rule. You may need to provide the necessary parameters if the rule requires them. + + + Generate + + + Scheme + + + Host + + + Requirement: %s (%s) + + + The value does not match pattern "%s"! + + + System was unable to generate the URL, please verify your configuration. + + + 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 new file mode 100644 index 0000000..371594d --- /dev/null +++ b/src/Resources/contao/templates/backend/be_url_rewrite_qr_code.html5 @@ -0,0 +1,53 @@ + +
+ +
+ +
+

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

+ +
+

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

+
+ + error): ?> +
+

trans('ERR.general') ?>

+

error ?>

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

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

+ +
+
+ + + 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 @@ + 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()); 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(); 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']); + } +}