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

Plug Laravel Package

znck/plug

A collection of pluggable Eloquent traits for Laravel models, adding features like BelongsToThrough, UUID keys, and fixes for belongsTo/morphTo relations. Just use a trait and it boots automatically—no config needed.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

znck/plug is a thin layer of Eloquent traits — no service provider, no config, no migrations, no facade. That is about as low-ceremony as a PHP dependency gets, and it fits our architecture in the narrow sense: if we are on Eloquent, use SomeTrait; on a model is a pattern we already use.

The fit degrades on inspection, though. Traits are a class-level composition mechanism: once applied, behavior is bound to the model for all call sites, cannot be swapped per-request, and collides badly when two traits touch the same lifecycle hook (saving, creating, getAttribute, setAttribute). For a package whose entire value proposition is "many small traits you can mix in," the composition model is the risk model.

Integration feasibility

Technically high, practically low.

  • Package targets PHP 7.0+ and Laravel 5.x-era illuminate/* constraints. On a modern Laravel/PHP stack, composer require will most likely fail resolution outright.
  • Getting past that requires a fork, widened constraints, and re-validation of every trait against current Eloquent internals — at which point we have forked an abandoned package to gain a few dozen lines of code.
  • The source is small and readable, which cuts both ways: cheap to audit, and cheap enough that vendoring or reimplementing is a realistic alternative.

Technical risk

Risk Severity Note
Abandonment High Last release 2016-09-27; no commits path to modern Laravel
Single-maintainer / bus factor High No triage, no disclosure channel, no CVE process
Zero adoption signal High 13 stars, 0 dependents — no field testing, no Stack Overflow corpus
Dead CI evidence Medium StyleCI / CircleCI / Coveralls badges; CircleCI 1.0 was retired in 2018, so the "green build" is not a live signal
Lifecycle-hook conflicts Medium Traits that hook saving/creating interact with observers, soft deletes, and event ordering
Event bypass Medium insert()/upsert()/query-builder writes skip model events entirely, producing inconsistent rows
Security exposure Low–Medium MIT, no network surface, but unpatched dependencies are a hygiene flag at audit time

Recommendation (TPM position): Do not adopt znck/plug as a runtime Composer dependency. Treat it as a reference implementation. Vendor the specific traits we need into our own namespace under our own test coverage, or reimplement them outright.

Key questions to close before committing engineering time

  1. Which capabilities do we actually need, enumerated by behavior rather than by package trait name?
  2. Does Laravel core or our existing base model already cover any of them?
  3. What Laravel/PHP version matrix must we support over the next 24 months?
  4. Estimated LOC for a faithful reimplementation of the needed subset — is it under ~200 lines? (If yes, reimplementing wins on total cost of ownership.)
  5. Who is the named owner of the vendored code, and where is the ADR recording this decision?
  6. Any data-model impact (new columns for slugs/UUIDs) that forces a migration and backfill?

Integration Approach

Stack fit

Eloquent-only, framework-version-coupled through illuminate/* constraints. No infrastructure footprint: no queue, no cache dependency, no external service. That makes it easy to evaluate in isolation and easy to rip out — the main reason this is a low-blast-radius decision rather than a strategic one.

Migration path — three options, ranked

  • A. Cherry-pick (recommended). Copy required trait source into app/Support/Eloquent/Concerns/, re-namespace, retain the MIT header, add unit + integration tests. Behavior becomes ours, visible, covered.
  • B. Internal fork. Fork to our VCS, widen composer.json constraints, tag an internal version, require via repositories VCS entry. Only justified if we need a large subset and expect upstream movement — and there has been none in ~8 years, so upstream-sync value is effectively zero.
  • C. Reimplement. For a slug generator, a UUID primary key, or a sortable column, this is typically 30–80 lines. Often cheaper than A once you account for renaming, dead-code removal, and adapting to current APIs.

Default to A, fall back to C per trait where the original is doing something we would not write today.

Compatibility checks per trait

  • Trait boot hooks (boot{TraitName}) — confirm they still fire and in what order relative to other traits.
  • Overrides of getAttribute / setAttribute / casts — these internals have shifted across Laravel majors.
  • Deprecated global helpers (array_get, str_*) removed in later Laravel versions.
  • $fillable / mass-assignment interaction if the trait sets attributes.
  • Interaction with SoftDeletes, observers, and Model::withoutEvents().
  • Bulk-write paths that bypass events entirely.

Sequencing

  1. Capability inventory — list needed behaviors; mark each as already covered, vendor, or reimplement. This is a half-day task and gates everything else.
  2. Spike — port one representative trait on the current Laravel version; run against the full DB test matrix (e.g., MySQL + SQLite).
  3. Test harness — factories, event assertions, and a regression test that fails if a trait silently stops applying (assert the slug/UUID is actually present post-save).
  4. Bulk-path audit — confirm seeder/import code paths that use insert() are handled explicitly.
  5. Ship as additive minor release. If a column is required: add nullable column → backfill job → add non-null constraint → enforce in code. Never combine schema change and behavior change in one deploy.
  6. Record the ADR so a future engineer does not re-litigate composer require znck/plug.

Operational Impact

Maintenance

Upstream maintenance is zero and will remain zero. The real question is only where the maintenance burden sits: behind a composer.json line (invisible, surprises us at upgrade time) or in our own repo (visible, owned, testable). Vendoring makes the cost legible; a dependency hides it.

Budget ~0.5–2 engineer-days for the initial port, test coverage, and ADR; then a few hours per Laravel major to re-validate.

Support

No maintainer SLA, no issue triage, no security contact, single contributor. We are the support organization for anything we ship that depends on this code. That is acceptable for vendored traits we own; it is not acceptable for a black-box dependency.

Scaling

Runtime overhead is whatever the trait's own logic costs — traits themselves add none. The scaling risk is in the logic:

  • Traits that enforce uniqueness (e.g., slugs) with a SELECT per save become write-path N+1s and, under concurrency, a read-modify-write race. At high insert volume this is a contention and duplicate-data problem, not a performance problem.
  • Traits that hook saving and perform I/O lengthen transaction hold times.
  • UUID primary keys trade sequential-insert locality for distribution — fine for most workloads, worth flagging for high-write tables on InnoDB.

Benchmark any trait that issues a query during save before it lands on a hot model.

Failure modes

Mode Detection Impact
Composer resolution failure on Laravel upgrade CI, immediately Build break — loud, cheap
Silent behavior drift post-upgrade (hook no longer fires) Only with explicit assertions Bad data: rows missing slug/UUID — quiet, expensive
Event-order conflict with observers / soft deletes Integration test Inconsistent lifecycle behavior
Bulk insert/upsert bypasses trait logic Seeder/import test Heterogeneous rows, downstream null-key bugs
$fillable / mass-assignment collision Feature test Unexpected overwrites
Trait method-name collision across models Static analysis / review Fatal at class load

The asymmetry matters: build failures are harmless, silent drift is not. That argues for assertion-style tests ("after save, the row has a slug") rather than mocking the trait.

Ramp-up

Near zero for any engineer fluent in Eloquent — traits are a familiar idiom and the source is short enough to read in full. The actual ramp-up cost is organizational: engineers must be told the package is vendored and deliberately not a dependency, or someone will "helpfully" add it back. That is what the ADR and the namespace choice (App\Support\Eloquent\Concerns) are for.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings