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

Popo Laravel Package

scrumble-nl/popo

Popo is a Laravel package for generating plain old PHP objects (POPOs) from Eloquent models, giving you lightweight, framework-independent data containers that keep application layers clean and decoupled, with simple Artisan commands and an expressive API.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What the package is (working assumption): scrumble-nl/popo is a Laravel-oriented generator/abstraction for Plain Old PHP Objects — typed data-transfer objects used to move validated data between HTTP, service, and persistence layers instead of associative arrays. The evaluation below is written on that assumption and must be confirmed in the first diligence step; if it turns out to be a domain-model/presenter helper instead, the integration plan holds but the value case shifts from "type safety at boundaries" to "serialization consistency."

What changed in 2.0.2 (delta review). The release removes the laravel/helpers dependency — snake_case() is replaced by Str::snake() — because laravel/helpers defines array_first()/array_last() with Laravel's two-argument signature, which collides with PHP 8.5's native one-argument functions. No API changes are declared. Two implications matter more than the diff itself:

  1. The package is actively maintained and is being kept ahead of a PHP minor. PHP 8.5 compatibility work landing before broad adoption is a meaningful positive signal and directly contradicts the "likely abandoned consultancy byproduct" hypothesis that dominated the previous assessment.
  2. The release notes publish a CI matrix: Laravel 10–13 on PHP 8.1–8.5. This answers the two most load-bearing open questions from the prior review (version constraints, existence of CI) in the affirmative, without us having to run the audit.

Architecture fit. Unchanged and still the package's main virtue. POPO/DTO layers fit cleanly into a conventional Laravel layering (FormRequest → DTO → Action/Service → Eloquent). This is additive: it does not touch routing, the container, or the ORM, so blast radius is low. It fits best where we already have a boundary problem — fat controllers, array-passing between jobs/listeners, payloads crossing into queues. It fits poorly in codebases that are deliberately array-first or that already standardize on Spatie Laravel Data or plain readonly classes; adopting it there creates a second, competing convention. Nothing in 2.0.2 changes this.

Integration feasibility. Still mechanically easy: Composer install, optional service provider auto-discovery, Artisan generator commands, no infrastructure or migrations. 2.0.2 slightly improves feasibility by shrinking the dependency graph — one fewer transitive package to audit, and the removed package is a global-function-definition package, which is exactly the kind of dependency that causes namespace collisions in large applications. The feasibility question remains organizational (will the team keep generated classes in sync with schema), not technical.

