Laravel Model HashId

repository·main·Indexed 41 days ago

https://github.com/deligoez/laravel-model-hashid

Generates, saves, and routes Stripe-like non-sequential unique identifiers for Laravel Eloquent models to hide database row numbers. Features include route model binding, database persistence via the SavesHashId trait, API serialization, and validation rules like ValidHashId and HashIdExists. Supports PHP ^8.0+ and Laravel ^8.0+.

Tokens
7.3K
Snippets
37
Records
40
Agent score
50%

What's inside Laravel Model HashId

  1. Install Laravel Model HashId

    main

    To use Laravel Model HashId in your project, install it via Composer and publish the configuration file.

    Requirements:

    • PHP ^8.0+
    • Laravel ^8.0+

    Installation Steps:

    1. Install the package:
      composer require deligoez/laravel-model-hashid
    2. Publish the configuration:
      php artisan vendor:publish --provider="Deligoez\LaravelModelHashId\LaravelModelHashIdServiceProvider" --tag="config"
    composer require deligoez/laravel-model-hashid
    php artisan vendor:publish --provider="Deligoez\LaravelModelHashId\LaravelModelHashIdServiceProvider" --tag="config"
  2. Breaking Changes in v4

    main

    Version 4 introduces several breaking changes that may affect custom implementations or extensions of the package:

    1. ConfigParameters is now final: You can no longer extend this class. Instead, use its constants directly.
    2. HashIdDTO is now readonly: Properties of HashIdDTO are immutable. Attempting to modify them after construction will result in an error.
    3. Config::checkIfModelClassExists() renamed: The method checkIfModelClassExist() has been renamed to checkIfModelClassExists() (added an 's').
    4. HasHashIdRouting::getRouteKey() return type changed: The return type has changed from string to mixed to allow returning null for unsaved models.
  3. Configure Laravel Model HashId

    main

    To customize the global Hash Id generation settings, publish the configuration file using the Artisan command. Once published, you can modify the settings in config/laravel-model-hashid.php.

    Important Security Note: You must change the salt value before deploying to a production environment to ensure the security of your generated Hash Ids.

    php artisan vendor:publish --provider="Deligoez\LaravelModelHashId\LaravelModelHashIdServiceProvider" --tag="config"
  4. Enable Route Model Binding with Hash Ids

    main

    To allow Laravel to automatically resolve models in routes using their Hash Id, add the HasHashIdRouting trait to your model.

    Implicit Binding

    Standard route parameters will automatically resolve the model using the Hash Id:

    // GET /users/user_kqYZeLgo
    Route::get('/users/{user}', function (User $user) {
        return $user;
    });

    Explicit Binding

    Register a custom model key in your RouteServiceProvider:

    Route::model('hash_id', User::class);
    
    // GET /users/user_kqYZeLgo
    Route::get('/users/{hash_id}', function (User $user) {
        return $user;
    });
    use Deligoez\LaravelModelHashId\Traits\HasHashIdRouting;
    
    class User extends Model
    {
        use HasHashIdRouting;
    }
  5. Save Hash Ids to the Database

    main

    By default, Hash Ids are generated on the fly and do not need to be stored. If you want to persist them in a database column, add the SavesHashId trait to your model.

    1. Add the trait to your model.
    2. Ensure the database_column in your config matches your migration (default is hash_id).

    Note: Saving to the database requires an additional query after model creation because Hash Id generation requires the integer model key.

    use Deligoez\LaravelModelHashId\Traits\SavesHashId;
    
    class User extends Model
    {
        use SavesHashId;
    }
  6. Configure model-specific Hash Id settings

    main

    You can override global configuration settings for specific models by using the model_generators array in the configuration file. This allows you to define unique salts, lengths, or custom prefixes for individual Eloquent models.

    Note that if you provide a prefix key, it will use that custom string instead of generating one from the class name.

    'model_generators' => [
        App\Models\User::class => [
            'salt'            => 'user-specific-salt',
            'length'          => 8,
            'prefix_length'   => -1, // full class name as prefix
            'separator'       => '-',
        ],
    
        App\Models\Post::class => [
            'prefix' => 'article', // custom prefix (not generated from class name)
        ],
    ],
  7. Create Hash Id Columns in Migrations

    main

    A hashId() macro is available on the Blueprint class to simplify adding Hash Id columns to your migrations.

    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->hashId();              // Creates a nullable, unique string column (default: 'hash_id')
        $table->hashId('custom_hash'); // Creates a column with a custom name
        $table->timestamps();
    });
    $table->hashId();
    $table->hashId('custom_hash');
  8. Validate Hash Ids

    main

    The package provides two validation rules for use in form requests or manual validators:

    ValidHashId (Format Validation)

    Checks if a value is a valid Hash Id format. It does not hit the database. You can optionally validate against a specific model to ensure the prefix and decoding are correct.

    // Generic: any decodable Hash Id
    'token' => [new ValidHashId]
    
    // Model-specific: must decode for User model
    'user_id' => [new ValidHashId(User::class)]

    HashIdExists (Database Existence Check)

    Checks if a Hash Id corresponds to an existing record in the database. This is equivalent to Laravel's exists rule.

    'user_id' => [new HashIdExists(User::class)]
    use Deligoez\LaravelModelHashId\Rules\ValidHashId;
    use Deligoez\LaravelModelHashId\Rules\HashIdExists;
    
    // Format check
    'user_id' => [new ValidHashId(User::class)]
    
    // Existence check
    'user_id' => [new HashIdExists(User::class)]
  9. Note on `HasHashIdRouting::getRouteKey()` return type

    main

    In v4, HasHashIdRouting::getRouteKey() now returns mixed instead of string. This change allows the method to return null when a model has not yet been saved (and thus has no hash ID), preventing TypeError exceptions.

    // Before (v3): returned string
    public function getRouteKey(): string
    
    // After (v4): returns mixed
    public function getRouteKey(): mixed
  10. Use Generic Hash Ids without a Model

    main

    You can use the HashId utility class to encode and decode integers independently of Eloquent models.

    use Deligoez\LaravelModelHashId\Support\HashId;
    
    // Encode with default config
    HashId::encode(1234);                                    // 'kqYZeLgo...'
    
    // Encode with specific parameters
    HashId::encode(1234, prefix: 'tok', separator: '_');     // 'tok_kqYZeLgo...'
    HashId::encode(1234, salt: 'custom', length: 8);
    
    // Decode
    HashId::decode('tok_kqYZeLgo...', prefix: 'tok');        // 1234
    
    // Build a standalone generator
    $generator = HashId::buildGenerator(salt: 'my-salt', length: 10);
    use Deligoez\LaravelModelHashId\Support\HashId;
    
    HashId::encode(1234, prefix: 'tok', separator: '_');
    HashId::decode('tok_kqYZeLgo...', prefix: 'tok');