pimbay-php/sequence-formatter

Pattern formatter, initial value generator, random code generator, alphabet, and transformers for the PimBay Sequence Stack.

Maintainers

Package info

codeberg.org/pimbay-php/sequence-formatter

Homepage

Issues

Documentation

pkg:composer/pimbay-php/sequence-formatter

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

dev-main 2026-05-18 04:40 UTC

This package is auto-updated.

Last update: 2026-05-18 04:44:16 UTC


README

Latest Version on Packagist PHP Version License Code Coverage

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

TokenDescription
{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

TokenDescription
{R}One random character
{R4}Exactly 4 random characters
{R3..5}Random length between 3 and 5

Shared tokens

TokenOutput (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

PackageDescription
pimbay-php/sequenceInterfaces, results, exceptions
pimbay-php/sequence-formatterThis package
pimbay/sequence-number-sqlSQL snippets for number sequence adapters
pimbay-php/sequence-number-pdoPDO adapter — MySQL, MariaDB, PostgreSQL, SQLite
pimbay-php/sequence-number-pdo-mssqlPDO adapter — MSSQL

Test matrix

PHPStatus
8.3
8.4
8.5

License

Public domain — Unlicense

Created by Jan Sarmir · No conditions · No copyright