adamhopkinson/laravel-model-hash

A trait which automatically generates a unique hash per model instance

1.2.0 2020-08-08 23:27 UTC

This package is auto-updated.

Last update: 2024-04-19 04:02:19 UTC


README

Automatically create short hashes for your Laravel models, automatically use them in urls and back-fill existing models.

Build & Test Status

Why?

Database IDs in URLs such as stackoverflow.com/users/12280 never quite feel ok to me

  • having the index of an entity allows website size and growth to be estimated
  • accessing something that shouldn't be accessible is just a careless developer and a curious visitor away

But at the same time, I didn't want to completely replace the database ID with a UUID, as some packages do - as I was nervous about how this might affect performance.

laravel-model-hash allows you to generate a short, random hash when an item is created while still using auto-incrementing IDs for database relationships.

How it works

This package provides a trait which - when attached to a model - creates a random string hash when new instances of the model are created.

The hash is created by shuffling an alphabet, taking the first length characters, and checking for uniqueness in the database (up to a maximum number of times). If a unique hash wasn't found within the maximum attempts, an exception of type UniqueHashNotFoundException will be thrown and the model instance will not be saved.

The package is configured either globally using a config file, or by defining model-specific properties.

Installation

You can install the package via Composer:

composer require adamhopkinson/laravel-model-hash

If you would like to tweak any of the package configuration, you must first publish the config file:

php artisan vendor:publish --provider="AdamHopkinson\LaravelModelHash\LaravelModelHashServiceProvider"

Usage

To add a hash to model, add the LaravelModelHash trait:

use AdamHopkinson\LaravelModelHash\Traits\ModelHash;

class MyModel extends Model
{
    use ModelHash;
    //...
}

And create a migration to add a field to store the hash - by default, the field is called hash and has a length of 5:

$table->string('hash', 5)->unique()->index();

You may add a unique and index flag for database performance improvements. If you're adding this trait to an existing model, you will need to use nullable() until all records have a hash.

Now, when new instances of the model are created, they will be assigned a random string.

Adding hashes to existing models

If you are adding this package to an existing installation, there is an artisan command to 'backfill' existing models. The syntax is:

php artisan laravelmodelhash:populate

This uses reflection to find all models (in app_path()) which extend the ModelHash trait, and adds hash values to any records where the hash is currently null.

If you would like to only run this for a specific model, use the --model (or -M) option - but remember to double-slash the namespace:

php artisan laravelmodelhash:populate --model \\App\\MyModel

Configuration

There are three configurable parts to the hash:

  • the alphabet used (ie the set of allowed characters)
  • the name of the hash field
  • the length of the hash

And two other configuration properties

  • the maximum number of attempts to find a hash which isn't already present in the database before an exception is thrown
  • whether to automatically use the hash in route model binding

Each of these is set in the default configuration, which can be overridden in /config/laravelmodelhash.php (this must first be published - see the Installation section for details).

If you want to change these settings per model, they can be changed by adding the following model properties:

protected $hashName; // string
protected $hashLength; // int
protected $hashAlphabet; // string
protected $hashMaximumAttempts; // int
protected $useHashInRoutes; // boolean

Thanks

I've gotten this far thanks to the following: