PHPackages                             pfrug/composite-key - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. pfrug/composite-key

ActiveLibrary

pfrug/composite-key
===================

Support for composite primary keys in Laravel Eloquent models.

v2.0.0(8mo ago)1132↓50%MITPHPPHP ^8.2

Since Jun 3Pushed 6mo ago1 watchersCompare

[ Source](https://github.com/pfrug/composite-key)[ Packagist](https://packagist.org/packages/pfrug/composite-key)[ RSS](/packages/pfrug-composite-key/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (2)Versions (4)Used By (0)

Laravel Composite Key Support
=============================

[](#laravel-composite-key-support)

`pfrug/composite-key` provides support for composite primary keys in Eloquent models.

Laravel does not natively support composite primary keys, as mentioned in the official documentation:

This package offers a lightweight and flexible solution to enable composite key support for:

- `find()` and `findOrFail()` methods
- `save()` and `delete()` operations
- Basic Eloquent relationships:
    - `hasManyComposite()`
    - `belongsToComposite()`

Installation
------------

[](#installation)

Install via Composer:

```
composer require pfrug/composite-key
```

Usage
-----

[](#usage)

### Model Setup

[](#model-setup)

```
use Pfrug\CompositeKey\Traits\HasCompositeKey;
use Illuminate\Database\Eloquent\Model;

class ShipmentHeader extends Model
{
    use HasCompositeKey;

    protected $compositeKey = ['company_code', 'shipment_number'];
}
```

### Finding Records

[](#finding-records)

```
ShipmentHeader::find(['COMP001', 'SHIP123']);
ShipmentHeader::findOrFail(['COMP001', 'SHIP123']);
```

Relationships
-------------

[](#relationships)

### hasManyComposite

[](#hasmanycomposite)

```
$this->hasManyComposite(
    RelatedModel::class,
    ['foreign_key_1', 'foreign_key_2'],
    ['local_key_1', 'local_key_2']
);
```

### belongsToComposite

[](#belongstocomposite)

```
$this->belongsToComposite(
    RelatedModel::class,
    ['foreign_key_1', 'foreign_key_2'],
    ['owner_key_1', 'owner_key_2']
);
```

Route Model Binding
-------------------

[](#route-model-binding)

### HasCompositeRouteKey

[](#hascompositeroutekey)

For models that need to be resolved from route parameters, use the `HasCompositeRouteKey` trait:

```
use Pfrug\CompositeKey\Traits\HasCompositeKey;
use Pfrug\CompositeKey\Traits\HasCompositeRouteKey;
use Illuminate\Database\Eloquent\Model;

class ShipmentHeader extends Model
{
    use HasCompositeKey, HasCompositeRouteKey;

    protected $compositeKey = ['company_code', 'shipment_number'];
}
```

This trait overrides `getRouteKey()` and `resolveRouteBinding()` for composite key support in route parameters.

It enables route model binding for composite keys by:

- **Encoding composite keys**: Converts composite key values to URL-safe strings using `:` as separator
- **Decoding route parameters**: Resolves models from encoded composite key strings in URLs

### Usage in Routes

[](#usage-in-routes)

```
// Route definition
Route::get('/shipments/{shipment}', function (ShipmentHeader $shipment) {
    return $shipment;
});

// URL: /shipments/COMP001:SHIP123
// Resolves to: ShipmentHeader::find(['COMP001', 'SHIP123'])
```

The route key format uses `:` as separator between composite key parts:

- `company_code:shipment_number`
- Example: `COMP001:SHIP123`

**Note**: When generating URLs with Laravel's `route()` helper, use the model instance to get the properly formatted composite key:

```
$shipment = ShipmentHeader::find(['COMP001', 'SHIP123']);
$url = route('shipments.show', $shipment); // Generates: /shipments/COMP001:SHIP123
```

Example: Composite Relationships in Practice
--------------------------------------------

[](#example-composite-relationships-in-practice)

### Student.php

[](#studentphp)

```
class Student extends Model
{
    public function enrollments()
    {
        return $this->hasMany(Enrollment::class, 'student_id');
    }
}
```

### Course.php

[](#coursephp)

```
class Course extends Model
{
    public function enrollments()
    {
        return $this->hasMany(Enrollment::class, 'course_id');
    }
}
```

### Enrollment.php

[](#enrollmentphp)

```
use Pfrug\CompositeKey\Models\CompositeModel;

class Enrollment extends CompositeModel
{
    protected $compositeKey = ['student_id', 'course_id'];

    public function student()
    {
        return $this->belongsTo(Student::class, 'student_id');
    }

    public function course()
    {
        return $this->belongsTo(Course::class, 'course_id');
    }

    public function grades()
    {
        return $this->hasManyComposite(
            Grade::class,
            ['student_id', 'course_id'],
            ['student_id', 'course_id']
        );
    }
}
```

### Grade.php

[](#gradephp)

```
use Pfrug\CompositeKey\Models\CompositeModel;

class Grade extends CompositeModel
{
    protected $compositeKey = ['student_id', 'course_id'];

    public function enrollment()
    {
        return $this->belongsToComposite(
            Enrollment::class,
            ['student_id', 'course_id'],
            ['student_id', 'course_id']
        );
    }
}
```

### Sample Usage

[](#sample-usage)

```
// Retrieve record with composite key
$enrollment = Enrollment::find([1, 1]);

// Update record
$enrollment->grade = 'B+';
$enrollment->save();

// Access belongsTo relation
echo $enrollment->student->name;

// Access hasManyComposite relation
foreach ($enrollment->grades as $grade) {
    echo $grade->value;
}

// Access belongsToComposite relation from Grade
$grade = Grade::first();
echo $grade->enrollment->course_id;
```

Eager Loading with Composite Keys
---------------------------------

[](#eager-loading-with-composite-keys)

Composite relationships defined with `hasManyComposite` and `belongsToComposite` fully support eager loading via `with()` or `load()`.

### Example

[](#example)

```
use App\Models\Course;
use App\Models\Grade;

// 1) Eager-load enrollments and grades when retrieving courses
$courses = Course::with(['enrollments.grades'])->get();

foreach ($courses as $course) {
    foreach ($course->enrollments as $enrollment) {
        foreach ($enrollment->grades as $grade) {
            echo $grade->value;
        }
    }
}

// 2) Eager-load course and student when retrieving grades
$grades = Grade::with(['enrollment.course', 'enrollment.student'])->get();

foreach ($grades as $grade) {
    echo $grade->enrollment->course->name;
    echo $grade->enrollment->student->name;
}
```

Compatibility
-------------

[](#compatibility)

- Laravel 10+
- PHP 8.2+

License
-------

[](#license)

This package is open-sourced software licensed under the [MIT license](LICENSE).

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance65

Regular maintenance activity

Popularity14

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~97 days

Total

2

Last Release

251d ago

Major Versions

v1.0.0 → v2.0.02025-09-09

### Community

Maintainers

![](https://www.gravatar.com/avatar/bdea59e3f90698df3c5fa81e8b9f40e0444a32a1bc99270314ef976a90735e70?d=identicon)[frugone](/maintainers/frugone)

---

Top Contributors

[![pfrug](https://avatars.githubusercontent.com/u/5391920?v=4)](https://github.com/pfrug "pfrug (18 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/pfrug-composite-key/health.svg)

```
[![Health](https://phpackages.com/badges/pfrug-composite-key/health.svg)](https://phpackages.com/packages/pfrug-composite-key)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
