qr_generator-1.0.1/src/Plugin/rest/resource/QRRestResource.php
src/Plugin/rest/resource/QRRestResource.php
<?php
declare(strict_types=1);
namespace Drupal\qr_generator\Plugin\rest\resource;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\qr_generator\Exception\QRCodeExpiredHttpException;
use Drupal\rest\Attribute\RestResource;
use Drupal\rest\Plugin\ResourceBase;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* REST resource for retrieving and redirecting QR code entities by UUID.
*
* This REST plugin exposes a read-only GET endpoint at
* `/api/qr-code/{uuid}` which:
* - Validates that a `qr_code` entity with the provided UUID exists.
* - Checks whether the QR code has expired based on its `field_expires` value.
* - Redirects the client to the target URL stored in `field_redirect_url`.
*
* If the entity does not exist, a 404 Not Found response is returned.
* If the QR code has expired, a `QRCodeExpiredHttpException` is thrown.
* Otherwise, the client receives a `TrustedRedirectResponse` to the target URL.
*
* Typical use cases:
* - Serving as the scan target for generated QR codes, enabling them to
* redirect users to their intended destination.
* - Providing a centralized place to enforce expiry rules and manage
* redirection logic for QR code entities.
*
* Route & HTTP method:
* - GET /api/qr-code/{uuid}
*
* Access control:
* - Currently allows all requests without authentication or permission checks.
* Adjust the `access()` method if additional security is required.
*
* @package Drupal\qr_generator\Plugin\rest\resource
*
* @see \Drupal\rest\Plugin\rest\resource\EntityResource
* @see \Drupal\rest\Plugin\ResourceBase
*/
#[RestResource(
id: 'qr_code_rest_resource',
label: new TranslatableMarkup('QR Code Rest Resource'),
uri_paths: [
'canonical' => '/api/qr-code/{uuid}'
],
)]
final class QRRestResource extends ResourceBase
{
/**
* The key-value storage.
*/
private readonly KeyValueStoreInterface $storage;
/**
* {@inheritdoc}
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
array $serializer_formats,
LoggerInterface $logger,
KeyValueFactoryInterface $keyValueFactory,
) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
$this->storage = $keyValueFactory->get('qr_generator_rest_resource');
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self
{
return new self(
$configuration,
$plugin_id,
$plugin_definition,
$container->getParameter('serializer.formats'),
$container->get('logger.factory')->get('rest'),
$container->get('keyvalue')
);
}
/**
* Responds to GET requests.
*/
public function get($uuid): TrustedRedirectResponse
{
// Check if entity exist
$entities = \Drupal::entityTypeManager()->getStorage('qr_code')->loadByProperties(['uuid' => $uuid]);
if (!$entities) {
throw new NotFoundHttpException('QR-Code not found!');
}
$entity = reset($entities);
$expired = $entity->get('field_expires')->getString();
// Check if qr-code expired
if ($expired) {
$timestamp = \Drupal::time()->getCurrentTime(); // website datetime in timestamp
if (!empty($timestamp)) {
if ($timestamp >= (int)$entity->get('field_expires')->getString()) {
throw new QRCodeExpiredHttpException('This QR code has expired!');
}
}
}
return new TrustedRedirectResponse($entity->get('field_redirect_url')->getString());
}
public function permissions()
{
// Don't declare any permissions, or return empty array
return [];
}
public function access($operation = 'view', AccountInterface $account = NULL, $return_as_object = FALSE)
{
return AccessResult::allowed();
}
}
