PHPackages                             baraja-core/variable-generator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. baraja-core/variable-generator

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

baraja-core/variable-generator
==============================

Generate new variable symbol by last variable and selected strategy.

v2.0.4(4y ago)13.7k[1 PRs](https://github.com/baraja-core/variable-generator/pulls)1PHPPHP ^8.0CI failing

Since Jan 12Pushed 4mo ago1 watchersCompare

[ Source](https://github.com/baraja-core/variable-generator)[ Packagist](https://packagist.org/packages/baraja-core/variable-generator)[ Docs](https://github.com/baraja-core/variable-generator)[ RSS](/packages/baraja-core-variable-generator/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (10)Dependencies (10)Versions (15)Used By (1)

Variable Generator
==================

[](#variable-generator)

[![Integrity check](https://github.com/baraja-core/variable-generator/workflows/Integrity%20check/badge.svg)](https://github.com/baraja-core/variable-generator/workflows/Integrity%20check/badge.svg)

A smart PHP library for generating unique variable symbols, order numbers, and sequential identifiers in e-commerce applications. It handles complex problems like format specifications, transaction safety, duplicate prevention, and overflow management through pluggable strategies.

💡 Key Principles
----------------

[](#bulb-key-principles)

- **Automatic duplicate protection** - Uses locking mechanism to prevent concurrent generation of the same number
- **Pluggable strategies** - Choose from built-in strategies or implement your own formatting logic
- **Doctrine integration** - Automatic entity discovery for seamless database integration
- **Transaction safety** - Built-in lock management ensures data integrity in high-concurrency environments
- **Year-aware numbering** - Default strategy automatically resets sequences on year change
- **Zero configuration** - Works out of the box with sensible defaults

🏗️ Architecture Overview
------------------------

[](#building_construction-architecture-overview)

The library is built around a modular architecture with clear separation of concerns:

```
┌─────────────────────────────────────────────────────────────────┐
│                      VariableGenerator                          │
│                    (Main Entry Point)                           │
├─────────────────────────────────────────────────────────────────┤
│                              │                                  │
│         ┌────────────────────┼────────────────────┐             │
│         │                    │                    │             │
│         ▼                    ▼                    ▼             │
│  ┌──────────────┐    ┌──────────────┐    ┌──────────────┐       │
│  │VariableLoader│    │FormatStrategy│    │     Lock     │       │
│  │  (Interface) │    │  (Interface) │    │  (External)  │       │
│  └──────┬───────┘    └──────┬───────┘    └──────────────┘       │
│         │                   │                                   │
│         ▼                   ▼                                   │
│  ┌──────────────┐    ┌─────────────────────────────────┐        │
│  │DefaultOrder  │    │ ┌─────────────────────────────┐ │        │
│  │VariableLoader│    │ │YearPrefixIncrementStrategy  │ │        │
│  │  (Doctrine)  │    │ ├─────────────────────────────┤ │        │
│  └──────────────┘    │ │SimpleIncrementStrategy      │ │        │
│                      │ ├─────────────────────────────┤ │        │
│                      │ │Custom Strategy (Your Own)   │ │        │
│                      │ └─────────────────────────────┘ │        │
│                      └─────────────────────────────────┘        │
└─────────────────────────────────────────────────────────────────┘

```

### 🧩 Main Components

[](#jigsaw-main-components)

ComponentDescription`VariableGenerator`Main service class that orchestrates number generation with locking and strategy execution`VariableLoader`Interface for retrieving the last used number from your data source`FormatStrategy`Interface defining how the next number should be calculated`OrderEntity`Interface for Doctrine entities that enables automatic loader discovery`VariableGeneratorExtension`Nette DI extension for framework integration`VariableGeneratorAccessor`Accessor interface for lazy service injection### ⚙️ Built-in Strategies

[](#gear-built-in-strategies)

#### YearPrefixIncrementStrategy (Default)

[](#yearprefixincrementstrategy-default)

Generates numbers in format `YYXXXXXX` where `YY` is the current year and `XXXXXX` is an incrementing sequence:

```
Year: 2024
Format: 24000001, 24000002, 24000003, ...

Year: 2025 (automatic reset on year change)
Format: 25000001, 25000002, 25000003, ...

```

Features:

- Automatic year prefix based on current date
- Automatic sequence reset on year change
- Configurable total length (default: 8 characters)
- Overflow protection (expands length if needed)

#### SimpleIncrementStrategy

[](#simpleincrementstrategy)

A straightforward incrementing strategy that adds one to the previous number:

```
Input:  21000034
Output: 21000035

```

Features:

- Maintains consistent number length with zero-padding
- Configurable length (minimum: 4 characters)
- Falls back to year-prefixed first number if no previous exists

🚀 Basic Usage
-------------

[](#rocket-basic-usage)

### Creating the Generator

[](#creating-the-generator)

```
use Baraja\VariableGenerator\VariableGenerator;
use Baraja\VariableGenerator\Strategy\YearPrefixIncrementStrategy;

// With Doctrine EntityManager (automatic entity discovery)
$generator = new VariableGenerator(
    variableLoader: null,  // Auto-discovered from Doctrine
    strategy: null,        // Uses YearPrefixIncrementStrategy by default
    em: $entityManager,
);

// With custom variable loader
$generator = new VariableGenerator(
    variableLoader: new MyCustomVariableLoader(),
    strategy: new YearPrefixIncrementStrategy(length: 6),
);
```

### Generating Numbers

[](#generating-numbers)

```
// Generate next number (automatically retrieves last used number)
$newOrderNumber = $generator->generate();
// Result: 24000001 (if first order in 2024)

// Generate next number based on specific previous value
$newNumber = $generator->generate('24000034');
// Result: 24000035

// Get current (last used) number without generating new one
$current = $generator->getCurrent();
// Result: 24000034
```

### Using Custom Strategies

[](#using-custom-strategies)

```
use Baraja\VariableGenerator\Strategy\SimpleIncrementStrategy;

// Switch to simple increment strategy
$generator->setStrategy(new SimpleIncrementStrategy(length: 10));

// Or use custom strategy at initialization
$generator = new VariableGenerator(
    variableLoader: $loader,
    strategy: new SimpleIncrementStrategy(length: 8),
);
```

🔐 Duplicate Prevention
----------------------

[](#closed_lock_with_key-duplicate-prevention)

This library automatically protects against generating duplicate numbers in high-concurrency environments. The protection mechanism works as follows:

1. **Wait for existing transactions** - Before generating, the system waits if another process is currently generating
2. **Lock acquisition** - A 15-second transaction lock is acquired for the generation process
3. **Number generation** - The new number is calculated using the selected strategy
4. **Short protection window** - A 1-second lock remains to allow saving the new entity to database

```
// The generate() method handles all locking automatically
$number = $generator->generate();
// IMPORTANT: Save your entity immediately after generation!

// Custom transaction name for different entity types
$orderNumber = $generator->generate(transactionName: 'order-generator');
$invoiceNumber = $generator->generate(transactionName: 'invoice-generator');
```

> **Warning:** You must save the generated number to your database within 1 second. After that, the lock is released and another process may generate the same number.

🔧 Custom Implementations
------------------------

[](#wrench-custom-implementations)

### Custom Variable Loader

[](#custom-variable-loader)

Implement the `VariableLoader` interface to retrieve the last number from your data source:

```
use Baraja\VariableGenerator\VariableLoader;

final class MyCustomVariableLoader implements VariableLoader
{
    public function __construct(
        private PDO $pdo,
    ) {
    }

    public function getCurrent(): ?string
    {
        $stmt = $this->pdo->query(
            'SELECT order_number FROM orders ORDER BY id DESC LIMIT 1'
        );
        $result = $stmt->fetchColumn();

        return $result !== false ? (string) $result : null;
    }
}
```

### Custom Format Strategy

[](#custom-format-strategy)

Implement the `FormatStrategy` interface for custom number formatting:

```
use Baraja\VariableGenerator\Strategy\FormatStrategy;

final class MonthlyResetStrategy implements FormatStrategy
{
    public function generate(string $last): string
    {
        $prefix = date('ym'); // e.g., "2401" for January 2024

        if (str_starts_with($last, $prefix)) {
            $sequence = (int) substr($last, 4);
            return $prefix . str_pad((string) ($sequence + 1), 4, '0', STR_PAD_LEFT);
        }

        return $this->getFirst();
    }

    public function getFirst(): string
    {
        return date('ym') . '0001';
    }
}
```

### Doctrine Entity Integration

[](#doctrine-entity-integration)

Implement the `OrderEntity` interface on your Doctrine entity for automatic discovery:

```
use Baraja\VariableGenerator\Order\OrderEntity;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity]
class Order implements OrderEntity
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string', unique: true)]
    private string $number;

    #[ORM\Column(type: 'datetime')]
    private \DateTime $insertedDate;

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getNumber(): string
    {
        return $this->number;
    }

    public function getInsertedDate(): \DateTime
    {
        return $this->insertedDate;
    }
}
```

> **Note:** If your entity has `getInsertedDate()` method, the `DefaultOrderVariableLoader` will automatically filter orders from the last year when searching for the latest number.

⚡ Nette Framework Integration
-----------------------------

[](#zap-nette-framework-integration)

Register the extension in your configuration:

```
extensions:
    variableGenerator: Baraja\VariableGenerator\VariableGeneratorExtension
```

Then inject the generator into your services:

```
final class OrderFacade
{
    public function __construct(
        private VariableGenerator $generator,
    ) {
    }

    public function createOrder(array $data): Order
    {
        $order = new Order();
        $order->setNumber((string) $this->generator->generate());
        // ... save order

        return $order;
    }
}
```

For lazy loading, use the accessor:

```
public function __construct(
    private VariableGeneratorAccessor $generatorAccessor,
) {
}

public function process(): void
{
    $generator = $this->generatorAccessor->get();
    // ...
}
```

⚠️ Important Considerations
---------------------------

[](#warning-important-considerations)

1. **Save immediately** - Always save the generated number to your database immediately after calling `generate()`. The lock protection lasts only 1 second.
2. **Single entity per interface** - If using automatic Doctrine discovery, only one entity can implement `OrderEntity`. For multiple entities, implement custom `VariableLoader` services.
3. **No caching** - The `VariableLoader::getCurrent()` method should always fetch real data from the database. Never use cached values.
4. **Transaction safety** - The generator uses the `baraja-core/lock` library for thread safety. Make sure this dependency is properly installed.

📦 Installation
--------------

[](#package-installation)

It's best to use [Composer](https://getcomposer.org) for installation, and you can also find the package on [Packagist](https://packagist.org/packages/baraja-core/variable-generator) and [GitHub](https://github.com/baraja-core/variable-generator).

To install, simply use the command:

```
$ composer require baraja-core/variable-generator
```

You can use the package manually by creating an instance of the internal classes, or register a DIC extension to link the services directly to the Nette Framework.

### Requirements

[](#requirements)

- PHP 8.0 or higher
- `baraja-core/lock` package (installed automatically)
- Doctrine ORM (optional, for automatic entity discovery)
- Nette DI (optional, for framework integration)

👤 Author
--------

[](#bust_in_silhouette-author)

**Jan Barášek** -

📄 License
---------

[](#page_facing_up-license)

`baraja-core/variable-generator` is licensed under the MIT license. See the [LICENSE](https://github.com/baraja-core/variable-generator/blob/master/LICENSE) file for more details.

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance52

Moderate activity, may be stable

Popularity18

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity66

Established project with proven stability

 Bus Factor1

Top contributor holds 95.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~40 days

Recently: every ~83 days

Total

10

Last Release

1588d ago

Major Versions

v1.1.0 → v2.0.02021-02-09

PHP version history (3 changes)v1.0.0PHP &gt;=7.4.0

v1.1.0PHP ^7.4 || ^8.0

v2.0.0PHP ^8.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3382204?v=4)[baraja](/maintainers/baraja)[@baraja](https://github.com/baraja)

---

Top Contributors

[![janbarasek](https://avatars.githubusercontent.com/u/4738758?v=4)](https://github.com/janbarasek "janbarasek (39 commits)")[![dependabot-preview[bot]](https://avatars.githubusercontent.com/in/2141?v=4)](https://github.com/dependabot-preview[bot] "dependabot-preview[bot] (2 commits)")

---

Tags

generatorinvoicenumberordershopvariable

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/baraja-core-variable-generator/health.svg)

```
[![Health](https://phpackages.com/badges/baraja-core-variable-generator/health.svg)](https://phpackages.com/packages/baraja-core-variable-generator)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
