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 Inspectors Laravel Package

smartassert/doctrine-inspectors

Inspect Doctrine ORM entities and metadata programmatically. smartassert/doctrine-inspectors provides utilities for examining entity classes, fields, associations, and mappings, useful for analysis, validation, and tooling in Doctrine-based PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

smartassert/doctrine-inspectors is a small, testing-oriented library that exposes read-only inspection of Doctrine entities, their entity manager, and their mapping metadata. In a Laravel app it belongs in require-dev, and it earns its place when you want to assert things about your model layer (identifiers, field types, associations, table names) in tests rather than asserting behaviour through the database.

As of 4.0 the package requires PHP 8.4, phpunit ^12, and phpstan ^2, and adopts PER-CS (replacing PSR-12). There are no functional/API changes called out in the changelog — the release is a toolchain refresh — but the platform bump is real and will block installation on Laravel apps still running PHP 8.2/8.3.

Minimal steps:

composer require --dev smartassert/doctrine-inspectors:^4.0

Where to look first, in this order:

  1. The entity inspector (src/Entity/...) — the primary entry point; you hand it an entity instance and read back class name, identifiers, fields, and associations.
  2. The factory — how inspectors are constructed, and therefore how you wire them into the container.
  3. The entity manager inspector (src/EntityManager/...) — wraps EntityManagerInterface and answers "is this class managed?", "what is the metadata for X?".
  4. The mapping inspector — the bridge between Doctrine metadata and your physical schema (table names, column definitions).

First use case — a guard test that every entity your app persists is actually mapped:

use Doctrine\ORM\EntityManagerInterface;

it('maps every domain entity', function (string $class) {
    $em = app(EntityManagerInterface::class);

    expect($em->getMetadataFactory()->isTransient($class))->toBeFalse();
})->with(fn () => glob(app_path('Models/*.php')));

Then escalate to the inspectors when you need structured answers (identifier field names, association targets) instead of a boolean.

Implementation Patterns

Bind inspectors through a test-only service provider. Don't app(...) the factory inline in twenty tests; register a TestingServiceProvider (or bind in TestCase::setUp) so the factory receives the same EntityManagerInterface your app resolves. This keeps the inspectors honest about proxies and lazy metadata.

Entity-provider pattern. Combine a PHPUnit data provider over your model directory with a parameterised test that runs each class through the inspector. This is the highest-value use: it catches "someone added an entity and forgot to register it / forgot an attribute" at CI time rather than in production.

it('has a valid identifier', function (string $class) {
    $entity = new $class();               // or resolve via container/factory
    $inspector = $this->entityInspectorFactory->create($entity);

    expect($inspector->getIdentifierFieldNames())->not->toBeEmpty();
})->with(entityClasses());

Pair with doctrine/schema-validator. The inspectors tell you what Doctrine thinks the mapping is; the schema validator tells you whether the database agrees. Run both in the same test suite — inspectors for cheap, DB-less assertions; schema validator in a slower integration group.

Assert before persisting, not after. Inspector assertions are pure metadata reads, so they run without RefreshDatabase. Put them in a fast unit-style suite and keep the database-touching tests separate; it meaningfully cuts CI time on larger Laravel apps.

Version strategy across a multi-app estate. If you maintain several Laravel apps, pin ^3.0 on anything below PHP 8.4 and roll ^4.0 forward only with the runtime upgrade. Because 4.0 pins PHPUnit 12, this is really an "upgrade PHPUnit and PHP together" task, not a standalone dependency bump.

CI parity. Mirror the package's own toolchain if you vendor or extend it: PHP 8.4, PHPUnit 12, PHPStan 2. Mismatched static analysis versions are the most common source of "works locally, fails in CI" in repos that reuse smartassert tooling.

Gotchas and Tips

  • PHP 8.4 is a hard floor in 4.0. Composer will refuse to install on 8.2/8.3 even though nothing in the API changed. If your CI matrix still includes 8.3, the install step fails before any test runs — check composer.json platform config as well as the runner image.
  • PHPUnit 12 only. Laravel 10/11 projects commonly sit on PHPUnit 10/11 or Pest 2. Expect a resolution conflict; you'll need to upgrade the test stack in lockstep or stay on ^3.0.
  • PER-CS replaces PSR-12. Irrelevant unless you vendor the source or run a shared PHP-CS-Fixer config; if you do, expect a one-off reformat diff.
  • Proxy classes. If you pass an entity that has been loaded through the EntityManager, you may be holding a Proxy. Inspecting a proxy's class name gives you the generated subclass, not your model. Resolve the real class (Doctrine's class-utils helper) before asserting on class names, or always construct fresh instances for inspection.
  • Unmanaged classes throw. The entity-manager inspector is strict: a class not known to the metadata factory produces an exception rather than a false. Wrap it if you're iterating a directory that may contain non-entity classes (DTOs, enums, value objects).
  • Dev-only, always. The package pulls in Doctrine testing surface you don't want autoloaded in production; keep it in require-dev and never reference it from app/ code paths.
  • PHPStan 2 behaviour shift. If you analyse your tests/ directory, upgrading to PHPStan 2 alongside this package can surface a wave of new findings. Regenerate the baseline in its own commit, separately from the dependency bump.
  • Extension points are thin. The inspectors are deliberately small and mostly final; the intended pattern is composition — write your own assertion helpers or Pest expectations that wrap an inspector, rather than subclassing one. That also keeps your test API stable across major versions of the package.
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