popo/generator
popo/generator scaffolds Plain Old PHP Object (POPO) classes from your database tables, reducing boilerplate and helping Laravel developers build a simple, maintainable data layer.
What it actually is. popo/generator is a build-time code generator: it reads a YAML schema and emits plain PHP classes (POPOs/DTOs). Critically, it is not a runtime dependency — it does not sit in the request path, does not register a service provider in the hot loop, and the artifacts it produces are framework-agnostic PHP. This materially lowers the blast radius of adopting it, and it also means the tool is replaceable: worst case, you keep the generated classes and drop the tool.
Architecture fit. Good fit for teams practicing explicit boundary modeling (hexagonal/clean architecture, CQRS read models, API request/response contracts) where DTOs are currently hand-written and repetitive. The generated output has zero coupling to Laravel or to the generator itself, which is the right property. The architectural cost is that you introduce a second source of truth: the YAML becomes a schema of record, and the PHP becomes derived. That is a governance commitment, not a technical one, and it is where most adoptions of this class of tool fail.
Integration feasibility. Low. It is a Composer package installable under require-dev, invoked via CLI or a thin Artisan wrapper, writing into a target namespace. There is no migration, no database surface, no middleware, no config publishing to speak of. A spike is measurable in hours. The integration risk is almost entirely in convention (naming, namespaces, where generated files live, how they are excluded from or included in static analysis) rather than in wiring.
Technical risk. The dominant risk is maturity, not capability:
readonly properties and constructor promotion, native enums, backed enums, union/intersection types, nullable handling, nested DTOs, typed collections (array<int, Foo> vs. untyped array), and default values.require-dev in a regulated codebase.Key questions to resolve before a go decision.
readonly/promoted constructors and native enums?Stack fit. Reasonable for a Laravel codebase, with one important caveat: it overlaps heavily with spatie/laravel-data, which is mature, widely adopted, and provides runtime validation, casting, and transformation on top of DTOs. If the team already uses laravel-data, popo/generator adds marginal value — you would be generating classes that a richer library already scaffolds. The genuine niche is teams that specifically want dependency-free POPOs with no runtime library attached, or teams generating DTOs for non-Laravel consumers (SDK clients, shared contract packages) where pulling in a framework helper is undesirable.
Placement. Install under require-dev. Emit into a dedicated, clearly-named directory (e.g. app/Data/Generated or a packages/contracts path) that is excluded from hand-editing by convention and annotated with a "generated — do not edit" header. Keep the YAML schema checked into the repo alongside the code it produces so the derivation is reviewable in the same PR.
Migration path. Do not retrofit the existing DTO surface. Start with a bounded spike:
fromArray/toArray helpers (likely absent — plan for that gap).Only expand if parity is acceptable and the team accepts the schema-governance overhead.
Compatibility and CI gates. Pin the version explicitly; do not float. Add a CI step that runs generation and asserts git diff --exit-code so drift between YAML and PHP fails the build rather than silently accumulating. Run the generator's output through the same static analysis baseline (PHPStan/Psalm) as the rest of the app so type-fidelity gaps surface immediately.
Sequencing.
Maintenance. The tool itself is small, but adoption transfers a durable maintenance obligation: you now own the YAML schema, the generation pipeline, and the review process for both. Generator upgrades are the sharp edge — if output templates change between versions, a patch bump can produce a repository-wide diff that is functionally a no-op but unreviewable. Budget for deliberate, batched regeneration rather than continuous upgrades.
Support. No vendor, no SLA, negligible community. Support is self-support. Mitigations: pin the version, vendor or fork the package internally, and confirm the MIT license permits the fork (it does). Treat "we may have to fork this" as a planning assumption rather than a contingency.
Scaling. Technically it scales without concern — it is a build step, and build steps are cheap. The scaling constraint is organizational: as more teams contribute to a shared YAML schema set, you need ownership, review rules, backwards-compatibility discipline, and a versioning scheme for the schema itself. Left ungoverned, the YAML quietly becomes an undocumented internal DSL with no owner, which is a worse outcome than the hand-written boilerplate it replaced.
Failure modes to plan for.
array/mixed, static analysis passes, and a runtime type error reaches production.Ramp-up. Shallow for individual engineers: YAML plus generated PHP is immediately legible, and the onboarding question is only "where did this class come from?" — answered by a header comment and a short README section. Realistic estimates: roughly 1–2 engineer-days for the spike and parity report, and about one sprint to institutionalize (CI gate, conventions, generation script, rollback runbook). The ongoing tax is the review discipline on regeneration PRs and periodic schema stewardship, which should be assigned to a named owner before rollout rather than after.
Recommendation. Conditional adoption, scoped narrowly. Worth a spike for greenfield DTO scaffolding in one or two bounded contexts where framework-free plain-PHP data structures are an explicit goal. Not justified for retrofitting an existing DTO surface, not justified if spatie/laravel-data is already in the stack, and not justifiable at all until the PHP-version support, type fidelity, and output determinism questions are answered with evidence from the actual repository rather than the package summary.
How can I help you explore Laravel packages today?