承接 madebyclowd/laravel-auto-sequence 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

madebyclowd/laravel-auto-sequence

Composer 安装命令:

composer require madebyclowd/laravel-auto-sequence

包简介

A concurrency-safe and customizable sequence number generator for Laravel Eloquent models, with support for database/Redis locking and soft deletes.

README 文档

README

Latest Version on Packagist Total Downloads License

A concurrency-safe and customizable sequence number generator for Laravel Eloquent models (e.g., Invoices, Orders, CRM records, etc.).

Features

  • Concurrency Safety: Utilizes pessimistic database locking (SELECT ... FOR UPDATE) or Redis-based distributed locks to prevent duplicate number generation.
  • Hi/Lo Pre-Allocation Caching: Optionally allocates sequence numbers in blocks (e.g., 50 at a time) and increments them in-memory to reduce database lock contention.
  • Composite Key Partitioning: Segregates counters using composite primary keys ['module', 'type_code', 'period', 'scope'].
  • Period Resets: Automatically resets counters on date boundaries (daily, weekly, monthly, yearly) or custom fiscal periods.
  • Dynamic Rules & Scopes: Resolves type prefixes from model relations (e.g. $invoice->branch->code) and scopes sequences by organizational units (e.g. $invoice->tenant_id).
  • Flexible Format Placeholders: Supports template placeholders like date tokens ({YYYY}, {MM}, {date:d-M-Y}), dynamic model attributes ({attribute:customer_code}), and random strings ({rand:8}).
  • Verification & Repair Commands: Includes Artisan commands to audit model records, detect counter drift, and repair sequence state.

Installation

Install the package via Composer:

composer require madebyclowd/laravel-auto-sequence

Run the interactive installation wizard to publish the configuration file, database migrations, AI developer skills, and run the database migrations:

php artisan sequence:install

Basic Usage

1. Implement and Configure Your Model

Add the AutoSequence contract and use the HasSequenceNumber trait on your Eloquent model:

use MadeByClowd\AutoSequence\Contracts\AutoSequence;
use MadeByClowd\AutoSequence\Traits\HasSequenceNumber;
use Illuminate\Database\Eloquent\Model;

class Invoice extends Model implements AutoSequence
{
    use HasSequenceNumber;

    /**
     * Return the sequence configurations for the model.
     */
    public function getSequenceConfig(): array
    {
        return [
            'number' => [
                'module' => 'invoice',
                'type_code' => 'INV',
                'period' => 'monthly', // daily, weekly, monthly, yearly, never (or custom date formats)
                'format_template' => '{type_code}-{YYYY}-{MM}-{seq:5}', // Outputs: INV-2026-06-00001
                'pad_length' => 5,
            ]
        ];
    }
}

2. Manual Override Protection

If you manually assign a value to the sequenced attribute before saving, the package will respect it and skip generation:

$invoice = new Invoice();
$invoice->number = 'MANUAL-999';
$invoice->save(); // Bypasses sequence generator, keeping 'MANUAL-999'

Advanced Usage

1. Dynamic Type Code Resolution (type_relation)

Resolve the type code prefix from a model relationship dynamically (e.g., Bali branch DPS vs Jakarta branch JKT):

'number' => [
    'module' => 'invoice',
    'type_relation' => 'branch', // Calls $model->branch->code
    'default_type' => 'HQ',       // Fallback if relation is missing
    'period' => 'yearly',
    'format_template' => '{type_code}-{YYYY}-{seq:5}',
]

To use a relationship column other than code:

'type_relation' => [
    'relation' => 'category',
    'column' => 'id_code',
]

2. Multi-Tenant Scoping (scope)

Isolate sequence pools across tenants or branches by specifying a scoping model attribute:

'number' => [
    'module' => 'invoice',
    'type_code' => 'INV',
    'scope' => 'tenant_id', // Evaluates $model->tenant_id dynamically to separate counters
    'format_template' => '{type_code}-{YYYY}-{seq:5}',
]

3. Custom Reset Callables (Fiscal Calendar)

Provide a closure or a custom class string to partition sequences by custom dates (e.g., fiscal years starting in April):

'number' => [
    'module' => 'invoice',
    'type_code' => 'INV',
    'period' => function ($model) {
        $createdAt = $model->created_at ?? now();
        $year = $createdAt->month >= 4 ? $createdAt->year : $createdAt->year - 1;
        return "FY{$year}";
    },
    'format_template' => '{type_code}-{period}-{seq:5}',
]

4. Custom PHP Date Formatting ({date:FORMAT})

Format the template using standard PHP date character parameters:

'format_template' => '{type_code}-{date:d-M-Y}-{seq:5}' // INV-16-Jun-2026-00001

5. Multi-Column Sequences

Generate sequences for multiple attributes on a single model:

public function getSequenceConfig(): array
{
    return [
        'invoice_number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'format_template' => '{type_code}-{YYYY}-{seq:5}',
        ],
        'internal_ref' => [
            'module' => 'internal',
            'type_code' => 'REF',
            'period' => 'never',
            'format_template' => '{type_code}-{seq:8}',
        ]
    ];
}

6. Closure Format Templates & Nested Relation Placeholders

Customize your formatting templates dynamically using closures or fetch nested relation attributes using dot-notation:

'number' => [
    'module' => 'invoice',
    'type_code' => 'INV',
    // 1. Fetching a nested relationship attribute:
    'format_template' => 'INV-{attribute:branch.company.code}-{seq:5}', 
    
    // 2. Closure-based template:
    'format_template' => function ($model) {
        return 'INV-' . ($model->is_priority ? 'URGENT' : 'NORMAL') . '-{seq:5}';
    }
]

