pimbay-php / sequence-random-doctrine
Doctrine DBAL implementation of RandomSequenceInterface for the PimBay Sequence Stack (MySQL, MariaDB, PostgreSQL, SQLite, MSSQL).
Package info
codeberg.org/pimbay-php/sequence-random-doctrine
pkg:composer/pimbay-php/sequence-random-doctrine
Requires
- php: >=8.3
- doctrine/dbal: ^2.13 || ^3.0 || ^4.0
- pimbay-php/sequence: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0
- pimbay/sequence-random-sql: ^1.0
README
Doctrine DBAL implementation of RandomSequenceInterface for the PimBay Sequence Stack. Supports MySQL, MariaDB, PostgreSQL, SQLite, and MSSQL.
Code uniqueness is guaranteed by a UNIQUE(group_id, code) database constraint — no application-level locking required.
Installation
composer require pimbay-php/sequence-random-doctrine
Usage
Schema setup
use PimBay\Sequence\Random\Doctrine\SchemaManager;
$schema = new SchemaManager($connection);
$schema->createTable(); // default table: pimbay_sequence_random
$schema->createTable('my_custom_table'); // custom table name
createTable() is idempotent — safe to call on every deploy.
Basic usage
use PimBay\Sequence\Random\Doctrine\RandomSequence;
use PimBay\Sequence\Random\Doctrine\Adapter\DriverDetectingAdapter;
$adapter = new DriverDetectingAdapter($connection);
$sequence = new RandomSequence($connection, $adapter, $generatorFactory);
// Create a sequence — binds a code generator to a group+name pair
$result = $sequence->createSequence('vouchers', 'christmas_2026', $generator, ['channel' => 'email']);
// Generate unique codes
$code = $sequence->nextCode('vouchers', 'christmas_2026', context: ['country' => 'SK'], metadata: ['batch' => 'q4']);
// Reserve a fixed code — prevents random generation of the same code
$sequence->insertCode('vouchers', 'christmas_2026', 'VIANOCE2026', ['source' => 'import_2026_q1']);
// Check existence — scoped to group
$exists = $sequence->exists('vouchers', 'VIANOCE2026');
// Read current sequence state
$state = $sequence->getCurrent('vouchers', 'christmas_2026');
// $state->group, $state->name, $state->metadata, $state->createdAt, $state->generatorConfig
Adapters
DriverDetectingAdapter resolves the correct adapter from the DBAL driver automatically:
use PimBay\Sequence\Random\Doctrine\Adapter\DriverDetectingAdapter;
// Auto-detects driver and picks the right adapter
$adapter = new DriverDetectingAdapter($connection);
// Custom table name — must match the table used in RandomSequence
$adapter = new DriverDetectingAdapter($connection, 'my_custom_table');
// Custom adapter map — extend with your own driver
$adapter = new DriverDetectingAdapter($connection, 'my_table', [MyOracleDriver::class => MyOracleAdapter::class]);
Concrete adapters can be used directly:
use PimBay\Sequence\Random\Doctrine\Adapter\MysqlAdapter;
use PimBay\Sequence\Random\Doctrine\Adapter\PostgresAdapter;
use PimBay\Sequence\Random\Doctrine\Adapter\SqliteAdapter;
use PimBay\Sequence\Random\Doctrine\Adapter\MssqlAdapter;
$adapter = new MysqlAdapter($connection, $tableName);
Custom table name
Pass the same table name consistently to RandomSequence, DriverDetectingAdapter, and SchemaManager:
$tableName = 'my_voucher_sequences';
$schema = new SchemaManager($connection);
$schema->createTable($tableName);
$adapter = new DriverDetectingAdapter($connection, $tableName);
$sequence = new RandomSequence($connection, $adapter, $generatorFactory, $tableName);
Exception handling
All exceptions implement SequenceExceptionInterface:
use PimBay\Sequence\Exception\SequenceExceptionInterface;
use PimBay\Sequence\Exception\SequenceNotFoundException;
use PimBay\Sequence\Exception\SequenceAlreadyExistsException;
use PimBay\Sequence\Exception\SequenceCollisionException;
use PimBay\Sequence\Exception\CodeAlreadyExistsException;
try {
$code = $sequence->nextCode('vouchers', 'christmas_2026');
} catch (SequenceCollisionException $e) {
// max attempts exceeded — generator alphabet too small or sequence exhausted
} catch (SequenceNotFoundException $e) {
// sequence does not exist — createSequence() was not called
} catch (SequenceExceptionInterface $e) {
// catch-all for any sequence exception
}
Doctrine Migrations
applyToSchema() integrates with Doctrine Migrations:
use PimBay\Sequence\Random\Doctrine\SchemaManager;
$schema = new Schema();
(new SchemaManager($connection))->applyToSchema($schema);
Constraint names match the SQL schema files (uq_{table}_*, fk_{table}_*) — no diff noise on subsequent migrations.
Raw SQL access
SQL constants are available for custom migration tooling:
use PimBay\Sequence\Random\Doctrine\SchemaManager;
// Per-driver statement arrays
SchemaManager::MYSQL_CREATE_TABLE_STATEMENTS;
SchemaManager::POSTGRES_CREATE_TABLE_STATEMENTS;
SchemaManager::SQLITE_CREATE_TABLE_STATEMENTS;
SchemaManager::MSSQL_CREATE_TABLE_STATEMENTS;
// Full SQL string (statements joined with \n\n)
$sql = (new SchemaManager($connection))->getCreateTableSql('my_table');
Test Matrix
| PHP 8.3 | PHP 8.4 | PHP 8.5 | |
|---|---|---|---|
| DBAL 2 | ✅ | — | — |
| DBAL 3 | ✅ | ✅ | ✅ |
| DBAL 4 | ✅ | ✅ | ✅ |
| MariaDB 11 | ✅ | ✅ | ✅ |
| SQLite | ✅ | ✅ | ✅ |
DBAL 2 tested on PHP 8.3 only — EOL since early 2026. MySQL, PostgreSQL, and MSSQL covered by unit tests with DBAL Connection mock.
Packages in the stack
| Package | Description |
|---|---|
pimbay/sequence-random-sql | SQL snippets for random sequence adapters |
pimbay-php/sequence | Interfaces, results, exceptions |
pimbay-php/sequence-formatter | Pattern formatter, code generator, alphabet |
pimbay-php/sequence-random-pdo | PDO adapter for random sequences |
pimbay-php/sequence-random-doctrine | This package — Doctrine DBAL adapter |
License
Public domain — Unlicense
Created by Jan Sarmir · No conditions · No copyright