pimbay-php/sequence-contracts

Contracts, DTOs and exceptions for the PimBay Sequence Stack. Shared foundation for number and random sequence implementations.

Maintainers

Package info

codeberg.org/pimbay-php/sequence-contracts

Homepage

Issues

Documentation

pkg:composer/pimbay-php/sequence-contracts

Statistics

Installs: 2

Dependents: 1

Suggesters: 0

v1.0.0 2026-05-11 07:07 UTC

This package is auto-updated.

Last update: 2026-05-11 07:18:28 UTC


README

Latest Version on Packagist PHP Version License Code Coverage

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/clock as the only dependency — compatible with any PSR-20 clock implementation (Symfony, Laravel, or custom).
  • Testing Friendly: Includes an InMemoryNumberSequence for 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. Throws SequenceNotFoundException if the sequence does not exist.
  • SequenceResult DTO: A final readonly DTO 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, including MockClock provided by this package.
  • InMemoryNumberSequence: A simple, array-based implementation of NumberSequenceInterface included for easy testing and mocking in consumer projects.
  • MockClock: A test support class that implements ClockInterface, 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