Download the PHP package hatchyu/laravel-sequence without Composer

On this page you can find all versions of the php package hatchyu/laravel-sequence. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-sequence

Laravel Sequence Numbers

Concurrency-safe Laravel sequence numbers with database transactions, row-level locking, grouping, prefixes, and Eloquent model integration.

Latest Stable Version Total Downloads License PHP Laravel

The Problem: Generating sequential, human-readable numbers—like INV-0001 or ORD-2026-001—is surprisingly difficult in a highly concurrent Laravel application. Relying on simple database counts or max() queries inevitably leads to race conditions, duplicate numbers, and database query crashes.

The Solution: A concurrency-safe sequence number generator for Laravel using database transactions and row-level locking. It guarantees perfectly incremental, gapless numbers even under extreme server load. Effortlessly create formatted sequences with customized prefixes and zero-padding, isolate counters by dynamic groups (like per-tenant or per-year), and auto-assign them to your Eloquent models using a convenient HasSequence trait.

Quick summary: use the sequence() helper inside a DB transaction to generate concurrency-safe sequence numbers, or add the HasSequence trait to auto-assign them on Eloquent model creating.

Important constraint: This package intentionally requires a database transaction to guarantee correctness under concurrency.

How It Works

When To Use This Package

When Not To Use This Package

Requirements

Installation

Install via Composer:

Run your migrations (the package auto-loads its migrations via the service provider):

Optional: publish the config file if you want to customize table/connection/model:

Optional: publish the migration if you want to customize the table name or columns:

Tables

The package creates a sequences table which stores the current last_number per (name, group_by) tuple. The group_by column is a deterministic string token generated from the configured groupBy values.

If you use a custom model via config('sequence.model'), it must extend Eloquent Model and be backed by a table that contains name, group_by, and last_number columns. The package writes those attributes via forceFill(), so fillable is not required.

If you publish and customize the migration, keep the unique index on (name, group_by) and a numeric last_number column — those are required for correctness under concurrency.

Usage

Important: Sequence generation must run inside a DB transaction; the package will throw an exception if called outside one. This package intentionally requires a database transaction to guarantee correctness under concurrency. Use ->next() to reserve and return the next value.

Mental model

1) Simple sequential numbers

Generate an incrementing sequence ("1", "2", "3", ...):

2) Prefix and pad length

Provide a prefix and a pad numeric length (padded with zeros):

You can combine any prefix string with an integer padLength.

padLength behaves like PHP str_pad(..., STR_PAD_LEFT): the numeric part is left-padded with 0 up to the requested length, and if the number is already longer than that length, it is returned unchanged.

2b) Custom increment step

By default the package increments by 1. If you need 1, 6, 11, ... or any other step size, use step():

The first generated value still starts from the configured minimum. The step is applied to each subsequent reservation.

3) Dynamic parts in the output (e.g. year + sequence)

If you want codes like 202601, 202602, ... you can pass dynamic prefix values (for example date('Y')) and a suitable pad length:

This only prefixes the generated number with the current year. It does not create a separate counter per year.

For example, if the underlying sequence keeps incrementing across years, you might see values like 202601, 202602, ... and later 2027100, 2027101, ...

prefix() and format() only control how the final sequence value is displayed. They do not create a new counter or reset numbering.

groupBy() determines which counter row is used. Use it whenever numbering should reset by year, month, tenant, branch, or any other grouping key.

For common date-based scopes, you can also use the convenience helpers groupByYear(), groupByMonth(), and groupByDay().

If you want the number to reset for each new year, month, branch, or tenant, use grouping as well:

3b) Custom format templates

If you want a full template such as INV/20260318/0001, use format() and place a ? where the sequence number should go:

The ? placeholder is replaced with the generated number after padding is applied.

3c) Custom format callbacks

If you need full control over the final output, format() also accepts a callback. The callback receives the already padded numeric portion and must return the final sequence string:

This is useful when you need dynamic suffixes, more advanced string composition, or formatting that does not fit a single ? placeholder template.

Like prefix(), format() only changes how the final value is displayed. It does not create a separate counter by itself.

