PHPackages                             awobaz/compoships - 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. [Database &amp; ORM](/categories/database)
4. /
5. awobaz/compoships

ActiveLibrary[Database &amp; ORM](/categories/database)

awobaz/compoships
=================

Laravel relationships with support for composite/multiple keys

2.5.5(2mo ago)1.2k10.6M—0.9%141[16 issues](https://github.com/topclaudy/compoships/issues)[6 PRs](https://github.com/topclaudy/compoships/pulls)20MITPHPCI failing

Since Apr 4Pushed 2mo ago14 watchersCompare

[ Source](https://github.com/topclaudy/compoships)[ Packagist](https://packagist.org/packages/awobaz/compoships)[ Fund](https://paypal.me/awobaz)[ RSS](/packages/awobaz-compoships/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (6)Dependencies (6)Versions (54)Used By (20)

Compoships
==========

[](#compoships)

**Compoships** offers the ability to specify relationships based on two (or more) columns in Laravel's Eloquent ORM. The need to match multiple columns in the definition of an Eloquent relationship often arises when working with third party or pre existing schema/database.

The problem
-----------

[](#the-problem)

Eloquent doesn't support composite keys. As a consequence, there is no way to define a relationship from one model to another by matching more than one column. Trying to use `where clauses` (like in the example below) won't work when eager loading the relationship because at the time the relationship is processed **$this-&gt;team\_id** is null.

```
namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    public function tasks()
    {
        //WON'T WORK WITH EAGER LOADING!!!
        return $this->hasMany(Task::class)->where('team_id', $this->team_id);
    }
}
```

#### Related discussions:

[](#related-discussions)

- [Relationship on multiple keys](https://laracasts.com/discuss/channels/eloquent/relationship-on-multiple-keys)
- [Querying relations with extra conditions not working as expected](https://github.com/laravel/framework/issues/1272)
- [Querying relations with extra conditions in Eager Loading not working](https://github.com/laravel/framework/issues/19488)
- [BelongsTo relationship with 2 foreign keys](https://laravel.io/forum/08-02-2014-belongsto-relationship-with-2-foreign-keys)
- [Laravel Eloquent: multiple foreign keys for relationship](https://stackoverflow.com/questions/48077890/laravel-eloquent-multiple-foreign-keys-for-relationship/49834070#49834070)
- [Laravel hasMany association with multiple columns](https://stackoverflow.com/questions/32471084/laravel-hasmany-association-with-multiple-columns)

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

[](#installation)

The recommended way to install **Compoships** is through [Composer](http://getcomposer.org/)

```
$ composer require awobaz/compoships
```

Usage
-----

[](#usage)

### Using the `Awobaz\Compoships\Database\Eloquent\Model` class

[](#using-the-awobazcomposhipsdatabaseeloquentmodel-class)

Simply make your model class derive from the `Awobaz\Compoships\Database\Eloquent\Model` base class. The `Awobaz\Compoships\Database\Eloquent\Model` extends the `Eloquent` base class without changing its core functionality.

### Using the `Awobaz\Compoships\Compoships` trait

[](#using-the-awobazcomposhipscompoships-trait)

If for some reason you can't derive your models from `Awobaz\Compoships\Database\Eloquent\Model`, you may take advantage of the `Awobaz\Compoships\Compoships` trait. Simply use the trait in your models.

**Note:** To define a multi-columns relationship from a model *A* to another model *B*, **both models must either extend `Awobaz\Compoships\Database\Eloquent\Model` or use the `Awobaz\Compoships\Compoships` trait**

### Syntax

[](#syntax)

... and now we can define a relationship from a model *A* to another model *B* by matching two or more columns (by passing an array of columns instead of a string).

```
namespace App;

use Illuminate\Database\Eloquent\Model;

class A extends Model
{
    use \Awobaz\Compoships\Compoships;

    public function b()
    {
        return $this->hasMany('B', ['foreignKey1', 'foreignKey2'], ['localKey1', 'localKey2']);
    }
}
```

We can use the same syntax to define the inverse of the relationship:

```
namespace App;

use Illuminate\Database\Eloquent\Model;

class B extends Model
{
    use \Awobaz\Compoships\Compoships;

    public function a()
    {
        return $this->belongsTo('A', ['foreignKey1', 'foreignKey2'], ['ownerKey1', 'ownerKey2']);
    }
}
```

### Factories

[](#factories)

Chances are that you may need factories for your Compoships models. If so, you will probably need to use Factory methods to create relationship models. For example, by using the -&gt;has() method. Just use the `Awobaz\Compoships\Database\Eloquent\Factories\ComposhipsFactory` trait in your factory classes to be able to use relationships correctly.

### Example

[](#example)

As an example, let's pretend we have a task list with categories, managed by several teams of users where:

- a task belongs to a category
- a task is assigned to a team
- a team has many users
- a user belongs to one team
- a user is responsible for one category of tasks

The user responsible for a particular task is the user *currently* in charge for the category inside the team.

```
namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    use \Awobaz\Compoships\Compoships;

    public function tasks()
    {
        return $this->hasMany(Task::class, ['team_id', 'category_id'], ['team_id', 'category_id']);
    }
}
```

Again, same syntax to define the inverse of the relationship:

```
namespace App;

use Illuminate\Database\Eloquent\Model;

class Task extends Model
{
    use \Awobaz\Compoships\Compoships;

    public function user()
    {
        return $this->belongsTo(User::class, ['team_id', 'category_id'], ['team_id', 'category_id']);
    }
}
```

Supported relationships
-----------------------

[](#supported-relationships)

**Compoships** only supports the following Laravel's Eloquent relationships:

- hasOne
- HasMany
- belongsTo

Also please note that while **nullable columns are supported by Compoships**, relationships with only null values are not currently possible.

Support for nullable columns in 2.x
-----------------------------------

[](#support-for-nullable-columns-in-2x)

Version 2.x brings support for nullable columns. The results may now be different than on version 1.x when a column is null on a relationship, so we bumped the version to 2.x, as this might be a breaking change.

Disclaimer
----------

[](#disclaimer)

**Compoships** doesn't bring support for composite keys in Laravel's Eloquent. This package only offers the ability to specify relationships based on more than one column. In a Laravel project, it's recommended for all models' tables to have a single primary key. But there are situations where you'll need to match many columns in the definition of a relationship even when your models' tables have a single primary key.

Contributing
------------

[](#contributing)

Please read [CONTRIBUTING.md](https://github.com/topclaudy/compoships/blob/master/CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests.

[![](https://camo.githubusercontent.com/3170920f099804f92e9cdc9fe54f73add9e529e334ab959f8c1b99020392996e/68747470733a2f2f736f757263657265722e696f2f66616d652f746f70636c617564792f746f70636c617564792f636f6d706f73686970732f696d616765732f30)](https://sourcerer.io/fame/topclaudy/topclaudy/compoships/links/0)[![](https://camo.githubusercontent.com/1ddc7163b26f6c714e4395ea35ff3ecc34bd2077cb23bedf2999efe31ad9be35/68747470733a2f2f736f757263657265722e696f2f66616d652f746f70636c617564792f746f70636c617564792f636f6d706f73686970732f696d616765732f31)](https://sourcerer.io/fame/topclaudy/topclaudy/compoships/links/1)[![](https://camo.githubusercontent.com/b5e66a4b32c7b4e53706897ac21635902eb9ddd2de0fddd64608080f1c15d578/68747470733a2f2f736f757263657265722e696f2f66616d652f746f70636c617564792f746f70636c617564792f636f6d706f73686970732f696d616765732f32)](https://sourcerer.io/fame/topclaudy/topclaudy/compoships/links/2)[![](https://camo.githubusercontent.com/fccbbcccdfc98e00baa58eaf0b1178ed25a9471576de48d25f6b926bfc9bc02c/68747470733a2f2f736f757263657265722e696f2f66616d652f746f70636c617564792f746f70636c617564792f636f6d706f73686970732f696d616765732f33)](https://sourcerer.io/fame/topclaudy/topclaudy/compoships/links/3)[![](https://camo.githubusercontent.com/e0e7d39c8486044702bb78ad3b9f443cfda7c1d0417e59ab69d4aad37bcc7ac6/68747470733a2f2f736f757263657265722e696f2f66616d652f746f70636c617564792f746f70636c617564792f636f6d706f73686970732f696d616765732f34)](https://sourcerer.io/fame/topclaudy/topclaudy/compoships/links/4)[![](https://camo.githubusercontent.com/e5eb643768cdf5532c81a834b77e6b96241c6dedc5c4449adac01e4d9a089c65/68747470733a2f2f736f757263657265722e696f2f66616d652f746f70636c617564792f746f70636c617564792f636f6d706f73686970732f696d616765732f35)](https://sourcerer.io/fame/topclaudy/topclaudy/compoships/links/5)[![](https://camo.githubusercontent.com/c6d275bb8cf53c5aef6bc6dbaab4d12be3f8ded8d1c5f1c589b43460e1797218/68747470733a2f2f736f757263657265722e696f2f66616d652f746f70636c617564792f746f70636c617564792f636f6d706f73686970732f696d616765732f36)](https://sourcerer.io/fame/topclaudy/topclaudy/compoships/links/6)

Versioning
----------

[](#versioning)

We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/topclaudy/compoships/tags).

Unit Tests
----------

[](#unit-tests)

To run unit tests you have to use PHPUnit

Install compoships repository

```
git clone https://github.com/topclaudy/compoships.git
cd compoships
composer install
```

Run PHPUnit

```
./vendor/bin/phpunit
```

Authors
-------

[](#authors)

- [Claudin J. Daniel](https://github.com/topclaudy) - *Initial work*

Support This Project
--------------------

[](#support-this-project)

[![Buy Me a Coffee via Paypal](https://camo.githubusercontent.com/7f803b4c3a634f4d451c4310d00c2520aae1f15ef910420a0f27890e3c4787dd/68747470733a2f2f617a3734333730322e766f2e6d7365636e642e6e65742f63646e2f6b6f6669332e706e673f763d30)](https://paypal.me/awobaz)

License
-------

[](#license)

**Compoships** is licensed under the [MIT License](http://opensource.org/licenses/MIT).

###  Health Score

73

—

ExcellentBetter than 100% of packages

Maintenance86

Actively maintained with recent releases

Popularity71

Solid adoption and visibility

Community45

Growing community involvement

Maturity77

Established project with proven stability

 Bus Factor1

Top contributor holds 52.3% 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 ~55 days

Recently: every ~38 days

Total

53

Last Release

68d ago

Major Versions

1.1.18 → 2.0.02020-05-14

PHP version history (2 changes)1.0.0PHP &gt;=7

1.0.5PHP &gt;=5.6.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1437237?v=4)[Claudin J. Daniel](/maintainers/topclaudy)[@topclaudy](https://github.com/topclaudy)

---

Top Contributors

[![topclaudy](https://avatars.githubusercontent.com/u/1437237?v=4)](https://github.com/topclaudy "topclaudy (137 commits)")[![erikn69](https://avatars.githubusercontent.com/u/4933954?v=4)](https://github.com/erikn69 "erikn69 (21 commits)")[![parkourben99](https://avatars.githubusercontent.com/u/7295774?v=4)](https://github.com/parkourben99 "parkourben99 (16 commits)")[![yurii-github](https://avatars.githubusercontent.com/u/1162656?v=4)](https://github.com/yurii-github "yurii-github (13 commits)")[![mpyw](https://avatars.githubusercontent.com/u/1351893?v=4)](https://github.com/mpyw "mpyw (12 commits)")[![isclopezm](https://avatars.githubusercontent.com/u/14881514?v=4)](https://github.com/isclopezm "isclopezm (8 commits)")[![ChristopheB](https://avatars.githubusercontent.com/u/5377792?v=4)](https://github.com/ChristopheB "ChristopheB (7 commits)")[![SlyDave](https://avatars.githubusercontent.com/u/1842611?v=4)](https://github.com/SlyDave "SlyDave (5 commits)")[![jayjfletcher](https://avatars.githubusercontent.com/u/5743488?v=4)](https://github.com/jayjfletcher "jayjfletcher (5 commits)")[![didac-adria](https://avatars.githubusercontent.com/u/63950600?v=4)](https://github.com/didac-adria "didac-adria (4 commits)")[![chrispappas](https://avatars.githubusercontent.com/u/4694803?v=4)](https://github.com/chrispappas "chrispappas (4 commits)")[![SavKS](https://avatars.githubusercontent.com/u/1731510?v=4)](https://github.com/SavKS "SavKS (4 commits)")[![fmangelsdorf](https://avatars.githubusercontent.com/u/24457087?v=4)](https://github.com/fmangelsdorf "fmangelsdorf (3 commits)")[![hackel](https://avatars.githubusercontent.com/u/583677?v=4)](https://github.com/hackel "hackel (3 commits)")[![leo108](https://avatars.githubusercontent.com/u/1551716?v=4)](https://github.com/leo108 "leo108 (2 commits)")[![KentarouTakeda](https://avatars.githubusercontent.com/u/4785040?v=4)](https://github.com/KentarouTakeda "KentarouTakeda (2 commits)")[![pedrofmj](https://avatars.githubusercontent.com/u/935566?v=4)](https://github.com/pedrofmj "pedrofmj (2 commits)")[![wojo1206](https://avatars.githubusercontent.com/u/8170483?v=4)](https://github.com/wojo1206 "wojo1206 (2 commits)")[![axelitus](https://avatars.githubusercontent.com/u/732441?v=4)](https://github.com/axelitus "axelitus (1 commits)")[![jpscharf](https://avatars.githubusercontent.com/u/1039984?v=4)](https://github.com/jpscharf "jpscharf (1 commits)")

---

Tags

composite-keyseloquentlaravelmulti-columnsmulti-keysrelationshipslaravellaravel composite keyslaravel relationships

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/awobaz-compoships/health.svg)

```
[![Health](https://phpackages.com/badges/awobaz-compoships/health.svg)](https://phpackages.com/packages/awobaz-compoships)
```

###  Alternatives

[silber/bouncer

Eloquent roles and abilities.

3.6k4.4M25](/packages/silber-bouncer)[cybercog/laravel-love

Make Laravel Eloquent models reactable with any type of emotions in a minutes!

1.2k302.7k1](/packages/cybercog-laravel-love)[cviebrock/eloquent-taggable

Easy ability to tag your Eloquent models in Laravel.

567694.8k3](/packages/cviebrock-eloquent-taggable)[clickbar/laravel-magellan

This package provides functionality for working with the postgis extension in Laravel.

423715.4k1](/packages/clickbar-laravel-magellan)[reedware/laravel-relation-joins

Adds the ability to join on a relationship by name.

2121.2M13](/packages/reedware-laravel-relation-joins)[guidocella/eloquent-populator

Guess attributes for Eloquent model factories

7661.6k2](/packages/guidocella-eloquent-populator)

PHPackages © 2026

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