mbezhanov/faker-provider-collection
A collection of custom Faker providers for Laravel and standalone PHP that generate locale-specific fake data like addresses, phone numbers, and company details, making test fixtures and database seeders more realistic.
1. Install and check compatibility first. This package was written against fzaninotto/faker, which was abandoned in favour of fakerphp/faker (the one Laravel 8+ ships). Before anything else:
composer require mbezhanov/faker-provider-collection
composer show mbezhanov/faker-provider-collection # inspect the faker constraint
If Composer refuses to install because your app already has fakerphp/faker, you have three options: fork the package and widen the constraint to fakerphp/faker: ^1.9, add a replace entry in your root composer.json, or pin an older Laravel for the project. The provider code itself is API-compatible — only the constraint is stale.
2. Look at the source, not just the README. There is no service provider, no config file, and no auto-discovery. Everything lives in plain classes under vendor/mbezhanov/faker-provider-collection/src/Provider/. Open one and read the public methods — that is the API. Providers cover domain data such as Sports, Cinema, Books, Music, Gaming, Medical, Food and Colors (the README table is the canonical list; treat method names as "whatever the class exposes").
3. Register it once, in AppServiceProvider. Laravel binds Faker\Generator as a singleton in Illuminate\Database\DatabaseServiceProvider, so extend that binding rather than creating your own generator:
// app/Providers/AppServiceProvider.php
use Faker\Generator as FakerGenerator;
use Mbezhanov\Faker\Provider\Sports;
use Mbezhanov\Faker\Provider\Cinema;
public function register(): void
{
$this->app->extend(FakerGenerator::class, function (FakerGenerator $faker) {
$faker->addProvider(new Sports($faker));
$faker->addProvider(new Cinema($faker));
return $faker;
});
}
Now fake()->sport, fake()->movieTitle, $this->faker->... inside factories, and $this->faker in seeders all resolve through the same decorated instance.
4. First use case. You're building a demo/staging dataset for a media or content catalog. Add the Cinema/Books/Gaming provider in the snippet above, then reference a formatter directly in a factory ('title' => fake()->movieTitle). Verify with php artisan tinker → fake()->sport (or whichever formatter exists in the class you opened).
5. Discover formatters quickly instead of guessing names:
collect((new ReflectionClass(\Mbezhanov\Faker\Provider\Sports::class))
->getMethods(ReflectionMethod::IS_PUBLIC))
->pluck('name');
Decorate once, use everywhere. Because fake(), Model::factory(), and the Faker\Generator singleton all resolve the same container binding, the extend() registration is the only wiring needed. Avoid calling Faker\Factory::create() inside a seeder — that creates a fresh generator with no providers attached and silently bypasses your registration.
Factory-level usage. Treat custom formatters exactly like built-ins:
public function definition(): array
{
return [
'title' => fake()->movieTitle,
'genre' => fake()->movieGenre,
'rating' => fake()->randomFloat(1, 0, 10),
'released' => fake()->dateTimeBetween('-5 years'),
];
}
Coherent fixtures across providers. The real value is composing a domain: a clinic demo using the Medical provider plus Faker's Person/Address; a games store using Gaming + Commerce/Payment. Build one small DemoData/Fixtures service that wraps fake() and returns whole aggregates (createPatient(), createReview()), then call it from both seeders and tests. This keeps provider names out of your factories and makes swapping the source of data trivial.
Reset-friendly unique values. For columns with a unique index, use the proxy:
$faker->unique()->sport; // never repeats within this proxy
$faker->unique(true)->sport; // resets the seen-list first
For bulk seeding, prefer $faker->unique(true) at the top of the loop, and keep the unique() proxy in a variable rather than recreating it per row when you actually want cross-row uniqueness.
Deterministic tests. When a test asserts on generated values, seed the generator: $faker->seed(42) (or fake()->seed(42)). Combine with RefreshDatabase and a fixed factory state so fixtures are reproducible. If you only need "some valid value", don't seed — seeding couples tests to Faker's internal call order, which changes when you add a provider.
Config-driven registry. Rather than hard-coding addProvider calls, keep a list in config/faker.php and loop:
foreach (config('faker.providers') as $provider) {
$faker->addProvider(new $provider($faker));
}
Adding a new domain later becomes a one-line config change rather than a service-provider edit.
Extension point: subclass the provider. If a list is too short or contains names you don't want in screenshots (real brands, real people), subclass the package provider and override its data array / add methods. Because there's no service provider to fight with, this is safe and upgrade-friendly.
composer require. If formatters are "not found", you forgot the extend() call, or you resolved Faker\Generator in a provider registered before AppServiceProvider.Generator::getFormatter() scans providers in insertion order, and Faker's own providers are added first by Factory::create() — so a custom colorName/name/word will be shadowed by the built-in. Check $faker->getProviders() and rename your formatter if it never fires.addProvider() clears the formatter cache, so late registration is usually fine — but only for the base generator. Proxies returned by unique()/optional() hold a reference to the generator, so they keep working after you add a provider; they will not, however, reset already-seen values.unique() can throw. Small static lists plus a big seeder equals OverflowException. Catch it, raise maxRetries, or fall back to a non-unique value with a random suffix.fake('de_DE') will not translate them. They'll return English names inside an otherwise localized fixture — noticeable in demos.$this->faker in tests is version-dependent. Use fake() or app(Faker\Generator::class) in test classes; the protected $this->faker property has come and gone across Laravel versions.UniqueGenerator you hold across iterations accumulate state and memory. Reset with seed() between jobs, or re-resolve per unit of work.$faker in the constructor; typo in the method name (verify via reflection, not the README); or the container instance is a different Faker\Generator (e.g. you called Factory::create() manually).fzaninotto/faker.How can I help you explore Laravel packages today?