Without grouping, the date part in the formatted output can change while the underlying counter continues increasing. For example, you might see INV/20260318/0001, INV/20260318/0002, and later INV/20260319/0100, INV/20260319/0101, ...

If you also want the counter to reset per day, combine the format with grouping:

4) Grouped sequences (per parent, per branch, etc.)

Sometimes you want separate counters per group of values (branch, year, tenant, etc.). The package supports grouping by multiple keys or models.

Important: groupBy() changes which counter row is used. It does not automatically add those values to the output string. If you want the group key to also appear in the generated value, include it in the prefix or format template yourself.

Example: reset sequence per branch and year:

Notes:

Example with belongsTo():

Common recipes

Yearly reset with the year shown in the output:

Separate counters by multiple grouping keys (tenant, branch, year):

Invoice number with a date in the output and a per-day reset:

5) Auto-assign on Eloquent models (HasSequence)

Add the HasSequence trait to your model and provide a sequenceColumns() method that returns a SequenceColumnCollection. This supports one or many columns. Example:

Behavior notes for trait usage:

Example with a custom format on a model column:

Multiple columns example:

API reference

Example:

Example with direct fluent range configuration:

Example with config callback:

Note: config() is optional. The fluent sequence() builder forwards configuration methods to the underlying SequenceConfig, so you can chain methods like range(), bounded(), groupBy(), or format() directly. Use config() when you prefer an explicit callback or need to work with SequenceConfig itself.

Concurrency and transactions

Range and overflow

The package supports min/max ranges via range(), bounded(), and cyclingRange() on the fluent sequence() builder, or the same methods on SequenceConfig when configuring model sequences.

Notes:

Example (throw on overflow):

Example (cycle back to min):

See the error handling section below for a SequenceOverflowException catch example. Consult the config API in src/Support/SequenceConfig.php for exact methods and options.

Customization (Config)

After publishing the config file, you can customize:

Events

The package dispatches a Hatchyu\Sequence\Events\SequenceAssigned event whenever a number is reserved:

Event payload fields:

Testing

The package includes comprehensive unit tests and concurrency regression tests.

Unit Tests

Run the test suite with Pest:

Key test files:

Test coverage includes:

Concurrency Testing

For concurrency testing, use the regression script that simulates parallel processes:

This script:

Testing Best Practices

Example test:

Error handling & troubleshooting

The package throws Hatchyu\Sequence\Exceptions\SequenceException (a RuntimeException) and a few grouped subclasses with specific error codes:

You can catch either the base class or a specific subclass depending on how granular you want the handling to be. Each exception includes a specific error code for programmatic handling.

Example:

Common troubleshooting

FAQ

Does this package require a database transaction?

Yes. This package intentionally requires a database transaction to guarantee correctness under concurrency. It will throw a SequenceTransactionException if sequence generation runs outside an active transaction.

Why not just use max() + 1?

Because max() + 1 is not safe under concurrency. Two requests can read the same current maximum and generate the same next value. This package avoids that by using row-level locking inside a transaction.

Does prefix() or format() reset the counter?

No. prefix() and format() only change the rendered output. If you need separate counters per year, tenant, branch, or day, use groupBy(...) or the date grouping helpers.

Can I use this with Eloquent models?

Yes. Add the HasSequence trait and return a SequenceColumnCollection from sequenceColumns(). Your model creation flow still needs to run inside a database transaction.

Will this work for per-year or per-day numbering?

Yes, if you scope the counter with grouping. Use groupByYear(), groupByMonth(), groupByDay(), or groupBy(...) with your own keys.

Development

Running Tests

Note: the current test suite exercises the core generation logic against SQLite and includes standalone regression scripts. For production release confidence on MySQL or PostgreSQL, it is still a good idea to run one integration pass in an application that uses your target driver.

Regression Scripts

The scripts/ directory contains regression testing scripts:

Contribution

Contributions are welcome — open issues or PRs.

License

MIT. See LICENSE.


All versions of laravel-sequence with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
laravel/framework Version ^10.0||^11.0||^12.0||^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package hatchyu/laravel-sequence contains the following files

Loading the files please wait ...