Giter VIP home page Giter VIP logo

laravel-username-generator's Introduction

Laravel Username Generator

GitHub release (latest by date) Packagist Downloads GitHub GitHub branch checks state StyleCI Scrutinizer code quality (GitHub/Bitbucket)

Easily generate unique usernames for a Laravel User Model.

Works for Laravel versions above 5.5 including Laravel 9.

  1. Change Log
  2. Install
  3. Set Up
  4. Config
  5. Basic Usage
  6. Other Examples
  7. Drivers
  8. License

Change Log

See the Change Log

Install

Via Composer

$ composer require taylornetwork/laravel-username-generator

Publish Config

This will add the config to config/username_generator.php

$ php artisan vendor:publish --provider="TaylorNetwork\UsernameGenerator\ServiceProvider"

Quickstart

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();
            // ...
        });
    }
}

Laravel 8+

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-config

In 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 />

Laravel 7 and below

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';
}

Set Up

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

Config

This is in the process of being updated on the wiki

See the default config

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.

Allowed Characters

If you need to include additional characters beyond just 'A-Za-z' you'll need to update the allowed_characters config option.

You should also update 'convert_to_ascii' to false if you want the result to be in the same set.

For example

   'allowed_characters' => 'А-Яа-яA-Za-z',   // Would also allow Cyrillic characters
   
   'allowed_characters' => 'А-Яа-яA-Za-z-_' // Includes Cyrillic, Latin characters as well as '-' and '_'
   
   'allowed_characters' => '\p{Cyrillic}\p{Greek}\p{Latin}\s ' // Includes cyrillic, greek and latin sets and all spaces

Please note that all characters not included in this list are removed before performing any operations. If you get an empty string returned double check that the characters used are included.

Basic Usage

generate($name)

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'

generateFor($model)

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'

GeneratesUsernames Trait

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.

UsernameGenerator Facade

This package includes a UsernameGenerator facade for easy access

UsernameGenerator::generate('Test User');

UsernameGenerator::generateFor($user);

UsernameGenerator::setConfig([ 'separator' => '_' ])->generate('Test User');

Other Examples

With a Separator

$generator = new Generator([ 'separator' => '_' ]);
$generator->generate('Some User');

Returns

some_user

Upper Case

$generator = new Generator([ 'case' => 'upper' ]);
$generator->generate('Some User');

Returns

SOMEUSER

Additional Casing Options

To change the casing, we make use of the Laravel String Helpers so any value that changes the case will work.

Studly (Pascal)

UsernameGenerator::setConfig([ 'case' => 'studly' ])->generate('test user');
// Returns 'TestUser'

When using studly case the laravel helper will remove the spaces between separate words so if a separator is used it will be overridden. You would need to use title case (seen below) in order to have the same effect.

UsernameGenerator::setConfig([ 'case' => 'studly', 'separator' => '_' ])->generate('test user');
// Returns 'TestUser'

Title

This is the same as studly but the laravel helper will not remove spaces, so it can be used in conjunction with a separator

UsernameGenerator::setConfig([ 'case' => 'title' ])->generate('test user');
// Returns 'TestUser'

UsernameGenerator::setConfig([ 'case' => 'title', 'separator' => '_' ])->generate('test user');
// Returns 'Test_User'

Ucfirst

UsernameGenerator::setConfig([ 'case' => 'ucfirst' ])->generate('test user');
// Returns 'Testuser'

Mixed Case

$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.

Minimum Length

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

Maximum Length

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 maximum 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

Other Character Sets

Any other character set can be used if it's encoded with UTF-8. You can either include by adding the set to the 'allowed_characters' option.

Alternatively you can set 'validate_characters' to false to not check.

You will need to set 'convert_to_ascii' to false either way

$generator = new Generator([
    'allowed_characters' => '\p{Greek}\p{Latin}\s ',
    'convert_to_ascii' => false,
]);

$generator->generate('Αυτό είναι ένα τεστ');

// Returns

'αυτόείναιένατεστ'

Drivers

2 drivers are included, NameDriver (default) and EmailDriver

To use a specific driver

UsernameGenerator::usingEmail()->generate('[email protected]');

// Returns

'testuser'

OR

$generator = new Generator();
$generator->setDriver('email');
$generator->generate('[email protected]');

// Returns

'testuser'

Extending

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:

[
	'stripUnwantedCharacters',     // Removes all unwanted characters from the text
	'convertCase',                 // Converts the case of the field to the set value (upper, lower, mixed)
	'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 
{

	// --
	
}

Additionally if there is any operation you want to do as the very first or last thing you can use the first and last hooks.

public function first(string $text): string 
{
    // Happens first before doing anything else
}

public function last(string $text): string 
{
    // Happens last just before returning
}

Example

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,
        ...
    ],

License

See the License

laravel-username-generator's People

Contributors

itssamtaylor avatar john-climer avatar nikolaynikolaevn avatar pablomadariaga avatar stylecibot avatar timothyasp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

laravel-username-generator's Issues

Max length username

