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

Variable Keys Laravel Package

cline/variable-keys

Laravel Blueprint macros for variable primary key types, matching foreign keys, and polymorphic morph types. Easily switch between id/uuid/ulid (and more) via enums/config to keep migrations consistent across models and relationships.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require cline/variable-keys
    
  2. Configure your primary key type in config/database.php:
    'primary_key_type' => env('DB_PRIMARY_KEY_TYPE', 'uuid'),
    
  3. Use the macro in a migration:
    use Cline\VariableKeys\Enums\PrimaryKeyType;
    
    Schema::create('users', function (Blueprint $table) {
        $table->variablePrimaryKey(PrimaryKeyType::UUID);
        $table->string('name');
        $table->timestamps();
    });
    

First Use Case: Switching from id() to UUIDs

Replace all ->id() calls with ->variablePrimaryKey(PrimaryKeyType::UUID) in new migrations. For existing tables, add a new UUID column and backfill it.


Implementation Patterns

Core Workflow: Migration Refactoring

  1. Define the key type in config/database.php or .env:
    DB_PRIMARY_KEY_TYPE=uuid
    
  2. Replace id() with variablePrimaryKey():
    // Before
    $table->id();
    
    // After
    $table->variablePrimaryKey(PrimaryKeyType::UUID);
    
  3. Align foreign keys using variableForeignKey():
    $table->variableForeignKey('user_id', PrimaryKeyType::UUID)
          ->constrained()
          ->cascadeOnDelete();
    
  4. Update polymorphic models in AppServiceProvider:
    Model::morphMap([
        'user' => User::class,
        // Other models with variable keys
    ]);
    

Integration with Eloquent

  • Model Key Resolution: The package works seamlessly with Eloquent’s getKey(), getKeyType(), and incrementPrimaryKey() methods. No additional model overrides are needed for basic usage.
  • Custom Key Handling: For advanced use cases (e.g., custom key generation), extend the PrimaryKeyType enum or override getIncrementing() in your models:
    class User extends Model
    {
        public function getIncrementing(): bool
        {
            return false; // For UUIDs/ULIDs
        }
    }
    

Polymorphic Relationships

  1. Define morph types in AppServiceProvider:
    MorphType::configure([
        'user' => MorphType::UUID,
        'post' => MorphType::UUID,
    ]);
    
  2. Use in migrations:
    Schema::create('comments', function (Blueprint $table) {
        $table->variablePrimaryKey(PrimaryKeyType::UUID);
        $table->morphs('commentable', MorphType::UUID);
        $table->timestamps();
    });
    

Configuration-Driven Development

  • Centralize key types in config/database.php:
    'key_types' => [
        'primary' => 'uuid',
        'foreign' => 'uuid',
        'morph'   => 'uuid',
    ],
    
  • Override per-table in migrations:
    $table->variablePrimaryKey(PrimaryKeyType::ULID);
    

Gotchas and Tips

Pitfalls

  1. Migration Rollbacks:
    • Rollbacks may fail if foreign key constraints are not properly aligned. Always test rollback scenarios:
      Schema::table('posts', function (Blueprint $table) {
          $table->dropForeign(['user_id']);
      });
      
  2. Polymorphic Key Mismatches:
    • Ensure morphMap and MorphType configurations match across all polymorphic tables. Mismatches can cause ModelNotFoundException errors.
  3. Database-Specific Quirks:
    • MySQL: UUIDs require CHAR(36) columns, not BINARY(16). Configure PrimaryKeyType::UUID to use string in MySQL environments.
    • SQLite: Limited support for non-integer primary keys. Use INTEGER as a fallback if UUIDs are required.
  4. Key Generation Conflicts:
    • UUIDv4 collisions are rare but possible. For critical systems, consider UUIDv7 (time-based) or ULIDs:
      $table->variablePrimaryKey(PrimaryKeyType::ULID);
      

Debugging Tips

  1. Verify Key Types:
    • Check the generated SQL in migrations to confirm key types:
      $table->variablePrimaryKey(PrimaryKeyType::UUID); // Generates `uuid` column in PostgreSQL
      
  2. Eloquent Key Resolution:
    • Debug key resolution issues with:
      dd($model->getKeyType(), $model->getKey());
      
  3. Foreign Key Constraints:
    • Use Schema::hasTable() and Schema::hasColumn() to verify table/column existence before adding constraints:
      if (Schema::hasTable('users') && Schema::hasColumn('users', 'id')) {
          $table->variableForeignKey('user_id', PrimaryKeyType::UUID)->constrained();
      }
      

Extension Points

  1. Custom Key Types:
    • Extend the PrimaryKeyType enum to support custom key types (e.g., CUSTOM_STRING):
      namespace App\Enums;
      
      use Cline\VariableKeys\Enums\PrimaryKeyType;
      
      class AppPrimaryKeyType extends PrimaryKeyType
      {
          case CUSTOM_STRING = 'custom_string';
      }
      
  2. Blueprint Macros:
    • Override or extend macros in AppServiceProvider:
      use Cline\VariableKeys\BlueprintExtensions;
      
      BlueprintExtensions::macro('customPrimaryKey', function (Blueprint $table) {
          $table->variablePrimaryKey(PrimaryKeyType::ULID);
      });
      
  3. Morph Type Customization:
    • Extend MorphType for custom polymorphic key handling:
      MorphType::extend('custom_morph', function () {
          return 'custom_morph_key';
      });
      

Performance Considerations

  1. UUIDs vs. Integers:
    • UUIDs (16 bytes) consume more storage and may impact indexing performance compared to integers (4 bytes). Benchmark in your specific database.
  2. Indexing:
    • Ensure foreign key columns are indexed:
      $table->variableForeignKey('user_id', PrimaryKeyType::UUID)
            ->constrained()
            ->index();
      
  3. Batch Inserts:
    • For bulk operations, generate keys client-side (e.g., UUIDs) to avoid round-trips to the database:
      $keys = Str::uuid()->toString();
      DB::table('users')->insert([['id' => $keys, 'name' => 'Test']]);
      
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.
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver