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

Fixtures Laravel Package

xi/fixtures

Xi/Fixtures is a Laravel package for defining and loading fixtures, helping you seed consistent test and development data through a simple, expressive API. It streamlines fixture management so your database setup stays repeatable and easy to maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

xi/fixtures is a small, Doctrine-2-era factory library: you describe how to build an entity once, then ask for instances in tests with per-test overrides — the same ergonomics as Laravel's model factories, but for Doctrine entities instead of Eloquent models.

Before anything else, verify it installs. This package predates modern PHP and Doctrine tooling. Run:

composer require --dev xi/fixtures

If resolution fails on your PHP/Doctrine versions, check composer why-not xi/fixtures before fighting it — for many Laravel projects today the honest answer is "vendor a trimmed-down copy of the factory class" or "use doctrine/data-fixtures + Faker instead." Everything below assumes you got it installed (or vendored) against a Doctrine EntityManager.

Where to look first

  1. README.md — the usage example is the API in miniature.
  2. src/Xi/Fixtures/FixtureFactory.php — the class you'll actually call; note the exact method names (getEntity()/createEntity() style) and how it resolves field values.
  3. src/Xi/Fixtures/Annotation/ — if you plan to put defaults on entities via annotations, this is the authoritative list of annotation names. Don't guess them.
  4. tests/ — for a package this size, the test suite is the documentation. Copy patterns from there.

First use case: one entity, one test. Put a project-level subclass in tests/Support/ so your tests never touch FixtureFactory directly:

// tests/Support/Fixtures.php
namespace Tests\Support;

use Xi\Fixtures\FixtureFactory;

class Fixtures extends FixtureFactory
{
    public function user(array $overrides = [])
    {
        return $this->getEntity(App\Entity\User::class, $overrides + [
            'username' => 'user_' . self::nextId(),
            'email'    => 'user_' . self::nextId() . '@example.test',
        ]);
    }
}

Then in a test:

$user = $this->fixtures->user(['email' => '[email protected]']);

That's the whole day-to-day loop: define once, override per test. Get that working on one entity before building out twenty factory methods.

Implementation Patterns

One method per entity, overrides merged last. The single most important convention: the caller's array always wins. This keeps tests readable and makes factory methods safe defaults rather than fixed values.

public function order(array $overrides = [], ?User $user = null)
{
    return $this->getEntity(App\Entity\Order::class, $overrides + [
        'reference' => 'ORD-' . self::nextId(),
        'user'      => $user ?: $this->user(),
        'placedAt'  => new \DateTimeImmutable('2024-01-01 12:00:00'),
    ]);
}

Build vs. persist. Distinguish the two if the factory supports it (a non-persisting create for unit tests, a flushing one for integration tests). Unit tests that never touch the database run in milliseconds; reserve persistence for the tests that actually assert on queries.

Relationships: construct children explicitly. Prefer passing fully-built related entities in the overrides array over relying on cascade-persist behaviour. It's more verbose but it eliminates the "why is this entity detached / why did two users get created" class of bug:

$order = $this->fixtures->order([], $this->fixtures->user(['email' => '[email protected]']));

Deterministic unique values. Never use uniqid() or random strings for unique columns in tests — collisions are rare but maddening, and randomness breaks reproducibility. Use a reset-per-test static counter:

private static int $seq = 0;

private static function nextId(): int
{
    return ++self::$seq;
}

// in your base TestCase::setUp()
Fixtures::resetSequence();

Wire it once, in a base TestCase. Don't new Fixtures(...) in every test. Resolve the EntityManager from Laravel's container (e.g. laravel-doctrine) in a testing-only service provider or directly in setUp():

protected function setUp(): void
{
    parent::setUp();
    $this->fixtures = new Fixtures(app('em'));
}

Wrap each test in a transaction. Doctrine's identity map and database state bleed between tests otherwise. Open a DBAL transaction in setUp(), roll it back in tearDown(), and call $em->clear() so the next test starts with a fresh identity map:

protected function tearDown(): void
{
    $this->em->clear();
    $this->em->getConnection()->rollBack();
    parent::tearDown();
}

Keep dev seeders separate. Use doctrine/data-fixtures (or plain fixtures) for db:seed-style developer data. xi/fixtures belongs in tests/ only — mixing the two means test data leaks into environments where it shouldn't exist.

Annotations vs. code: prefer code. If the package lets you declare defaults via annotations on entity properties, that's convenient but invisible — a grep for 'email' won't find it. Keep defaults in the factory class where a rg search finds them; use annotations only for trivially-obvious values if at all.

Gotchas and Tips

It is Doctrine-only. This is not an Eloquent factory. If your Laravel app is Eloquent-based (default), this package has no role — use database/factories. Only reach for it in a Doctrine-backed app (e.g. via laravel-doctrine), and don't try to shim Eloquent models into it.

Maintenance risk is the headline gotcha. Single-digit stars, zero dependents, and code from the PHP 5 era. Expect doctrine/annotations deprecation warnings, PHP 8 incompatibilities (dynamic properties, nullable parameter ordering), and a missing composer.json PHP constraint that lets Composer install something broken. Pin it, or fork it into packages/ so you control the fixes. Do not build your whole test strategy on it without an exit plan.

EntityManager state, not fixture state, is what bites you. Detached entities after clear(), stale identity maps reusing the wrong object, and flush() semantics are the real debugging surface — not the factory. When an assertion fails strangely, first ask "is this the object I think it is?"

Unique constraints fail at flush, not at create. A duplicate email will surface as a Doctrine\DBAL\Exception\UniqueConstraintViolationException at flush() time, far from the factory call. Log or dump() the generated values in the failing test before chasing the assertion.

Lazy proxies surprise assertions. assertSame and equality checks on relations may compare proxies or uninitialised collections. Assert on IDs, or explicitly $em->refresh($entity)/access the collection before comparing.

Annotation reader cache in tests. If you're using annotation-driven defaults, the reader's cache can serve stale metadata after you edit an entity. Clear it (or disable caching in the test environment) when a definition change appears to have no effect.

Field-name mismatch is the most common runtime error. The factory resolves properties against entity metadata; a typo in an overrides key often fails silently or throws something unhelpful. Keep factory methods short and typed so mistakes surface at the call site.

Extension points worth knowing: subclass and override the field-resolution/naming convention if your codebase has non-obvious property names; register custom Faker providers if you standardise on realistic data; and centralise all defaults in the base Fixtures class — that class is your migration target if you later move to nelmio/alice or doctrine/data-fixtures, and keeping it as the single entry point makes that swap a mechanical translation rather than a rewrite of every test.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle