pimbay-php / sequence-contracts
Contracts, DTOs and exceptions for the PimBay Sequence Stack. Shared foundation for number and random sequence implementations.
Requires
- php: >=8.3
- psr/clock: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^11.0
README
The pimbay-php/sequence-contracts package provides the foundational interfaces, Data Transfer Objects (DTOs), and exceptions for the entire PimBay Sequence Stack.
It defines the core contracts for atomic sequence generation and ensures deterministic testing through PSR-20 clock abstraction.
This package is designed for maximum modularity, acting as the bedrock for all other components in the Sequence Stack.
Key Features
- Atomic Consistency: Focused on preventing duplicates in high-concurrency environments.
- PSR-20 Clock: Uses
psr/clockas the only dependency — compatible with any PSR-20 clock implementation (Symfony, Laravel, or custom). - Testing Friendly: Includes an
InMemoryNumberSequencefor rapid unit testing. - Global Standard: Built for PHP 8.3+ with strict typing and PSR-4 compliance.
- PHPStan Ready: Fully type-hinted for maximum static analysis compatibility (Level Max).
Core Features
NumberSequenceInterface(PimBay\SequenceContracts\Number\NumberSequenceInterface): Defines the contract for generating and retrieving number sequences, ensuring atomic integrity.nextNumber(string $group, string $name, int $initialValue = 1, array $metadata = []): int: Performs an atomic increment and returns the new value.getCurrent(string $group, string $name): SequenceResult: Retrieves the last generated value and its metadata without incrementing. ThrowsSequenceNotFoundExceptionif the sequence does not exist.
SequenceResultDTO: Afinal readonlyDTO that encapsulates the state of a sequence, including its last value, metadata, creation, and update timestamps.Psr\Clock\ClockInterface(PSR-20): Used directly as the clock abstraction — no custom wrapper. Any PSR-20 compliant clock implementation can be injected, includingMockClockprovided by this package.InMemoryNumberSequence: A simple, array-based implementation ofNumberSequenceInterfaceincluded for easy testing and mocking in consumer projects.MockClock: A test support class that implementsClockInterface, allowing developers to "freeze" or advance time in tests.
Installation
You can install the package via Composer:
composer require pimbay-php/sequence-contracts
Usage
NumberSequenceInterface
This interface defines how to interact with any number sequence implementation:
<?php
declare(strict_types=1);
namespace App;
use PimBay\SequenceContracts\Number\NumberSequenceInterface;
use PimBay\SequenceContracts\Dto\SequenceResult;
use PimBay\SequenceContracts\Exception\SequenceNotFoundException;
class MyService
{
public function __construct(private readonly NumberSequenceInterface $numberSequence)
{
}
public function generateOrderNumber(string $platform): string
{
$group = 'order';
$name = date('Y');
$initialValue = 1000;
$metadata = ['platform' => $platform];
$nextNumber = $this->numberSequence->nextNumber($group, $name, $initialValue, $metadata);
return "ORD-{$nextNumber}";
}
public function getCurrentInvoiceNumber(): ?SequenceResult
{
try {
return $this->numberSequence->getCurrent('invoice', date('Y'));
} catch (SequenceNotFoundException $e) {
return null; // Invoice sequence not yet created
}
}
}
MockClock — testing with controlled time
MockClock implements Psr\Clock\ClockInterface and allows freezing or advancing time in tests:
<?php
declare(strict_types=1);
namespace App\Tests;
use PHPUnit\Framework\TestCase;
use PimBay\SequenceContracts\InMemory\InMemoryNumberSequence;
use PimBay\SequenceContracts\Test\Support\MockClock;
final class MyNumberSequenceTest extends TestCase
{
public function testSequenceCreationTimestamp(): void
{
$mockClock = new MockClock(new \DateTimeImmutable('2026-04-25 10:00:00'));
$sequence = new InMemoryNumberSequence($mockClock);
$result = $sequence->nextNumber('test', 'first');
self::assertSame(1, $result);
self::assertEquals($mockClock->now(), $sequence->getCurrent('test', 'first')->createdAt);
// Advance time and verify updatedAt changes
$mockClock->advance('+1 hour');
$sequence->nextNumber('test', 'first');
self::assertNotEquals(
$sequence->getCurrent('test', 'first')->createdAt,
$sequence->getCurrent('test', 'first')->updatedAt,
);
}
}
Test Matrix
This package is rigorously tested across multiple PHP versions to ensure compatibility and reliability.
| PHP Version |
|---|
| 8.3 |
| 8.4 |
| 8.5 |
Contribution
Contributions are welcome. Please ensure that your code adheres to the existing coding standards and all tests pass. Open an issue or submit a pull request for any new features or bug fixes.
License
Public domain — Unlicense
Created by Jan Sarmir · No conditions · No copyright