Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Eloquent Keygen Laravel Package

jetcod/eloquent-keygen

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require jetcod/eloquent-keygen
    php artisan vendor:publish --provider="eloquent-key-generator-config"
    
    • Verify the config/eloquent-key-generator.php file exists and adjust settings (e.g., worker_id, datacenter_id) if needed.
  2. First Use Case:

    • Extend Base Model (for all models): Replace Illuminate\Database\Eloquent\Model with Jetcod\Eloquent\Model in app/Models/Model.php (or your base model).
      use Jetcod\Eloquent\Model as BaseModel;
      class Model extends BaseModel { ... }
      
    • Use Trait (for specific models): Add use Jetcod\Eloquent\Traits\Snowflake; to a single model.
      use Jetcod\Eloquent\Traits\Snowflake;
      class User extends Model { use Snowflake; ... }
      
  3. Migrate Existing Tables:

    • Update your migration to drop the auto-increment constraint and set the primary key as unsignedBigInteger:
      $table->bigInteger('id')->unsigned()->primary();
      
    • Run migrations:
      php artisan migrate
      
  4. Test:

    • Create a new record:
      $user = User::create(['name' => 'Test']);
      echo $user->id; // Outputs a Snowflake ID (e.g., 123456789012345678)
      

Implementation Patterns

Usage Patterns

  1. Global vs. Per-Model Configuration:

    • Global: Configure Snowflake settings (e.g., worker_id, datacenter_id) in config/eloquent-key-generator.php. Example:
      'worker_id' => env('SNOWFLAKE_WORKER_ID', 1),
      'datacenter_id' => env('SNOWFLAKE_DATACENTER_ID', 1),
      'epoch' => 1609459200, // Custom epoch if needed
      
    • Per-Model Override: Use the trait with custom settings:
      use Jetcod\Eloquent\Traits\Snowflake as SnowflakeTrait;
      class User extends Model {
          use SnowflakeTrait {
              SnowflakeTrait::boot as private bootSnowflake;
          }
          protected static function bootSnowflake() {
              parent::bootSnowflake();
              config(['eloquent-key-generator.worker_id' => 2]); // Override for this model
          }
      }
      
  2. Integration with Existing Workflows:

    • Seeding: Snowflake IDs work seamlessly with Laravel’s seeder:
      User::factory()->create(); // Auto-generates Snowflake ID
      
    • API Responses: Ensure API responses include the Snowflake ID (no changes needed; Eloquent handles it).
    • Relationships: Foreign keys must also use Snowflake IDs. Example:
      $user = User::create(['name' => 'Alice']);
      $post = Post::create(['user_id' => $user->id, 'title' => 'Hello']); // user_id is Snowflake
      
  3. Batch Operations:

    • Use insert() or create() in bulk:
      User::insert([
          ['name' => 'Alice'],
          ['name' => 'Bob'],
      ]);
      // Both IDs are Snowflake-generated.
      
  4. Custom ID Fields:

    • Override the default id field by setting $primaryKey and $keyType:
      class Order extends Model {
          use Snowflake;
          protected $primaryKey = 'order_id';
          public $keyType = 'string'; // If using string-based Snowflake
      }
      

Workflows

  1. Multi-Tenant Applications:

    • Use datacenter_id to isolate ID ranges per tenant:
      config(['eloquent-key-generator.datacenter_id' => $tenantId]);
      
    • Reset datacenter_id after operations to avoid conflicts.
  2. Testing:

    • Mock Snowflake IDs in tests using the Snowflake trait’s generateId() method:
      $this->app->bind('snowflake', function () {
          return \Mockery::mock('overload:\Jetcod\Eloquent\Snowflake');
      });
      
    • Or use a custom epoch for predictable IDs in tests:
      config(['eloquent-key-generator.epoch' => 0]);
      
  3. Performance:

    • Snowflake IDs are generated in-memory, so they add minimal overhead (~1ms per ID).
    • For high-throughput systems, pre-generate IDs in batches if needed (though the package handles this automatically).

Gotchas and Tips

Pitfalls

  1. Migration Issues:

    • Error: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry. Cause: Reusing auto-increment IDs after switching to Snowflake. Fix: Reset the id column to start from 1 (or a high value) in your migration:
      $table->bigInteger('id')->unsigned()->primary()->default(1);
      
      Then truncate and repopulate data.
  2. Foreign Key Conflicts:

    • Error: Foreign key constraint is incorrectly formed. Cause: Foreign keys referencing Snowflake IDs must also be unsignedBigInteger. Fix: Update foreign key columns in migrations:
      $table->unsignedBigInteger('user_id')->constrained();
      
  3. Time-Based Collisions:

    • Cause: Snowflake IDs rely on timestamps. If your epoch is too far in the past/future, IDs may collide or appear invalid. Fix: Use a recent epoch (e.g., 1609459200 for 2021-01-01) and ensure all servers use the same time.
  4. Trait vs. Base Model:

    • Issue: Forgetting to extend Jetcod\Eloquent\Model or include the trait. Fix: Verify your model extends the correct base class or uses the trait.
  5. Environment-Specific IDs:

    • Issue: IDs generated in staging/production differ due to worker_id/datacenter_id mismatches. Fix: Use environment variables for these settings:
      'worker_id' => env('SNOWFLAKE_WORKER_ID', 1),
      'datacenter_id' => env('SNOWFLAKE_DATACENTER_ID', env('APP_ENV') === 'production' ? 1 : 2),
      

Debugging

  1. Log Snowflake Generation: Add this to your model’s bootSnowflake() to debug:

    static::created(function ($model) {
        \Log::debug('Generated Snowflake ID:', ['id' => $model->id, 'model' => static::class]);
    });
    
  2. Validate ID Format: Snowflake IDs should be 19 digits (for 64-bit IDs). Use this helper:

    function isValidSnowflake($id) {
        return preg_match('/^\d{19}$/', $id) === 1;
    }
    
  3. Check for ID Reuse: If IDs appear to reset, verify:

    • No auto-increment is set in the database.
    • The epoch and worker_id/datacenter_id are consistent across servers.

Tips

  1. Custom ID Length: Override the generateId() method in the trait to customize length:

    use Jetcod\Eloquent\Traits\Snowflake as SnowflakeTrait;
    class User extends Model {
        use SnowflakeTrait {
            SnowflakeTrait::generateId as private generateSnowflakeId;
        }
        protected static function generateId() {
            return str_pad(parent::generateSnowflakeId(), 20, '0', STR_PAD_LEFT);
        }
    }
    
  2. String-Based Snowflake: Convert IDs to strings for readability (e.g., UUID-like format):

    protected $keyType = 'string';
    protected static function bootSnowflake() {
        static::creating(function ($model) {
            $model->{$model->primaryKey} = (string) $model->{$model->primaryKey};
        });
    }
    
  3. Fallback to UUID: Combine Snowflake with UUID for extra safety (e.g., in distributed systems):

    use Ramsey\Uuid\Uuid;
    protected static function bootSnowflake() {
        static::creating(function ($model) {
            $model->{$model->primaryKey} = Uuid::uuid4()->toString();
        });
    }
    
  4. Database Indexing: Snowflake IDs are sequential

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope