qr_generator-1.0.1/src/Form/OfflineQRCodeExportForm.php
src/Form/OfflineQRCodeExportForm.php
<?php
declare(strict_types=1);
namespace Drupal\qr_generator\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Endroid\QrCode\Builder\Builder;
use Symfony\Component\HttpFoundation\Response;
use Endroid\QrCode\Writer\PngWriter;
use Endroid\QrCode\Writer\SvgWriter;
use Endroid\QrCode\Writer\PdfWriter;
/**
* Form controller for generating and exporting stand-alone (offline) QR codes.
*
* This form lets a user enter a target URL and generate a downloadable QR code
* without relying on any host system or online service at scan time.
*
* Key features:
* - Accepts a full URL from the user.
* - Allows customization of QR code size (in pixels) and margin.
* - Supports multiple output formats (PNG, SVG, PDF).
* - Uses the Endroid\QrCode library to create the QR code image.
* - Streams the generated QR code directly to the browser as a file download.
*
* Workflow:
* 1. User enters a valid URL and selects output parameters.
* 2. Form validates the URL format, size, margin, and output format.
* 3. Based on the chosen format, the corresponding writer (PngWriter, SvgWriter, PdfWriter) is instantiated.
* 4. The QR code is generated using Endroid\QrCode\Builder with the given parameters.
* 5. A binary response is returned to the browser with the proper MIME type and
* a filename based on the current timestamp.
*
* Example use cases:
* - Creating QR codes for printed materials that point to static online resources.
* - Providing direct access to a configuration URL for devices in offline-friendly contexts.
* - Generating QR codes for physical product labels or event passes.
*
* @package Drupal\qr_generator\Form
*/
final class OfflineQRCodeExportForm extends FormBase
{
/**
* {@inheritdoc}
*/
public function getFormId(): string
{
return 'qr_generator_offline_q_r_code_export';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array
{
$form['link'] = [
'#type' => 'url',
'#title' => $this->t('URL'),
'#description' => $this->t('Enter a full URL, including http:// or https://'),
'#required' => TRUE,
];
$form['size'] = [
'#type' => 'number',
'#title' => $this->t('Size (px)'),
'#default_value' => 300,
'#min' => 100,
'#max' => 1000,
];
$form['margin'] = [
'#type' => 'number',
'#title' => $this->t('Margin'),
'#default_value' => 10,
'#min' => 0,
'#max' => 50,
];
$form['format'] = [
'#type' => 'select',
'#title' => $this->t('Output format'),
'#options' => [
'png' => 'PNG',
'svg' => 'SVG',
'pdf' => 'PDF',
],
'#default_value' => 'png',
];
$form['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Generate QR Code'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state): void
{
$url = $form_state->getValue('link');
if (!filter_var($url, FILTER_VALIDATE_URL)) {
$form_state->setErrorByName('link', $this->t('Please enter a valid URL.'));
}
$size = (int) $form_state->getValue('size');
$margin = (int) $form_state->getValue('margin');
$format = $form_state->getValue('format');
// Validate size
if ($size <= 0) {
$form_state->setErrorByName('size', $this->t('Size must be a positive number.'));
}
// Validate margin
if ($margin < 0) {
$form_state->setErrorByName('margin', $this->t('Margin cannot be negative.'));
}
// Validate format
$allowed_formats = ['png', 'pdf', 'svg']; // Example allowed values
if (!in_array($format, $allowed_formats)) {
$form_state->setErrorByName('format', $this->t('Invalid format selected. Allowed formats: @formats', [
'@formats' => implode(', ', $allowed_formats),
]));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void
{
$url = $form_state->getValue('link');
$size = (int) $form_state->getValue('size');
$margin = (int) $form_state->getValue('margin');
$format = $form_state->getValue('format');
// Determine writer
$writer = match ($format) {
'svg' => new SvgWriter(),
'pdf' => new PdfWriter(),
default => new PngWriter(),
};
$builder = new Builder();
$result = $builder->build($writer, null, false, $url, null, null, $size, $margin);
$filename = \Drupal::time()->getCurrentTime() . '.' . $format;
$response = new Response($result->getString());
$response->headers->set('Content-Type', $result->getMimeType());
$response->headers->set('Content-Disposition', 'attachment; filename="'.$filename.'"');
$response->send();
exit;
}
}
