parables/laravel-model-nanoid
composer require parables/laravel-model-nanoid in your Laravel project.php artisan vendor:publish --provider="Parables\LaravelModelNanoid\LaravelModelNanoidServiceProvider" to publish the config file.HasNanoId trait to your Eloquent model:
use Parables\LaravelModelNanoid\HasNanoId;
class User extends Model
{
use HasNanoId;
}
nano_id column to your table (e.g., string with length 21 or more):
Schema::table('users', function (Blueprint $table) {
$table->string('nano_id')->unique()->after('id');
});
$user = User::create(['name' => 'John Doe']);
// $user->nano_id will be a 21-character string like "V1StGXW8_G5d0J9KqP2x"
config/nanoid.php for customizing alphabet, size, or randomness.HasNanoId provides getNanoId(), setNanoId(), and generateNanoId() for manual control.php artisan nanoid:test to verify NanoID generation.Automatic Generation:
create() if the field is empty. No manual intervention needed.$post = Post::create(['title' => 'Hello World']); // nano_id auto-populated
Manual Overrides:
$nanoId = $model->generateNanoId();
$model->setNanoId($nanoId);
$model->save();
Querying by NanoID:
where('nano_id', $value) for lookups. Ensure the column is indexed for performance:
$user = User::where('nano_id', 'V1StGXW8_G5d0J9KqP2x')->first();
Custom Alphabets:
config/nanoid.php:
'alphabet' => '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ_abcdefghjkmnpqrstuvwxyz',
Integration with APIs:
/users/{nano_id}). Example:
Route::get('/users/{nano_id}', [UserController::class, 'show']);
Seeding:
User::factory()->create(['nano_id' => \Str::random(21)]); // Not recommended; use trait instead
User::factory()->create(); // Auto-generates nano_id
Composite Keys:
id (auto-increment) and nano_id for hybrid lookups:
$model = Model::where('id', $id)->orWhere('nano_id', $nano_id)->first();
Soft Deletes:
SoftDeletes. Ensure the deleted_at column is indexed separately.Caching:
Cache::remember()) to avoid repeated DB lookups.Events:
creating events to customize NanoID generation:
User::creating(function ($user) {
if (empty($user->nano_id)) {
$user->nano_id = $user->generateNanoId(16); // Shorter ID for testing
}
});
Testing:
$model = new User();
$model->shouldReceive('generateNanoId')->andReturn('TEST123');
Database Indexing:
nano_id column will cause slow queries.$table->string('nano_id')->unique();
$table->index('nano_id'); // Explicit index (optional but recommended)
Collision Risk:
Auto-Increment Conflicts:
$table->id()->unsigned(false)), the package won’t work as expected.id). NanoIDs are for secondary use cases.Case Sensitivity:
utf8mb4_bin collation) treat case-insensitively.Migration Order:
nano_id to an existing table without a default value may cause issues if the column is required.nullable() during migration and backfill later:
$table->string('nano_id')->nullable()->unique();
// Later: update existing records with NanoIDs
Performance:
id for internal joins.Validation Errors:
size in config/nanoid.php matches your column length.Duplicate NanoIDs:
php artisan nanoid:test to verify generation uniqueness.Slow Queries:
EXPLAIN in MySQL or pg_explain in PostgreSQL to check if the nano_id index is being used.where('nano_id', ...) and not like or partial matches.Config Overrides:
php artisan config:clear
Custom Randomness:
config/nanoid.php:
'random_bytes_generator' => function () {
return random_bytes(10); // Custom logic
},
Dynamic NanoID Length:
$model->generateNanoId(16); // 16-character ID
Event Hooks:
use Parables\LaravelModelNanoid\HasNanoId;
class User extends Model
{
use HasNanoId;
protected static function bootHasNanoId()
{
static::creating(function ($model) {
logger()->info("Generating NanoID for {$model->class}");
});
}
}
Database-Specific Optimizations:
citext for case-insensitive NanoIDs:
$table->string('nano_id')->unique();
$table->engine = 'citext'; // PostgreSQL-specific
Fallback for Missing IDs:
nano_id is missing in existing records:
if (empty($model->nano_id)) {
$model->nano_id = $model->generateNanoId();
}
How can I help you explore Laravel packages today?