davidbadura/faker-markdown-generator
A Faker provider that generates realistic Markdown content for PHP and Laravel projects. Create headings, paragraphs, lists, links, code blocks, and other formatted snippets to seed demos, tests, and fixtures with believable documentation-style text.
This package is a Faker provider, not a standalone markdown library. It plugs into an existing Faker\Generator and adds formatters that return random-but-valid markdown strings.
Install (Laravel 8+ already ships fakerphp/faker):
composer require davidbadura/faker-markdown-generator:^1.1.1 --dev
The --dev flag is usually correct: the realistic use case is fixtures, seeders, and tests, not production content. Pin at least 1.1.1 — see the blockquote note under Gotchas.
First place to look: the provider class itself, typically src/Provider/Markdown.php. The README is short; the source is the real documentation. Grep the public methods to see the exact formatter names and what each block type produces before you build on them.
Minimal usage:
use DavidBadura\FakerMarkdownGenerator\Provider\Markdown;
use Faker\Factory;
$faker = Factory::create();
$faker->addProvider(new Markdown($faker));
echo $faker->markdown(); // a full random markdown document
In Laravel, the same generator is reachable via fake() or $this->faker inside factories and seeders:
$faker = fake();
$faker->addProvider(new \DavidBadura\FakerMarkdownGenerator\Provider\Markdown($faker));
$body = $faker->markdown();
First use case: a Post factory with a markdown body column. It gives you headings, paragraphs, lists, quotes, and code fences without hand-writing fixture text, and it exercises your renderer (league/commonmark, Blade markdown components, etc.) with more structure than $faker->paragraphs() ever will.
Add the provider once, not per call. Faker's addProvider() appends to an internal list and duplicate additions are tolerated but wasteful. Put the addProvider call in a place that runs once per generator instance.
For Laravel factories, configure() is the natural hook:
class PostFactory extends Factory
{
public function configure(): static
{
$this->faker->addProvider(new Markdown($this->faker));
return $this;
}
public function definition(): array
{
return [
'title' => $this->faker->sentence(),
'body' => $this->faker->markdown(),
];
}
}
If you want the provider available to every factory and seeder, extend the container binding in a service provider:
// AppServiceProvider::register()
$this->app->extend(\Faker\Generator::class, function ($faker) {
if (! $faker->getProviders()/* or your own guard */) {
$faker->addProvider(new Markdown($faker));
}
return $faker;
});
Verify this against your Laravel version — the Faker\Generator binding is an implementation detail, and extend() must run after the binding is registered. If that feels fragile, a tiny helper is safer and more obvious:
function markdownFaker(): \Faker\Generator
{
static $faker = null;
if ($faker === null) {
$faker = fake();
$faker->addProvider(new Markdown($faker));
}
return $faker;
}
Mix with native Faker formatters. The provider only owns its own methods. Combine $faker->markdown() for body content with $faker->sentence(), $faker->slug(), $faker->dateTimeBetween() for the surrounding model attributes. Don't try to use the markdown provider for metadata.
Deterministic fixtures. For snapshot tests or reproducible demos, seed before generating:
$faker = fake();
$faker->seed(42);
$faker->addProvider(new Markdown($faker));
Seed after provider registration only if you control all random calls; otherwise seed at the very start of the test/setup.
Granular blocks in feature tests. Prefer the specific block formatters over markdown() when you need a targeted case — e.g., a single heading or list to test a TOC generator or a list-rendering component. This is especially worth doing for blockquotes: 1.1.1 fixed the blockquote output, so a focused test on the quote formatter is cheap coverage against regressions. Check the provider source for the exact names; the coarse markdown() output is great for "renderer does not blow up" tests, less so for asserting a specific HTML shape.
Seeder usage:
Post::factory()
->count(50)
->create(['body' => fn () => markdownFaker()->markdown()]);
Or simply rely on the factory's definition(). Avoid calling addProvider inside a closure that runs 50 times.
Integration with renderers. Pipe output through the same parser you use in production (e.g., League\CommonMark\CommonMarkConverter) and store the HTML if that's your pipeline. This catches edge cases in list nesting and table-like structures early — and it's exactly the class of bug the 1.1.1 blockquote fix addresses.
markdown() at all, since documents can contain quotes — you may have been generating malformed blocks that a lenient parser silently merged into the preceding or following paragraph. Upgrade, then re-check any stored fixtures, snapshots, or seeded content that was generated with the old version. If you generated and committed markdown fixtures, regenerate them.tests/Support/ if you only need it in tests. The source is small; copying one file removes a supply-chain and upgrade risk entirely.fzaninotto/faker (abandoned); Laravel 8+ uses fakerphp/faker. Check the package's composer.json constraint before installing, and expect composer require to fail or resolve oddly if it targets the abandoned package.addProvider needs the generator instance. new Markdown() with no argument will fail or produce a provider with no Faker reference. Always new Markdown($faker).src/Provider/Markdown.php rather than guessing from the README. If an expected method is missing, you're likely on a different release than the docs.## heading, has a fenced block, has a > line) rather than exact text.fakerphp/faker if you snapshot raw markdown.app()->environment(['local', 'testing']).markdown() body adds up. Cap document size or generate once and reuse in bulk seeders.Markdown to add your own block formatters (e.g., a task-list block, a fenced php block with realistic code) and register the subclass instead. That's the clean way to get domain-specific fixtures without forking the whole package — and it's a reasonable hedge if upstream goes quiet again.How can I help you explore Laravel packages today?