Hello
In the configuration I can see a variable to determine the minimum length for the username.
But is there any way to limit the maximum length?
Thank you,

Login with username

After the installation the package it is expected to be able to login with the username.

Assignment error

Hey Samuel

I get a duplicate key error when I try to add a unique index to my username column, and there are indeed duplicate values.

I reckon there is an assignment error in Generator.php right here: https://github.com/taylornetwork/laravel-username-generator/blob/master/src/Generator.php#L132

You assign the outcome of the comparison instead of the actual count, adding brackets would solve this:

if(($similar = count($this->model->findSimilarUsernames($this->username))) > 0) {

I'd write a PR but it's such a small fix, could you do this? Thank you for this package and thanks in advance.

Warm regards

Pieter

Not respecting nouns/adjectives in config

I tried adding a small list of words (nouns and adjectives) in the dictionary config but I am still getting usernames with words not in the list.
In /config/username_generator.php:

    /*
     * Add your own adjective and nouns word lists here if don't want to use the default
     */
    'dictionary' => [
        'adjectives' => ['sly','smart','sneaky'],
        'nouns'      => ['fox','rabbit','mouse'],
    ],

And generating a username with this method:

$username = UsernameGenerator::generate();

I also tried clearing config cache in laravel but still getting results like "invitingbuccane".

How to force the length of user name

I have tried the package as below:

 UsernameGenerator::generate($request->name . ' ' . $request->lastname)

.. and I passed the name 12s with something as the lastname but I got just s as the username.

I want to force the length of the user that it should generate about 5 chars. How should I do this?

Sugestion

This repo should be able to generate based on email address or any assigned emulator if available.

Possible SQL-Injection?

While reading your code i stumbled accross the following line (FindSimilarUsernames.php#L77):

return static::whereRaw("$column REGEXP '{$username}([0-9]*)?$'")->get();

Is the whereRaw necessary? Although you are stripping unwanted characters, this might lead to SQL-Injections, no? If a developer using your package does not know about this specific implementation and overwrites the allowed_characters Config-option and adds 'danagerous' characters, a user could inject SQL into the query by specifying a username.
I actually dont know much about REGEXP, but i am think that there has to be a way to use prepared statements here.

I found the following on laracasts:

$fulfills = Dialog::where('external_id', 'regexp', 'T[0-9]+')->get();

Which leads me to suggest something like this:

private function searchUsingRegexp(string $username)
{
    return static::where($this->getColumn(), 'REGEXP', $username."([0-9]*)?$")->get();
}

I'm actually not 100% sure if this fixes the SQL-Injection problem and still provide the same functunality.

Class '\App\User' not found

I can't update the configuration using this line:

public function generatorConfig(&$generator)
{
    $generator->setConfig(['model' => '\App\Models\User']);
}

Suggestion: Add a PascalCase setting for generated usernames.

I've looked around the documentation and tried a few things but couldn't seem to find a way to force generated usernames to use PascalCase.

For example, I was given the randomly generated username of Happybiographer, but I would love this to instead be HappyBiographer.

I appreciate that when it comes to converting usernames, you wouldn't really be able to convert to PascalCase successfully so perhaps it should just behave the same as 'mixed' when converting. But certainly when generating a random adjective-noun username it would be great to be able have this feature.

Is this possible?

Ability to create username using a word dictionary

Hello,

First of all, thank you for this package which looks very interesting, however, in my case I can't use it, I don't have any useful information about my users (name, email...), they are all anonymous, I was wondering if it was possible to reproduce what the alenoir/username-generator library made in nodeJS does and generate a username from a list of nouns (nouns.json) and adjectives (adjectives.json).

That would be very practical.

How do I use this package if my User model doesn't have name column ?

I get an error when I try to add the Trait to the User Model with

use FindSimilarUsernames, GeneratesUsernames;

Return value of App\Models\User::getField() must be of the type string, null returned {"exception":"[object] (TypeError(code: 0): Return value of App\\Models\\User::getField() must be of the type string, null returned at /Users/vikram/Sites/.../vendor/taylornetwork/laravel-username-generator/src/GeneratesUsernames.php:52)
[stacktrace]

Not working with cyrillic strings

Hi!

I noticed that the generator returns an empty string if the input data is in cyrillic.

Could you please fix it? Thanks in advance!

Bug impossible to get a username

First of all, thank you for the very fast addition of the feature, it's the first time I've seen such a reactivity!
Unfortunately I have a problem, I installed the package, published the configuration (php artisan vendor:publish), and tried to use the package with tinker (php artisan tinker) but it doesn't seem to work:
Capture d’écran 2019-10-31 à 20 17 15

Capture d’écran 2019-10-31 à 20 18 23

Can you help me ?

Unique possibly fails

Possible bug where "unique" values end up not being unique if too short and we do the random pad.

This will only happen if:

  • Too short action is to pad with random digits
  • There is an after unique hook that causes the make unique to not catch the duplicate entry since it won't check ahead

Solution:

  • Run make unique again after everything
    OR
  • Only run it again if the username was too short
    OR
  • Restrict after make unique hook (don't really want to do that)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.