17

I want to create a custom provider for Faker in Laravel (e.g. one for a random building name).

Where do I store the custom provider in my application and how do I use it?

carte
  • 983
  • 2
  • 9
  • 27

4 Answers4

29

You should use php artisan to generate the custom provider...

On the command line, navigate to the root of your app and type...

php artisan make:provider FakerServiceProvider

That should generate a new provider in the app/Providers folder. Here is what my register function looks like going off the example in the faker docs.

/**
 * Register the application services.
 *
 * @return void
 */
public function register()
{
    $this->app->singleton('Faker', function($app) {
        $faker = \Faker\Factory::create();
        $newClass = new class($faker) extends \Faker\Provider\Base {
            public function title($nbWords = 5)
            {
                $sentence = $this->generator->sentence($nbWords);
                return substr($sentence, 0, strlen($sentence) - 1);
            }
        };

        $faker->addProvider($newClass);
        return $faker;
    });
}

I'm using an anonymous class here. If you have php < 7, you would likely need to create a new file with your new provider class and pass that in. Make sure you also add this new provider to your providers array in config/app.php.

Now that it's registered, you can grab your new faker class using the following...

$faker = app('Faker');
echo $faker->title;

Additionally, if you go through the docs at https://laravel.com/docs/5.2/facades you should also be able to make a Faker facade quite easily. All the heavy lifting is done, you'd just have to create the new facade class, have getFacadeAccessor return 'Faker', and add it to your facades array in app/config.php.

Then you can simply use it like so...

echo Faker::title;
xperator
  • 2,393
  • 7
  • 29
  • 50
user1669496
  • 28,120
  • 6
  • 61
  • 61
  • I had `$factory->define(App\User::class, function (Faker\Generator $faker) {...` in factories, so I changed binding name to `Faker\Generator`. – x-yuri Sep 08 '16 at 14:43
  • @x-yuri Could you be more precise about what you have done? I have a similar requirement for my project – rap-2-h Nov 08 '17 at 08:58
  • @rap-2-h From what I can see, I probably meant, that the code in the answer binds to `Faker` class (`$this->app->singleton('Faker'...`). But since I had `Faker\Generator` in `database/factories`, I probably bound to `Faker\Generator` to make use of extra formatters (`title` in this case). – x-yuri Nov 08 '17 at 16:19
  • I kept the suggested binding to `Faker` and added a second binding to `Faker\Generator` below it, which redirects to `Faker`. I decided to keep both `singleton` declarations within the `FakerServiceProvider` class. Custom Faker providers are now working in factories, and the Faker singleton is still accessible via `app('Faker')`. Sorry for the minification, but here's the code: `$this->app->singleton('Faker\Generator', function($app) { return app('Faker'); });` – Illya Moskvin Nov 10 '17 at 21:20
  • Great implementation! How do you get your IDE to predict and recognize these added methods? I am using Laravel IDE for PhpStorm and they aren't being picked up. – famouspotatoes Apr 09 '20 at 17:18
  • I would recommend wrapping the `$this->app->singleton()` call in `$this->app->runningUnitTests()` so this doesn't register unless you're actually running tests. – SlyDave Jun 03 '20 at 13:24
9

Create your custom provider class and save it under app/Faker/CustomProvider.php. Code:

namespace App\Faker;

use Faker\Provider\Base;

class CustomProvider extends Base
{
    public function customName()
    {
        return $this->generator->sentence(rand(2, 6));
    }
}

Then you need just add your custom provider to faker by addProvider method. Example of laravel's factory with adding custom provider:

<?php
use Faker\Generator as Faker;

$factory->define(App\Models\Model::class, function(Faker $faker) {
    $faker->addProvider(new App\Faker\CustomProvider($faker));

    return [
         'name' => $faker->customName,
    ];
});
user580485
  • 141
  • 2
  • 2
7

I found this worked better, as it did not require my $faker instance to be instantiated with resolve():

public function register ()
    {
        $this->app->bind( Generator::class, function ( $app ) {

            $faker = \Faker\Factory::create();
            $faker->addProvider( new CustomFakerProvider( $faker ) );

            return $faker;
        } );

    }
Stuart Steedman
  • 146
  • 1
  • 6
2

The cleanest way to do this is to call a method in a ServiceProvider class that check if Faker is installed (it should not be in production), then extends the core definition.


use Faker\Generator;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
         // other stuff ...
         $this->registerFaker();
    }

    private function registerFaker()
    {
        if (class_exists(Generator::class)) {
            $this->app->extend(Generator::class, function (Generator $generator, $app) {
                $generator->addProvider(new MyCustomProvider($generator));
                
                return $generator;
            });
        }
    }
}
wesnick
  • 21
  • 1
  • 2