pimbay-php / sequence-formatter
Pattern formatter, initial value generator, random code generator, alphabet, and transformers for the PimBay Sequence Stack.
Requires
- php: >=8.3
- pimbay-php/sequence: ^1.0
- psr/clock: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- phpbench/phpbench: ^1.6
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2026-05-18 04:44:16 UTC
README
Pattern formatter, initial value generator, random code generator, and alphabet utilities for the PimBay Sequence Stack.
Installation
composer require pimbay-php/sequence-formatter
Pattern Syntax
Patterns are strings with {token} placeholders. Literals outside tokens pass through unchanged.
Sequence tokens — PatternFormatter / InitialValueGenerator
| Token | Description |
|---|---|
{N} | Single digit, right-to-left indexed |
{N4} / {NNNN} | Fixed padding — 4 digits |
{N3..5} | Dynamic range — min 3, max 5 digits |
{N+} | Unlimited — full number, no padding |
Random tokens — CodeGenerator
| Token | Description |
|---|---|
{R} | One random character |
{R4} | Exactly 4 random characters |
{R3..5} | Random length between 3 and 5 |
Shared tokens
| Token | Output (2026-04-16) |
|---|---|
{YYYY} | 2026 |
{YY} | 26 |
{MM} | 04 |
{DD} | 16 |
{key} | runtime context value |
PatternFormatter
Formats a sequence integer into a business identifier string. Implements ClockAwareInterface — inject clock via DI, not per call.
use PimBay\Sequence\Formatter\PatternFormatter;
$formatter = new PatternFormatter('INV/{YYYY}/{N4}');
$formatter->setClock($clock);
echo $formatter->format(125); // → INV/2026/0125
// Context tokens
$formatter = new PatternFormatter('{branch}/{YY}/{N4}');
$formatter->setClock($clock);
echo $formatter->format(1, ['branch' => 'SK']); // → SK/26/0001
InitialValueGenerator
Generates the $initialValue parameter for nextNumber(). The {N} segment receives the sequence part — all other tokens form the prefix. Context values must be numeric.
use PimBay\Sequence\Formatter\InitialValueGenerator;
$gen = new InitialValueGenerator('{YY}{MM}{N4}');
$gen->setClock($clock);
$initialValue = $gen->generate(1); // → 26040001 for 2026-04
$sequence->nextNumber('invoices', '2026-04', $initialValue);
CodeGenerator
Generates random codes from a pattern and alphabet. Implements CodeGeneratorInterface and ClockAwareInterface.
use PimBay\Sequence\Formatter\CodeGenerator;
use PimBay\Sequence\Formatter\Alphabet;
$gen = new CodeGenerator('{R4}-{R4}', Alphabet::UNAMBIGUOUS_UPPER);
echo $gen->generate(); // → 'A3KM-7PXT'
// Variable length
$gen = new CodeGenerator('{R3..6}', Alphabet::ALPHANUMERIC);
// Non-repeatable — no character repeated within one code
$gen = new CodeGenerator('{R6}', Alphabet::ALPHANUMERIC, repeatable: false);
// Date prefix — inject clock
$gen = new CodeGenerator('{YY}{MM}-{R4}', Alphabet::UNAMBIGUOUS_UPPER);
$gen->setClock($clock);
echo $gen->generate(); // → '2604-A3KM'
Configuration is serializable for storage alongside a sequence group:
$data = $gen->toArray();
$factory = new \PimBay\Sequence\Formatter\CodeGeneratorFactory();
$gen = $factory->create($data);
$gen->setClock($clock);
Alphabet
use PimBay\Sequence\Formatter\Alphabet;
Alphabet::NUMERIC // '0123456789'
Alphabet::UNAMBIGUOUS_UPPER // digits + uppercase, excludes look-alikes (B,G,I,O,S,0,1)
Alphabet::BASE36 // digits + lowercase
Alphabet::BASE58 // Bitcoin alphabet — no 0/O/I/l
Alphabet::URL_SAFE // alphanumeric + '-_'
// Custom — validates min length, whitespace, duplicates
$alpha = Alphabet::custom('ACDEF', '12345'); // → 'ACDEF12345'
Full list: NUMERIC, ALPHA_LOWER, ALPHA_UPPER, ALPHA, ALPHANUMERIC, UNAMBIGUOUS_NUMERIC, UNAMBIGUOUS_ALPHA_LOWER, UNAMBIGUOUS_ALPHA_UPPER, UNAMBIGUOUS_ALPHA, UNAMBIGUOUS, UNAMBIGUOUS_UPPER, URL_SAFE, BASE16, BASE32, BASE36, BASE58, BASE62.
Compiled Variants
Pre-compile patterns for high-throughput scenarios where patterns cannot be cached via DI (batch jobs, queue workers).
use PimBay\Sequence\Formatter\Compiler\PatternCompiler;
$compiled = (new PatternCompiler())->compile('{YY}/{MM}/{N4}');
$compiled->setClock($clock);
// Serialize to cache
$cache->set('pattern:invoice', serialize($compiled));
// Restore — clock must be re-injected after deserialization
$compiled = unserialize($cache->get('pattern:invoice'));
$compiled->setClock($clock);
foreach ($invoices as $seq) {
echo $compiled->format($seq);
}
Benchmark results (PHP 8.3, OPcache + JIT):
| Scenario | ~Time |
|---|---|
new PatternFormatter per call | ~4 μs |
CompiledPattern from cache | ~0.9 μs |
Shared PatternFormatter (DI-injected) | ~0.8 μs |
Full benchmark results and interactive charts
Transformers
Convert a sequence integer into a compact or obfuscated string. Independent of PatternFormatter.
use PimBay\Sequence\Formatter\Transformer\BaseNTransformer;
use PimBay\Sequence\Formatter\Transformer\Obfuscator32Transformer;
use PimBay\Sequence\Formatter\Transformer\LuhnChecksumTransformer;
use PimBay\Sequence\Formatter\Transformer\ModuloChecksumTransformer;
$t = new BaseNTransformer(Alphabet::BASE36);
echo $t->transform(1000); // → 'rs'
echo $t->inverse('rs'); // → 1000
$t = new Obfuscator32Transformer(Alphabet::BASE36, key: 0x5A3CF1B2);
$encoded = $t->transform(1);
echo $t->inverse($encoded); // → 1
$t = new LuhnChecksumTransformer();
echo $t->transform(125); // → '1255'
echo $t->inverse('1255'); // → 125
$t = new ModuloChecksumTransformer(modulus: 10);
echo $t->transform(125); // → '1258'
BaseNTransformer, LuhnChecksumTransformer, Obfuscator32Transformer, and Obfuscator64Transformer implement InvertibleTransformerInterface — decoding via inverse().
OverflowBehaviour
use PimBay\Sequence\Formatter\OverflowBehaviour;
// THROW (default) — throws OverflowException when value or length limit exceeded
// SILENT — allows overflow, caller is responsible for checking the result
new PatternFormatter('{N4}', overflow: OverflowBehaviour::SILENT);
Exceptions
All exceptions extend FormatterException implements SequenceExceptionInterface:
use PimBay\Sequence\Formatter\Exception\ContextException; // missing clock or context key
use PimBay\Sequence\Formatter\Exception\InvalidPatternException; // invalid pattern syntax
use PimBay\Sequence\Formatter\Exception\OverflowException; // value or length exceeded
use PimBay\Sequence\Formatter\Exception\TransformerException; // invalid alphabet, key or value
use PimBay\Sequence\Formatter\Exception\ConfigurationException; // invalid fromArray() / factory data
Packages in the stack
| Package | Description |
|---|---|
pimbay-php/sequence | Interfaces, results, exceptions |
pimbay-php/sequence-formatter | This package |
pimbay/sequence-number-sql | SQL snippets for number sequence adapters |
pimbay-php/sequence-number-pdo | PDO adapter — MySQL, MariaDB, PostgreSQL, SQLite |
pimbay-php/sequence-number-pdo-mssql | PDO adapter — MSSQL |
Test matrix
| PHP | Status |
|---|---|
| 8.3 | ✅ |
| 8.4 | ✅ |
| 8.5 | ✅ |
License
Public domain — Unlicense
Created by Jan Sarmir · No conditions · No copyright