7. Additional Configuration Options

The following additional configuration options are supported within the model sequence settings:

'number' => [
    'module' => 'invoice',
    'type_code' => 'INV',
    'format_template' => '{type_code}-{seq:5}',
    
    // Set a custom starting value (defaults to 1)
    'start_value' => 1000, 
    
    // Set a custom increment step size (defaults to 1)
    'step' => 2, 
    
    // Set a maximum limit. Throws a SequenceExhaustedException if exceeded
    'max_value' => 99999, 
    
    // Enforce sequence integrity. Throws a AutoSequenceException if a manual value is set before saving
    'allow_manual' => false, 
    
    // Enable D365 continuous sequence (recycles deleted numbers automatically)
    'continuous' => true,
    
    // Database connection override for this specific sequence
    'connection' => 'tenant_db_connection', 
]

8. Soft Deletes & Concurrency Best Practices

To ensure data integrity and prevent service disruption in high-volume production systems, the package implements the following behaviors:

  • Soft Deletes Protection: If your Eloquent model uses Laravel's SoftDeletes trait, deleting a record (soft delete) will not trigger sequence number recycling. The sequence number remains reserved on the soft-deleted record in the database. This allows restoring the model via $model->restore() without causing duplicate sequence collisions. The sequence number is only recycled when the model is permanently deleted via $model->forceDelete().
  • Preventing PHP-FPM Thread Exhaustion: Under the database locking driver, the package automatically sets session-level or local transaction-level lock wait timeouts on the database connection (using MySQL's innodb_lock_wait_timeout, Postgres's lock_timeout, SQL Server's LOCK_TIMEOUT, or SQLite's busy_timeout). If a transaction holds a sequence lock for too long, subsequent requests fail fast with a SequenceLockException after the configured timeout (default 5s) instead of blocking indefinitely, preventing worker exhaustion and gateway 502/504 errors.
  • Pre-Allocation & Transaction Modes: High-performance pre-allocation (pre_allocation.enabled => true) cannot be used together with the 'gapless' transaction mode. In 'gapless' mode, a rolled-back transaction would roll back the database counter but keep the pre-allocated block in memory/cache, resulting in duplicate sequence collisions. To use pre-allocation, set transaction_mode => 'gap_tolerant'.

Manual Generation (Facade)

Inject sequence values programmatically (e.g. in custom jobs, observers, or seeds):

use MadeByClowd\AutoSequence\Facades\Sequence;

// Fetch and increment next sequence value (with optional connection, start value, step, continuous, max value)
$number = Sequence::generate(
    'order', 
    'SO', 
    '202606', 
    '{type_code}-{YYYY}-{seq:5}', 
    5, 
    'tenant_1',
    null,       // $model (optional)
    null,       // $connection (optional override)
    1,          // $startValue (optional, default 1)
    1,          // $step (optional, default 1)
    false,      // $continuous (optional, default false)
    99999       // $maxValue (optional, default null)
);

// Recycle a sequence number manually (inserts it back into sequence_recycled table)
Sequence::recycle('order', 'SO', '202606', 'tenant_1', 105);

// Get current value without incrementing
$current = Sequence::getCurrent('order', 'SO', '202606', 'tenant_1');

// Reset or offset the counter
Sequence::reset('order', 'SO', '202606', 'tenant_1', 100);

Artisan Commands

List Sequences

Display a table of all active sequence counters in the database:

php artisan sequence:list
php artisan sequence:list --module=invoice

Reset Counters

Reset or set a specific sequence counter manually:

php artisan sequence:reset invoice INV --value=100

Verify and Repair

Scan actual model tables for sequence column values, identify any counter drift, and optionally align the database sequence counters to prevent key collisions:

php artisan sequence:verify "App\Models\Invoice" number --type=INV --module=invoice
# To automatically repair:
php artisan sequence:verify "App\Models\Invoice" number --type=INV --module=invoice --repair

Configuration (config/auto-sequence.php)

Publishing configuration gives you full architectural control:

return [
    'table' => 'sequences',
    'recycled_table' => 'sequence_recycled',
    'connection' => null,

    // Concurrency Locking Strategy
    'locking' => [
        'driver' => 'database',   // 'database' (Pessimistic lock), 'cache' (Atomic lock), or 'none'
        'cache_store' => null,    // cache connection name for atomic locks
        'timeout' => 5,           // seconds to block waiting for a lock (applies native DB lock timeout for MySQL, Postgres, SQL Server, SQLite)
        'retry_interval' => 100,  // milliseconds between retry attempts (applies if locking driver is cache)
    ],

    // Transaction Mode:
    // 'gapless': increments within model transaction (rolls back on failure; no gaps)
    // 'gap_tolerant': increments in isolated transaction (commits immediately; minimizes lock duration)
    // Note: 'gapless' is incompatible with pre-allocation.
    'transaction_mode' => 'gapless',

    // Hi/Lo Pre-Allocation Caching
    'pre_allocation' => [
        'enabled' => false,
        'block_size' => 50, // Grab 50 numbers at a time
        'store' => null,    // dedicated cache store name (e.g. 'redis') to prevent gaps from LRU eviction/flushes
    ],

    // Audit Tracking
    'audit' => [
        'enabled' => false, // Toggle created_by / updated_by tracking columns
        'user_model' => 'App\Models\User',
        'created_by_column' => 'created_by',
        'updated_by_column' => 'updated_by',
        'user_id_type' => 'bigInteger', // Options: 'bigInteger', 'uuid', 'ulid', 'string'
    ],
];

License

The MIT License (MIT). Please see the LICENSE file for more information.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 3
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-16

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固