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

Doctrine Assigned Identity Laravel Package

tseho/doctrine-assigned-identity

Doctrine ORM extension that lets entities use application-assigned identifiers—UUIDs, natural keys, or custom IDs—instead of database auto-increment, while keeping Doctrine's identity map and UnitOfWork working correctly.

Deep Wiki
Context7

Getting Started

  1. Install as a dev dependency. This package exists to make tests easier, so keep it out of production autoloading:

    composer require --dev tseho/doctrine-assigned-identity
    
  2. Read the source before the README. With ~10 stars and no linked repository, the package is small and low-activity; the src/ directory (a trait and/or an event subscriber is the typical shape) is the fastest way to learn the exact API surface. Confirm which class you need to add to your entity and whether the package ships a Doctrine DBAL type, an ID generator, or a prePersist listener.

  3. Wire it into one entity first. The normal first use case is a unit or functional test that needs a known primary key before the entity is persisted — for example, asserting that a repository method returns the entity with id = 1, or building fixtures with stable IDs so other fixtures can reference them. Add the package's trait (or implement its interface) on the entity whose ID you want to control, then set the ID explicitly:

    $user = new User();
    $user->setId(42);          // normally impossible; the generator would overwrite it
    $user->setEmail('[email protected]');
    $em->persist($user);
    $em->flush();
    
    self::assertSame(42, $user->getId());
    
  4. Run against SQLite in-memory first. It is the least surprising target: no sequence to fight, no auto-increment column to override. If it works there, then try your real test database.

Implementation Patterns

Deterministic fixtures / data providers. The strongest day-to-day use is seeding entities with fixed IDs inside a test data provider or fixture loader, so expected IDs in assertions and related fixtures are stable regardless of insertion order or database sequence state. Pair it with a fresh schema per test class.

Explicit-ID factories in tests. Wrap entity creation in a small test factory that sets the ID through the package, so production code never sees the manual-ID path:

final class UserFactory
{
    public static function create(int $id, string $email = '[email protected]'): User
    {
        $user = new User();
        $user->setId($id);
        $user->setEmail($email);
        return $user;
    }
}

Bypass the ID generator only where needed. Keep the trait on test-facing entities, or conditionally register the package's subscriber in config/packages/test/doctrine.yaml. Do not let this leak into a shared base entity used by production, or you risk persisting entities with null IDs in prod if the subscriber is accidentally enabled.

Pair with an event subscriber for bulk fixtures. If the package exposes a prePersist hook, register it only in the test kernel. Then a fixture set can loop and assign IDs from an incrementing counter, and the listener prevents Doctrine from re-generating them on flush. This composes well with doctrine/data-fixtures.

Integration with repository tests. When you test custom DQL or query-builder methods, assigned IDs let you assert exact result ordering and primary keys without depending on auto-increment starting values, which differ between SQLite, MySQL, and Postgres.

Compose with relationship fixtures. Build parent and child with known IDs first, flush in dependency order, then assert joins and collections. Because IDs are known up front, you can build association arrays before persisting anything.

Gotchas and Tips

  • IDENTITY generators ignore assigned values. If the entity uses @GeneratedValue(strategy="IDENTITY"), the database assigns the ID and your manual value is discarded — or worse, causes a constraint error. You generally need NONE/ASSIGNED strategy, or the package's own generator, for manual IDs to stick. Verify which strategy the trait expects.
  • Auto-increment schema columns fight you. Even with an assigned value, a column defined as AUTO_INCREMENT / SERIAL may still be overridden by the database. Prefer a plain integer or UUID column in the test schema, and remember that this means your test schema can diverge from production migrations — a classic source of "passes in SQLite, fails in MySQL" bugs.
  • Doctrine's identity map. If you flush an entity with ID 1, then build another entity with ID 1 in the same EntityManager, Doctrine treats them as the same managed object. Clear the manager ($em->clear()) between fixture batches, or use disjoint ID ranges per test.
  • Type coercion. UUIDs and string IDs need to match the column type exactly; assigning "1" to an integer column can silently succeed in SQLite and fail in Postgres. Assert on getId() return type if your code is strict-typed.
  • Detached and unmanaged entities. Manually setting an ID on an entity that is already managed can trigger Detached entity ... already has an identifier errors. Always construct, set the ID, then persist.
  • Versioning and optimistic locking. If the entity has a @Version field, manual IDs don't help; you still need a flush to populate the version. Don't assume assigned identity makes the entity fully "ready" without a round trip.
  • Debugging tip. When the assigned ID disappears after flush(), enable doctrine.dbal.logging and inspect the generated INSERT — if the ID column is in the column list but the value is regenerated, the issue is the generator strategy; if the column is omitted entirely, the issue is the listener not being registered.
  • Extension points to prefer. Rather than editing vendor code, subclass the package's trait or write your own prePersist subscriber behind a test-only service tag. A small subscriber is often clearer than adopting the whole package if you only need manual IDs on two or three entities.
  • Maintenance risk. With low star count and an unlinked repository, treat the package as a small, replaceable utility: pin the version, and be prepared to inline the few lines of logic (a trait plus a subscriber) if it stops being maintained.
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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels