Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Factory Laravel Package

aerni/factory

A Laravel package that generates Eloquent model factories from your database schema, inferring column types and relationships so you can start seeding realistic fake data for tests and local development in seconds.

View on GitHub
Deep Wiki
Context7

Getting Started

Install as a dev dependency. This package writes real content, so it belongs in require-dev only:

composer require aerni/factory --dev

The Composer name is aerni/factory even though the repo is statamic-factory. Check the composer.json constraint — the 2024-08 release targets Statamic 4/5; if you're on an older Statamic, pin accordingly.

Where to look first. Open vendor/aerni/factory/src/Factory.php — it's a small package and the base class is the whole API surface. Then skim the README for the exact method signatures for your pinned version, since minor helpers have moved between releases.

Create your first factory. One class per collection (and per blueprint, if a collection has several). A conventional location is database/factories, autoloaded via composer.json as you would for Laravel factories:

namespace Database\Factories;

use Aerni\Factory\Factory;

class ArticleFactory extends Factory
{
    protected $collection = 'articles';

    public function definition(): array
    {
        return [
            'title'   => fake()->sentence(),
            'intro'   => fake()->paragraph(),
            'content' => fake()->paragraphs(4, true),
        ];
    }
}

First use case. Seed a local collection so you can build templates, listings, and search against realistic data:

ArticleFactory::new()->count(25)->create();

Run it from php artisan tinker on a scratch database, or better, from a dev-only command (see below). If the fake entries render in your Antlers templates, you're done — that's the whole value proposition.

Implementation Patterns

One factory per blueprint, not per collection. Field handles in definition() must match the blueprint exactly. If articles has article and news blueprints, write two factories rather than branching inside one; overrides get messy otherwise.

Keep definition() boring. Return only the required fields and let the rest fall back to blueprint defaults. Fields you don't return simply stay empty, which is usually what you want for optional SEO/meta fields.

Variant content with states. For "featured", "draft", "long-form" shapes, compose on top of the base factory rather than duplicating it. In Laravel-factory style this looks like a method that merges overrides into the definition:

public function featured(): static
{
    return $this->state(fn () => ['featured' => true]);
}

ArticleFactory::new()->featured()->count(5)->create();

Check the README for whether your version exposes state() or expects you to override definition() with an array merge — both patterns exist across versions.

Seeding via a dedicated command. A php please fake-content or artisan command gated behind App::environment('local') is the cleanest day-to-day workflow. It keeps seeding out of migrations and gives teammates one command to bootstrap a project:

if (! app()->environment('local')) {
    $this->error('Refusing to write fake content outside local.');
    return;
}

ArticleFactory::new()->count(50)->create();

In tests, wrap creation with cleanup. Statamic persists entries to flat files, so tests that create entries leave artifacts unless you delete them. Use a tearDown() that queries by collection and deletes, or run tests against a throwaway content path. Pairing factories with a per-test fresh content directory makes test suites reproducible.

Relationships. Create the parent first, then feed its id or slug into the child's definition. Because entries are persisted immediately on create(), you can chain:

$author = AuthorFactory::new()->create();
ArticleFactory::new()->count(10)->create(['author' => $author->id()]);

Deterministic data. Call fake()->seed(1234) before generating so repeated runs produce identical content — invaluable when a template bug only reproduces with a specific title length.

Pair with please commands you already have. statamic:stache:warm, statamic:search:update, and cache clears should run after seeding; otherwise listings and search results may look empty even though the entries exist.

Gotchas and Tips

It writes to content/, for real. Unlike Laravel's database factories, this creates actual Markdown/YAML files in your content directory, which is usually tracked by git. After a seeding run, git status will be noisy. Either gitignore your local content tree, seed on a branch you discard, or always clean up afterward. This is the biggest "surprise" cost of the package.

No automatic teardown. There is no RefreshDatabase equivalent. Build your own cleanup helper early — a deleteFakeContent() command that filters by collection and deletes — and use it before every seed run so you don't accumulate 10,000 entries.

Slug collisions. Faker's sentence() can repeat, and Statamic derives slugs from titles. Duplicate slugs will silently overwrite or fail depending on your setup. Append a unique suffix (fake()->unique()->numberBetween(1, 999999)) or use fake()->unique()->words(3, true) for titles.

Dates and date behavior. For dated collections, set the date field explicitly; otherwise every entry lands at "now" and your ordering tests are meaningless. Use fake()->dateTimeBetween('-2 years') to spread entries realistically.

Validation rules still apply. If your blueprint or a save hook validates field formats (emails, URLs, max lengths), fake values that violate them will throw at save time. Match field semantics — safeEmail(), not sentence(), for an email field.

Multisite needs explicit sites. On a multisite install, entries may need sites set, and localized fields need per-site values. Seeding only the default site is the common silent failure: your second site looks empty and you assume the package is broken.

Asset and relationship fields. Passing a plain string to an assets or entries field won't resolve. Reference real asset container paths or existing entry IDs, or omit the field entirely — an empty assets field is better than an invalid one.

Performance scales linearly and painfully. Each create() is a file write plus Stache update. Seeding a few hundred entries is fine; a few thousand will crawl and bloat your Stache. Batch in the hundreds, run php please stache:clear if the index drifts, and avoid seeding during a stache:warm lock.

Extension point: a project base factory. Subclass Aerni\Factory\Factory once with your common helpers (a published() state, a uniqueTitle() helper, your seeded Faker instance) and have all project factories extend that. It keeps the package untouched and makes upgrades painless.

Never ship it to production. The --dev requirement plus a hard environment('local') guard in your seed command is the pattern that holds up. A factory call in a deploy script is the one mistake you cannot walk back cleanly, because it commits fake content into version control.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource