Architecture¶
Short URL is built on interface-based services that can be individually overridden via Drupal's service container.
Services¶
ShortUrlManager¶
Implements ShortUrlManagerInterface. Orchestrates the redirect
lifecycle for short URL nodes.
Key methods:
buildFullUrl(NodeInterface $node)— builds the full short URL through the outbound path processor pipelinesyncRedirects(NodeInterface $node)— deletes and recreates all redirects for the node (handles slug, destination, language, and publish status changes)deleteRedirects(NodeInterface $node)— removes all redirects associated with the noderesolveNodeBySlug(string $slug)— loads a short URL node by its slug valuegetUrlOptions(NodeInterface $node)— returns options array for URL generation (extensibility point for decorators)
SlugGenerator¶
Implements SlugGeneratorInterface. Generates slugs for the base36
and auto-increment modes.
Key methods:
generateBase36(int $length)— generates a random base36 slug usingrandom_bytes()generateAutoIncrement()— returns the next sequential number from the State API counter, with a database safety check
VisitTracker¶
Implements VisitTrackerInterface. Records visits and computes
statistics from the shorturl_visits table.
Tagged as backend_overridable, which means it can be swapped
out for an external analytics backend (Matomo, Google Analytics,
custom database) via service override.
Key methods:
trackVisit(int $nid, array $fields)— inserts a visit recordgetStats(int $nid)— returns the full statistics arraysupportsStats()— indicates whether inline statistics are available (returnsFALSEin overrides that delegate to external systems)
QrCodeGenerator¶
Implements QrCodeGeneratorInterface. Generates QR code images
using endroid/qr-code.
Key methods:
generateSvgDataUri(string $url)— returns a base64-encoded SVG data URI for inline embeddinggeneratePngResponse(string $url)— returns a Symfony Response with PNG contentgenerateSvgResponse(string $url)— returns a Symfony Response with SVG content
ShortUrlVisitMiddleware¶
HTTP middleware at priority 210 (above PageCache at 200). Intercepts
redirect responses bearing the X-Shorturl-Nid header and inserts
a visit row. Resolves country codes via Smart IP when available.
ShortUrlQrPathProcessor¶
Inbound path processor at priority 200. Rewrites /{slug}.qr
paths to /api/shorturl/qr/{slug} so that appending .qr to any
short URL serves its QR code.
URL generation¶
Short URLs are built through Drupal's outbound path processor
pipeline via ShortUrlBuilderTrait. This trait:
- Calls
PathProcessorManager::processOutbound()with the slug as the path (e.g./promo). - Applies any prefix from
$options['prefix'](e.g. a language prefix like/fr/promo). - Uses
$options['base_url']if set by a path processor, otherwise falls back to the current request's scheme and host.
This approach ensures short URLs include the correct language prefix and hostname, and allows decorator modules to inject additional context into the options array.
Hook implementations¶
Hook implementations are organized into dedicated classes:
| Class | Hooks |
|---|---|
ShortUrlEntityHooks |
node_presave, node_insert, node_update, node_delete, redirect_response_alter, entity_operation, entity_base_field_info |
ShortUrlFormHooks |
form_node_shorturl_form_alter, form_node_shorturl_edit_form_alter |
ShortUrlViewHooks |
entity_extra_field_info, node_view, theme |
ShortUrlViewsHooks |
views_data, views_data_alter |
Database schema¶
shorturl_visits table¶
| Column | Type | Description |
|---|---|---|
id |
serial | Primary key |
nid |
int | Short URL node ID |
langcode |
varchar(12) | Translation language code |
timestamp |
int | Unix timestamp |
referrer |
varchar(2048) | HTTP Referer header |
country_code |
varchar(2) | ISO 3166-1 alpha-2 country code |
ip_hash |
varchar(64) | SHA-256 hash of visitor IP |
Indexes: nid, nid + langcode, timestamp
Redirect entity additions¶
A shorturl_nid base field is added to the redirect entity type
to link redirects back to their source short URL node. This enables
efficient cleanup on node delete and status synchronization on
publish/unpublish.
Extending the module¶
Replacing the visit tracker¶
To delegate visit tracking to an external system:
# my_module.services.yml
services:
Drupal\shorturl\VisitTrackerInterface:
class: Drupal\my_module\ExternalVisitTracker
Your implementation should return FALSE from supportsStats()
if statistics are handled externally. The Statistics tab will be
hidden automatically.
Customizing slug generation¶
Override SlugGeneratorInterface to add custom slug algorithms:
services:
Drupal\shorturl\SlugGeneratorInterface:
class: Drupal\my_module\MySlugGenerator
Customizing QR codes¶
Override QrCodeGeneratorInterface to change QR code appearance,
size, error correction, or use a different library:
services:
Drupal\shorturl\QrCodeGeneratorInterface:
class: Drupal\my_module\MyQrCodeGenerator