Easily generate unique usernames for a Laravel User Model
v2.5
- Added maximum length check.
- Added ability for pre-filled usernames to go through generate process to allow for consistent username styles.
- Added checking for similar usernames using REGEXP or LIKE (LIKE is a fallback if REGEXP fails).
- Added a check if a username is unique as is before checking for similar ones.
- Updated
composer.jsonto support PHP 7.2 and above - Updated readme for better Laravel 8+ quickstart
v2.4
- This is a minor change but if you're using older versions of Laravel you may need to update your config file.
- Changed default User model from
App\UsertoApp\Models\Userto mirror new Laravel versions (8.0+). - Moved the adjective and noun word lists from the config file to a separate file, making the published config smaller and allowing you to create your own word lists if you wish.
v2.3
- Added support for random dictionary based usernames if a name is not provided. See the generate method
v2.2.2
- Fixed bug where if a custom column name was used and set using
generatorConfigit was not being passed through. - Fixed support for overriding the
getNamemethod fromGeneratesUsernames
v2.2
- Added support for minimum length
v2.1
- Switched to a driver based conversion
- Added email support
Note: Nothing should break with this update but let me know if you have any issues.
v2.0
- Removed support for deprecated
makeUsernamemethod Generatorwill now only accept an array of config as the optional constructing arguments- Added
UsernameGeneratorfacade
Via Composer
$ composer require taylornetwork/laravel-username-generatorThis will add the config to config/username_generator.php
$ php artisan vendor:publish --provider="TaylorNetwork\UsernameGenerator\ServiceProvider"This section will help you get up and running fast.
The following steps will be the same for all Laravel versions and assumes you're adding the package to a new installation.
User Model
In App\Models\User (or App\User for Laravel 7) add the FindSimilarUsernames and GeneratesUsernames traits.
Add 'username' to the fillable property.
// ...
use TaylorNetwork\UsernameGenerator\FindSimilarUsernames;
use TaylorNetwork\UsernameGenerator\GeneratesUsernames;
class User extends Authenticatable
{
// ...
use FindSimilarUsernames;
use GeneratesUsernames;
protected $fillable = [
// ...
'username',
];
// ...
}Database Migration
In your database/2014_10_12_000000_create_users_table add a username column.
class CreateUsersTable extends Migration
{
public function up()
{
Schema::create('users', function (Blueprint $table) {
// ...
$table->string('username')->unique();
// ...
});
}
}Note: if you are not using Laravel Jetstream for your project, simply continue with the Laravel 7 guide below.
Publish the Laravel Fortify config if you haven't already
$ php artisan vendor:publish --tag=fortify-configIn the config/fortify.php change the 'username' => 'email' to 'username' => 'username'
// ...
'username' => 'username',
'email' => 'email',
// ... Update the login view in resources/views/auth/login.blade.php and replace Email with Username.
<x-jet-label for="email" value="{{ __('Username') }}" />
<x-jet-input id="email" class="block mt-1 w-full" type="text" name="username" :value="old('username')" required autofocus />In config/username_generator.php update the User model namespace to match your project.
Using username to login
To use the username to login instead of the email you need to add the following to your LoginController
public function username()
{
return 'username';
}Add the FindSimilarUsernames trait on your user model (or whichever model you want to use).
use TaylorNetwork\UsernameGenerator\FindSimilarUsernames;
class User extends Authenticatable
{
use FindSimilarUsernames;
} Note: this is required in all cases if you want the username to be unique
This is in the process of being updated on the wiki
By default the Generator class has the following configuration:
| Config | Value | Type |
|---|---|---|
| Unique Username | true |
boolean |
| Separator | '' |
string (should be single character) |
| Case | 'lower' |
string (one of lower, upper, or mixed) |
| Username DB Column | 'username' |
string |
| Class | '\App\Models\User' |
string |
The config is stored in config/username_generator.php
You can override config on a new instance by new Generator([ 'unique' => false ]); etc.
Create a new instance and call generate($name)
use TaylorNetwork\UsernameGenerator\Generator;
$generator = new Generator();
$username = $generator->generate('Test User');Returns
'testuser'If you do not provide a name to the generate method an adjective and noun will be chosen as the name at random, using noun and adjective word lists from alenoir/username-generator, which will then be converted to a username.
use TaylorNetwork\UsernameGenerator\Facades\UsernameGenerator;
$username = UsernameGenerator::generate();Returns something similar to
'monogamousswish'Create a new instance and call generateFor($model)
This will access the model's name property and convert it to a username.
use TaylorNetwork\UsernameGenerator\Generator;
class User
{
public $name = 'Some Other User';
public function getUsername()
{
$generator = new Generator();
return $generator->generateFor($this);
}
}Returns
'someotheruser'This package also comes with a GeneratesUsernames trait that you can add to your model and it will automatically call the username generator when the model is saving without the specified username column.
Note: you will also need to include the FindSimilarUsernames trait either way
use TaylorNetwork\UsernameGenerator\GeneratesUsernames;
use TaylorNetwork\UsernameGenerator\FindSimilarUsernames;
class User
{
use FindSimilarUsernames, GeneratesUsernames;
}You can also add custom config to call before the username is generated.
Override the generatorConfig method in your model
use TaylorNetwork\UsernameGenerator\GeneratesUsernames;
use TaylorNetwork\UsernameGenerator\FindSimilarUsernames;
class User
{
use FindSimilarUsernames, GeneratesUsernames;
public function generatorConfig(&$generator)
{
$generator->setConfig([ 'separator' => '_' ]);
}
}If you need to modify the data before handing it off to the generator, override the getField method on your model.
For example if you have a first and last name rather than a single name field, you'll need to add this to your model.
class User
{
// ...
public function getField(): string
{
return $this->first_name . ' ' . $this->last_name;
}
// ...
}Note: if your code still uses a custom getName, it will still work, however it was replaced with getField in v2.1 when driver support was added.
This package includes a UsernameGenerator facade for easy access
UsernameGenerator::generate('Test User');
UsernameGenerator::generateFor($user);
UsernameGenerator::setConfig([ 'separator' => '_' ])->generate('Test User');$generator = new Generator([ 'separator' => '_' ]);
$generator->generate('Some User');Returns
some_user
$generator = new Generator([ 'case' => 'upper' ]);
$generator->generate('Some User');Returns
SOMEUSER
$generator = new Generator([ 'case' => 'mixed' ]);
$generator->generate('Some User');Returns
SomeUser
Note: Mixed case will just ignore changing case altogether
$generator = new Generator([ 'case' => 'mixed' ]);
$generator->generate('SoMe WeIrD CapitaliZation');Returns
SoMeWeIrDCapitaliZation
Note: if you pass an invalid value for the case option, mixed case will be used.
If you want to enforce a minimum length for usernames generated change the min_length option in config/username_generator.php
'min_length' => 6,By default if the generator generates a username less than the minimum length it will pad the end of it with a random digit between 0 and 9.
For example
UsernameGenerator::generate('test');
// Would return the following where 0 is a random digit
'test00' Alternatively you can throw an exception when the minimum length has not been reached
In config/username_generator.php set
'throw_exception_on_too_short' => true,UsernameGenerator::generate('test');Would throw a UsernameTooShortException
If you want to enforce a maximum length for usernames generated change the max_length option in config/username_generator.php
'max_length' => 6,By default if the generator generates a username more than the minimum length it will cut it to the max length value and then try to make it unique again. If that becomes too long it will remove one character at a time until a unique username with the correct length has been generated.
For example
UsernameGenerator::generate('test user');
'testus' Alternatively you can throw an exception when the maximum length has been exceeded
In config/username_generator.php set
'throw_exception_on_too_long' => true,UsernameGenerator::generate('test user');Would throw a UsernameTooLongException
2 drivers are included, NameDriver (default) and EmailDriver
To use a specific driver, if none is specified the default is used.
UsernameGenerator::usingEmail()->generate('[email protected]');
// Returns
'testuser'OR
$generator = new Generator();
$generator->setDriver('email');
$generator->generate('[email protected]');
// Returns
'testuser'You can make your own custom drivers that extend TaylorNetwork\UsernameGenerator\Drivers\BaseDriver or override an existing one.
Custom drivers require a public $field property to be set which is the name of the field on the model to use to generate the username.
Drivers will perform the following operations in order:
[
'convertCase', // Converts the case of the field to the set value (upper, lower, mixed)
'stripUnwantedCharacters', // Removes all unwanted characters from the text
'collapseWhitespace', // Collapses any whitespace to a single space
'addSeparator', // Converts all spaces to separator
'makeUnique', // Makes the username unique (if set)
]In your custom driver you can add a method to perform an operation before or after any of the above operations.
public function beforeConvertCase(string $text): string
{
// --
}
public function afterStripUnwantedCharacters(string $text): string
{
// --
}For example if you wanted to append -auto to all automatically generated usernames, you could make a new driver in App\Drivers\AppendDriver
namespace App\Drivers;
use TaylorNetwork\UsernameGenerator\Drivers\BaseDriver;
class AppendDriver extends BaseDriver
{
public $field = 'name';
public function afterMakeUnique(string $text): string
{
return $text . '-auto';
}
}And then in config/username_generator.php add the driver to the top of the drivers array to use it as default.
'drivers' => [
'append' => \App\Drivers\AppendDriver::class,
...
],MIT