Technical risk — materially reduced, but not resolved. The prior assessment called this the dominant concern. The release moves the needle on maintenance and competence; it does not move it on adoption breadth:

  • Still ~5 stars, ~0 dependents. This remains the single biggest unaddressed risk. Being well-maintained by one agency is not the same as being battle-tested across many codebases; we will still find the edge cases first.
  • Bus factor. The CI matrix and changelog discipline suggest at least one competent, engaged maintainer — but a PR number (#12) is not evidence of a second maintainer. Assume bus factor 1 until proven otherwise.
  • Semver line moved to 2.x. We are now evaluating a post-major package. The major bump happened at some point we did not review; treat the 1.x→2.x changelog as required reading before any decision, since "no API changes" describes 2.0.2 only, not the 2.0 line as a whole.
  • Transitive-helper breakage is a real, if narrow, integration hazard. Applications that only had array_get(), str_*(), or snake_case() via popo's transitive dependency will now get fatal errors at call sites unrelated to the package. This is the classic "removing a dependency is a breaking change for someone" case. The release notes document the remedy (composer require laravel/helpers), which is good practice, but detection is on us — nothing will fail at composer update time.
  • Verify the matrix is real, not aspirational. "Laravel 10–13 on PHP 8.1–8.5" implies a cross-product that is unusual at the edges (Laravel 13's own PHP floor is not obviously compatible with 8.1). Confirm that composer.json constraints match what CI actually instantiates; a matrix listed in prose can be a summary of a narrower job list.
  • Forward-dated release metadata (2026-10-16) from the prior review remains unexplained. PHP 8.5 compatibility work implies a late-2025-or-later timeframe, so the date is either a tagging error or a registry anomaly — still worth a one-line check, still not a blocker.
  • Still unverified: license terms and internal-fork permission, presence of tests of the generator output (not just a passing CI badge), security advisory channel, and whether generation is compile-time or reflection/cached at boot — the latter being the precondition for Octane and config:cache safety.

Key questions for the diligence gate (revised).

  1. Does composer.json constrain Laravel/PHP to versions we run? Answered: Laravel 10–13, PHP 8.1–8.5. Action: confirm constraints match CI jobs exactly, and confirm our own Laravel/PHP target sits inside the matrix rather than on an untested edge.
  2. Are there tests and a CI matrix? Answered in the affirmative. Action: check whether CI asserts generated output correctness (fixture diffing) or only that the package's own suite passes — the former is what protects us.
  3. Is code generation compile-time (files committed to the repo) or runtime (reflection/caching)? Still open, still a precondition.
  4. Read the 1.x → 2.x changelog in full: what broke at the major, and is 2.0.2 the stable point or is 2.0.x still settling?
  5. Who is the maintainer of record, and is PR #12 evidence of an external contributor or internal housekeeping? Will scrumble-nl accept our patches?
  6. What is the license, and does it permit an internal hard fork?
  7. Does it handle enums, nullable/union types, nested DTOs, collections, and readonly properties?
  8. Does it integrate with validation, or does it assume already-validated input?
  9. Does our application (or any dependency) rely on Laravel global helpers that were only present transitively via popo?

Integration Approach

Stack fit. Best fit is a Laravel 10/11/12 application on PHP 8.2+ using typed properties or enums, with queue jobs and/or an internal API surface. Worst fit is a legacy app on PHP 7.4/8.0 with array-based conventions, or one already standardized on Spatie Laravel Data. 2.0.2's PHP 8.5 readiness extends the viable lifespan of the dependency by at least one PHP minor, which modestly improves the fit case for teams planning to stay on current PHP.

Migration path. Do not migrate. Introduce incrementally and only at new boundaries:

  1. Fork-and-vendor posture first. Despite improved maintenance signals, bus factor is still plausibly 1. Default to pinning an exact version, mirroring the repository internally, and treating it as a vendored component we are prepared to own. Budget ~1 engineer-week per year of ownership cost — unchanged.
  2. Wrap it. Expose the package behind a thin internal base class or interface (App\Data\Popo / DtoContract) so call sites reference our symbol, not theirs. This keeps swap-to-in-house a one-file change.
  3. Pilot in one bounded context — a single module with a clear inbound payload (e.g., a webhook receiver or one public API resource). Keep it out of shared domain code until the pilot ships.
  4. Only then publish an internal standard for DTO usage (naming, immutability, validation ownership, serialization) and expand.

Compatibility. Version constraints are now answered by the release notes; the remaining surface to verify explicitly: PHPUnit/Pest version for test generation, and static analysis (PHPStan/Larastan level) — generated classes must pass our current gate or they create noise that engineers suppress, which erodes the whole point. Also verify behavior under php artisan config:cache, route caching, and Laravel Octane.

New in 2.0.2 — the helper-clash pre-flight check. Before upgrading, run a repo-wide grep for global-helper usage (array_get, array_first, array_last, str_*, snake_case, camel_case, studly_case) and confirm each is either unused, provided by laravel/helpers directly, or replaced with Str::/Arr:: equivalents. This is a 30-minute check that prevents a production fatal on upgrade, and it is cheap enough to fold into the same PR that bumps the pin. Note the failure mode is asymmetric: it will not appear during composer update and may only surface on an untested code path.

Sequencing (2-week timebox, revised).

  • Days 1–2: repository audit against the remaining key questions (1.x→2.x changelog, generation model, license, tests-as-output-verification); record findings. Faster than before — roughly half the question list is now closed.
  • Day 2 (new): helper-clash grep and PHP 8.5 collision check across our codebase and our transitive dependencies.
  • Days 3–5: sandbox spike in a throwaway branch; generate DTOs for one real endpoint; run static analysis and the full test suite.
  • Week 2: pilot in one module behind the internal wrapper; measure boilerplate removed, review findings, and run a build-vs-adopt comparison against ~150 lines of an in-house readonly DTO base class.
  • End of week 2: decision gate — adopt as vendored dependency, fork, or write in-house. The evidence now tilts "adopt as vendored dependency" from coin-flip to modestly favored, because active PHP-version maintenance is the specific thing that most often kills small generator packages. "Write in-house" remains legitimate but is no longer the default expectation.

Operational Impact

Maintenance. Low runtime maintenance, moderate ownership maintenance — but the ownership burden is now demonstrably shared with an engaged upstream, which lowers it in practice. There is nothing to operate: no service, no daemon, no storage. The package remains part of the build (PHP and Laravel upgrades, static-analysis level bumps, generator output changes), so keep an explicit internal owner, an exact pin in composer.json ("x.y.z", not ^), and a quarterly review entry. 2.0.2 is also a reminder to read changelogs rather than trust the pin: the "no API changes" release did remove a dependency whose absence is breaking for some consumers.

Support. Still no commercial support, no SLA, no visible security advisory feed. Support path is: read the source (small codebase), patch our fork, upstream a PR. Escalation is internal. The release demonstrates the upstream loop functions — a collision with a new PHP minor was identified and fixed rather than left to rot — which is the behaviour we actually care about from a small maintainer. Acceptable for a dev-time code generator; still unacceptable for anything in the request path we cannot replace in a day.

Scaling. No runtime scaling characteristics, which remains a genuine advantage: generated classes add no request-time overhead beyond autoloading, and file count grows linearly with domain size. Removing laravel/helpers slightly improves cold-start and memory characteristics for very large apps by eliminating a package that eagerly defines global functions. The real scaling risk is cognitive — a generated DTO layer that is not consistently used becomes a third convention alongside arrays and Eloquent models. Mitigate with the published internal standard and a lint/review rule.

Failure modes to plan for.

  • Transitive-helper removal (new): upgrade to 2.0.2 breaks call sites that relied on helpers only popo provided. Mitigate with the pre-flight grep; document composer require laravel/helpers in the upgrade runbook.
  • Silent drift: schema changes, DTOs not regenerated — type errors surface at runtime. Mitigate by generating in CI and failing the build on diff.
  • Abandonment: reduced likelihood, not eliminated. Mitigate via fork + wrapper; detect via the quarterly review.
  • Convention fragmentation: half the team uses DTOs, half uses arrays. Mitigate by scoping the pilot and gating expansion on the standard.
  • Static analysis suppression: engineers add @phpstan-ignore to generated code, then to adjacent code. Mitigate by requiring generated output to pass at current level before adoption.
  • Supply-chain: forward-dated release metadata remains unexplained. Mitigate with exact pinning, lockfile review, and a Composer audit step in CI.

Ramp-up. Low and unchanged: an experienced Laravel dev is productive in half a day, and the concepts (typed objects at boundaries) are transferable if we later swap libraries. Cost is concentrated in the first two adopters, who must write the internal standard, the wrapper, and the upgrade runbook (which now includes the helper check). Do not spread adoption wider than one team until that documentation exists.

TPM recommendation. Fund the two-week evaluation, and raise the probability of adoption from roughly a coin flip to modestly favored. The case has genuinely improved: version constraints and CI are answered, the dependency footprint shrank, and upstream is demonstrably tracking PHP minor releases — the single strongest counter-signal to the abandonment thesis. The case has not been made, however, on the one thing that would justify platform-wide commitment: adoption breadth is still effectively zero, so we will be the ones discovering the enum, nullable-nested-DTO, and Octane behaviours. Proceed as vendored and wrapped, pin exactly, complete the now-shorter audit, and hold the in-house readonly DTO base class as the documented fallback.

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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast