Token (from MM 2.4)
The “Token” attribute generates a cryptographically random, immutable string (token) when a record is saved for the first time. Typical use cases:
Unique order numbers or reference numbers (e.g.
TKN-aB3xYqUK)Access keys or release links in the frontend
Internal reference IDs that must remain stable
The token is generated exactly once — when first saved, as long as the field is still empty.
Every subsequent save of the record leaves the existing token unchanged. Even a direct call
to setDataFor() does not overwrite an existing token (write-once protection at the
database level).
Note
The token is always unique. The “Unique values” option in the general attribute settings is therefore permanently active and cannot be disabled.
Warning
When duplicating (copying) a record in the backend, no token is carried over. The new item automatically receives its own new token when saved.
Installation
The attribute is installed via the Contao Manager or Composer:
composer require metamodels/attribute_token
Settings when Creating the Attribute
In addition to the general attribute settings (name, column name, description, override variants), the token attribute offers the following specific options:
Option |
Description |
|---|---|
Token character set |
Characters used for random generation. Possible inputs:
Default: |
Token character length |
Number of randomly generated characters (minimum: 3, default: 8). |
Token prefix |
Optional fixed text prepended to every token
(e.g. |
Examples of unique identifiers include the German ID and passport specifications with the characters 123456789CFGHJKMNPRTVWXYZ
and a length of 26 characters, or the Record Locator
known from airline tickets with six characters from 23456789ABCDEFGHJKMNPQRSTXYZ
— 0, 1, O, I, L are omitted for better readability.
The number of possible combinations V is derived from the number of possible characters
n and the token character length k — the formula is V = n**k.
With the default setting [a-z][A-Z][0-9], there are 62 characters n and a character
length k of 8, resulting in approximately 218 trillion possible combinations — with
three characters, there are only 238,328.
Settings in Render Settings
The token attribute has no specific render settings. In the attribute list of a render setting, the usual options are available:
Option |
Description |
|---|---|
Template |
Selection of a custom template for the output of the token value. If no template is specified, the output is as plain text. |
CSS class |
Optional CSS class added to the output element. |
Settings in the Input Form
When the token attribute is added to an input form, the field is fundamentally read-only
(readonly) in the backend. The following options are available:
Display
Option |
Description |
|---|---|
Backend class |
CSS classes for the display of the field in the backend form (e.g.
|
Overview (backend search)
Option |
Description |
|---|---|
Searchable |
The attribute is available in the backend as a search field. |
Note
The options “Required field”, “Always save”, and “Filterable” are not available for the token attribute, as the field is always saved internally and is read-only.
Filter Rules
The token attribute can be used with the following filter rules:
Filter rule |
Note |
|---|---|
Simple lookup |
Filters records by an exact token value; useful for URL-based access checks |
Custom SQL |
For more complex filters for combinations with additional parameters. |
Special Functions
Configuration via config.yaml
The maximum number of generation attempts before an exception is thrown can be adjusted
project-specifically in config/config.yaml:
1meta_models_attribute_token:
2 max_retries: 5 # Default: 3
Each attempt checks whether the generated token already exists in the database. If the
uniqueness check fails three times (or as many times as configured), a RuntimeException
is thrown.
Custom token generation via event
Via the event MetaModels\AttributeTokenBundle\Event\GenerateTokenEvent, the token
generation can be replaced or extended by custom code. If setToken() is called in the
listener, MetaModels skips the built-in random generation.
Example listener as src/EventListener/MyTokenListener.php:
1<?php
2
3use MetaModels\AttributeTokenBundle\Event\GenerateTokenEvent;
4
5class MyTokenListener
6{
7 public function onGenerateToken(GenerateTokenEvent $event): void
8 {
9 $prefix = $event->getAttribute()->get('token_prefix') ?? '';
10 $event->setToken($prefix . strtoupper(bin2hex(random_bytes(8))));
11 }
12}
Registration in config/services.yaml:
1App\EventListener\MyTokenListener:
2 tags:
3 - name: kernel.event_listener
4 event: MetaModels\AttributeTokenBundle\Event\GenerateTokenEvent
5 method: onGenerateToken
The available methods of the event:
Method |
Description |
|---|---|
|
Returns the token attribute (access to character set, length, prefix). |
|
The MetaModel item that is currently being saved. |
|
Sets a custom token; prevents the built-in generation. |
|
Returns the token set by the listener, or |
|
|
Write-once protection at the database level
Even if setDataFor() is called directly, MetaModels does not overwrite an existing
token value. The UPDATE query contains a condition WHERE column IS NULL OR column = '',
so a filled field always remains unchanged.
Database storage
The token is stored as varchar(255) NULL in the MetaModel table. An empty value is
stored as NULL (compatible with MySQL Strict Mode).