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 Composite Key Laravel Package

mpociot/laravel-composite-key

Adds support for composite primary keys in Laravel Eloquent models. This package lets models with multi-column keys work with common Eloquent operations like saving, updating, deleting, and finding records, without hacking around the framework's single-key assumptions.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Schema strategy: surrogate key vs. natural/composite key. Eloquent's default assumption is one auto-incrementing id. The first PM decision is upstream of any code: for tables we control, do we mandate a surrogate id plus UNIQUE(order_id, line_no) — same integrity, zero friction with bindings, relations, caching, and third-party tooling — or do we accept tuple identity? This package only becomes a candidate after that call is made in favor of composite keys, and only for tables where the tuple is a fact of the data rather than a modeling choice.
  • Build vs. buy vs. fork. For a Laravel codebase that needs composite-key writes, the realistic options are (a) redesign the schema, (b) write a small in-house trait, (c) adopt this package, or (d) fork and vendor it. The honest benchmark is ~30 lines of trait code and roughly an engineer-week of in-house work plus tests — not a paid product. This package is only ever a (c)/(d) candidate, and (d) is the realistic entry point.
  • Integration roadmap for externally-owned data. ERPs, warehouse models, vendor APIs, and mirrored datasets routinely key rows by two or more columns. When a roadmap item depends on reading from or writing to such a system, composite-key handling is a hidden prerequisite task. Surfacing it at planning time instead of mid-sprint is a direct PM win — it converts a surprise into a scheduled line item.
  • Feature scope for pivot and join-table domains. Enrollments, permissions, order lines, translations, and tag mappings are naturally identified by a composite. Whether we can find()/save() such models cleanly determines whether we ship a full CRUD surface for them or settle for read-only reporting — a scoping decision that changes the shape of a sprint, not just the code.
  • API and URL contract decisions. Composite-key models cannot emit a scalar id or use implicit route model binding. That forces an explicit, greppable contract (nested routes like /orders/{orderId}/lines/{lineNo}, or a composed route key) and forbids 'id' => $model->getKey() in responses. This is a public-facing decision that should be settled before the first endpoint ships, not retrofitted.
  • Dependency risk register entry. 35 stars, zero dependents, single author, last release May 2016, MIT. That is a textbook "abandoned" profile. Classifying it as such — and deciding up front whether we adopt, fork, or reject — is a governance decision with a named owner. If we cannot name who owns the fork, we do not adopt.
  • Cache, queue, and observability keying. Anything that assumes a scalar key — cache()->remember($model->getKey(), …), session keys, queue payloads, log correlation IDs — misbehaves silently. Choosing an explicit composite cache key convention (e.g. order_line:{order_id}:{line_no}) is a small but load-bearing platform standard.

When to Consider This Package

Consider it when all of the following hold:

  • The schema is not yours to change — vendor-owned, legacy, or replicated tables where the composite primary key already exists in the database (confirmed via SHOW CREATE TABLE … PRIMARY KEY (a, b), not merely a unique index).
  • The composite identity is a fact, not a choice, and the model needs full CRUD (find, save, update, delete), not just reporting reads.
  • The blast radius is small and named: a handful of read-mostly models on one shared abstract base class. If the number of models using the trait is growing, that is the signal to stop and return to the schema conversation.
  • Those models sit at the leaf of the relationship graph — the "many" side of a hasMany whose foreign key is a single column. They must not be the parent of a hasMany, a belongsTo target, or a morphMany target.
  • Nothing in the stack touches models generically through a scalar key: admin panels, activity-log packages, auditing tools, Nova-style resource tooling, or polymorphic helpers that call $class::find($ids). Note that under this trait, find([1,2,3]) means "the tuple (1,2,3)", not "three records" — a genuine footgun in shared code.
  • The team can fork and own it: pin the version, vendor it into packages/, and back it with a canary test covering the four CRUD paths that runs on every Laravel/PHP upgrade.

Look elsewhere when any of these are true:

  • You control the schema. Add a surrogate id plus a unique composite index. Same integrity guarantees, no friction with binding, relations, caching, or third-party packages. This is the default answer and should be beaten deliberately, not skipped.
  • Procurement or security review requires a maintained dependency. A 2016 release with zero dependents will not pass, and should not be argued past. Plan around it from the start rather than discovering it at review.
  • You need composite-key joins across tables — that is a different problem, solved by awobaz/compoships. Do not stack the two packages.
  • You want ongoing upstream support. fico7489/laravel-composite-key is the more actively maintained package in this niche and should be benchmarked before committing. Choose one, pin it, and isolate it behind a single base model so the swap is one file.
  • You need elegant implicit route model binding, fresh()/refresh() guarantees, is() comparisons, or generic queue/cache keying. All of these are unproven or broken territory; the workarounds are explicit and must be budgeted.

How to Pitch It (Stakeholders)

For executives (one paragraph): This is a small, tactically useful enabler, not a strategic dependency. It lets our Laravel application read and write records in systems that identify rows by two or more columns — common in ERP, warehouse, and vendor-owned data — using the ORM's normal find/save/delete API instead of hand-written SQL for every touch point. The relevant decision is not "should we depend on this abandoned 2016 package" (we should not) but "should we fork roughly thirty lines of MIT-licensed code and own it," which is cheaper than building it ourselves and far cheaper than the schema change that vendors and legacy systems will not permit. We should approve it only for a narrow, named set of models, with a designated owner and an upgrade canary test, and we should prefer a surrogate key on every table we actually control.

For engineering: Treat it as vendored source you own, not a dependency that will fix itself. The entire package is a single trait; the one real failure mode is signature drift on setKeysForSaveQuery(), which fails either loudly (PHP fatal on incompatible declaration — fine) or silently (parent method wins and save() returns truthy while updating zero rows — dangerous). Guard that with a query-log assertion in CI. Non-negotiables on the model: $primaryKey is an array, $incrementing = false, $keyType set correctly, and the trait applied on a shared abstract base model so replacement is a one-file change. Prefer query-builder bulk operations and scoped where chains for read paths — they never touch getKeyName() and behave normally — and verify write paths explicitly rather than assuming updateOrCreate, fresh, or refresh work. Benchmark fico7489/laravel-composite-key and a plain surrogate-key redesign before we commit; both are credible and one of them is probably cheaper.

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