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

Laravel Doctrine Projections Laravel Package

darangonaut/laravel-doctrine-projections

A Laravel package for Doctrine projections that helps you build and maintain read models from domain events. It integrates projection classes with Laravel’s container and console, making event-sourced read-model setup and rebuilding straightforward.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Baseline: no prior assessment existed; this establishes the first baseline at v0.7.0. Prior versions should be considered unfit for use — v0.7.0 fixes two silent-failure classes that would have shipped broken systems.

Architecture fit. The package is a build-time generator: it reads Doctrine ORM mapping metadata and emits Eloquent model classes ("projections") plus migrations. That is a good architectural shape for our context if — and only if — we have a Doctrine-mapped domain layer and want an Eloquent query surface over it without hand-maintaining a parallel set of models. The strongest signal in the release notes is that generation reads mapping, not schema, and needs no database (pinned by test; 200 entities in 0.03s). That makes generation deterministic, cheap, and runnable in any CI job without a service container. It also means generated output can be diffed and reviewed like source.

Integration feasibility. Low technical effort, moderate verification effort. Constraints are explicit and checkable: PHP 8.3/8.4, Laravel 12/13, SQLite/MySQL 8.4/PostgreSQL 16. The Eloquent surface we would actually depend on — chunk, cursor, lazy, paginate, route model binding, replicate, toArray, toJson — is verified under Model::shouldBeStrict(), which is the right test posture and materially raises confidence in the generated runtime behavior.

Technical risk. This is a minor version with three deliberate refusals (namespace collision with entity namespace, case-only-differing short names, migration overwrite) — each documented in UPGRADING.md, each turning a previously silent mis-generation into a hard failure. For a 0.x package this is legitimate, but it means pinning is mandatory and CI pipelines that previously passed may now fail.

The two substantive fixes define the real risk picture:

Fixed defect Failure mode Exposure if we ran < 0.7.0
Abstract STI class had no scope Returned every row in the table (folder appeared as a file) Wrong query results, potential cross-type data exposure
Failed write reported as success (File::put() false / raw ErrorException) Printed "3 projection(s) generated", exit 0 Green deploy with no models; total app breakage post-deploy

Both are the "silent" category, and both are exactly the kind of failure a TPM must assume exists in any code-generation tool until proven otherwise. The remaining risk is the three mapping patterns documented rather than guarded (non-backed enum, enumType on a json column, discriminator column mapped as a field). These will produce broken projections at runtime with no generator complaint — so they must be covered by our own mapping lint, not by trust.

Key questions for the maintainer/team:

  1. Do any of our entity classes sit in, or share a prefix with, the configured projection namespace?
  2. Do we have entity short names differing only in case? (Will pass on Linux CI, fail on macOS/Windows dev machines — or vice versa.)
  3. Are generated migrations committed? If so, has any historical run collided on the timestamp-to-the-second + doctrine_diff default?
  4. Do we use STI with abstract intermediate classes? Those query semantics change in this release (narrower results) — what application code depends on the old behavior?
  5. What is the post-1.0 versioning and support policy, and what is the maintainer bus factor?
  6. Is generated code committed or built at deploy time, and who owns the regeneration step?

Integration Approach

Stack fit. Clean, provided we are on Laravel 12/13 and PHP 8.3+. The verified database matrix matches ours. The dependency on Doctrine mapping metadata is the gating prerequisite — if the entity layer is not Doctrine, the package is not applicable.

Migration path. Pin 0.7.x (not a floating ^0.7) and upgrade on a branch. The critical step is regenerate everything and diff the artifacts. Two categories of diff will appear:

  • Scope changes on STI hierarchies — generated Eloquent models for non-root classes now carry a discriminator scope. Any application code that relied on the old unscoped behavior will silently see fewer rows. This is a correctness fix, but it is a behavioral change and belongs in the release notes of our deploy, not just theirs.
  • New refusals — the generator will now abort on namespace/case/migration collisions. Run generation locally (on both a case-sensitive and case-insensitive filesystem) before it reaches CI.

Compatibility. No API surface is documented as removed; the breakage is in generator acceptance criteria, not in a public PHP API. That is the cheapest kind of break — it fails at build time, not at runtime. Still treat it as breaking for our pipeline contract.

Sequencing.

  1. Inventory entity mappings; flag STI hierarchies, case-colliding names, and the three documented-unsupported patterns.
  2. Verify projection namespace does not overlap entity namespaces.
  3. Upgrade in branch; run generation; diff generated models and migrations; review the STI scope deltas line by line.
  4. Run the full suite with Model::shouldBeStrict() enabled in staging; add targeted query-count/row-count assertions for each STI hierarchy.
  5. Add a CI gate: regenerate and fail on dirty working tree (this also catches the false-success class of bug permanently).
  6. Clear/rename any historical migration collisions, then deploy.

Operational Impact

Maintenance. Generated artifacts become a maintained surface. Every Doctrine mapping change requires regeneration and PR review of the diff. Keep projections in a dedicated directory and namespace, treat the output as vendored code, and never hand-edit it.

Support. 0.x with a single maintainer — the classic bus-factor exposure. Mitigating evidence is strong: 211 tests, PHPStan at max with no baseline, and a real OS/DB/PHP matrix. That is well above median for a 0.x package, but it does not remove the need for a pilot and an exit plan (worst case: freeze the generator, commit the output, and own the generated models).

Scaling. Generation cost is negligible (200 entities / 0.03s) and does not grow with data volume. Runtime scaling risk sits in the generated Eloquent models: STI scopes add a discriminator predicate to every query, so ensure the discriminator column is indexed on single-table hierarchies. chunk/cursor/lazy being verified means large-table iteration paths are usable.

Failure modes to instrument.

  • Silent success with no output — largely closed in 0.7.0, but the CI dirty-diff gate is the durable control, not the release notes.
  • Collision aborts — loud, but only at generation time; a pre-flight check in the pipeline shortens feedback.
  • Unsupported mappings — silent today; a mapping lint covering non-backed enums, enumType on json, and discriminator-as-field is mandatory before onboarding new entities.
  • Drift — a Doctrine mapping changed but generation was skipped; caught by the same dirty-diff gate.

Ramp-up. Low for anyone fluent in Laravel and Doctrine — roughly a day to first generated projections and half a day of team documentation on the projection namespace convention, migration generation, and STI scoping rules. Budget an extra half day for the case-sensitivity divergence between macOS/Windows developer machines and Linux CI, which is the least intuitive of the new refusals.

Recommendation. Adopt at exactly 0.7.x for a scoped pilot on one or two bounded domains, with the generation CI gate and mapping lint in place from day one. Do not adopt below 0.7.0 under any circumstance, and do not adopt 1.0+ without a stated support policy.

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.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log