Weave Code
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 Relations Laravel Package

reedware/laravel-composite-relations

View on GitHub
Deep Wiki
Context7

Laravel Composite Relations

Laravel Version Tests Lint Static Analysis Total Downloads

This package adds the ability to have multiple foreign keys in a relation.

Introduction

Eloquent does not natively support using composite keys in relationships. While single key relationships are typically preferred, there are times where they are unfortunately needed, and there's good way around it. This package offers a solution where you can use composite keys, and everything still feels like it's Eloquent.

This package will allow you to define the following composite relations:

  • Belongs To
  • Has One
  • Has Many

All composite relations support eager loading and existence queries (e.g. "where has").

There currently is no intention to add support for additional relations, as these should be enough for the vast majority of use cases.

Installation

Using Composer

composer require reedware/laravel-composite-relations

Versioning

This package is maintained with the latest version of Laravel in mind, but support follows Laravel's Support Policy.

Package Laravel PHP
5.x 11.x - 12.x 8.2 - 8.4+
4.x 10.x - 11.x 8.1 - 8.3+
3.x 8.x - 10.x 7.2 - 8.0+
2.x 6.x - 8.x 7.2 - 8.0+
1.x 5.5 - 5.8 7.1 - 7.3+

Code Changes

This package does not use a service provider or facade, but rather a trait. On your base model instance, you'll want to include the following:

use Illuminate\Database\Eloquent\Model as Eloquent;
use Reedware\LaravelCompositeRelations\HasCompositeRelations;

abstract class Model extends Eloquent
{
    use HasCompositeRelations;
}

Usage

1. Defining Relations

Composite Belongs To

Imagine you were defining a non-composite belongs to relation:

public function myRelation()
{
    return $this->belongsTo(MyRelated::class, 'my_column_on_this_table', 'my_column_on_the_other_table');
}

Since composite relations use multiple keys, you'll simply define the keys as an array:

public function myCompositeRelation()
{
    return $this->compositeBelongsTo(MyRelated::class, ['my_first_key', 'my_second_key'], ['their_first_key', 'their_second_key']);
}

Composite Has One

This follows the same structure as the composite belongs to relation:

public function myCompositeRelation()
{
    return $this->compositeHasOne(MyRelated::class, ['their_first_key', 'their_second_key'], ['my_first_key', 'my_second_key']);
}

Composite Has Many

The pattern continues:

public function myCompositeRelation()
{
    return $this->compositeHasMany(MyRelated::class, ['foreign_1', 'foreign_2'], ['local_1', 'local_2']);
}

2. Omitting Foreign and Local Keys

With non-composite relationships, you aren't actually required to provide the foreign and local key, assuming you follow a certain convention. This functionality is also available for composite relations, but must be defined differently. Here's how:

class Task extends Models
{
    /**
     * The primary keys for the model.
     *
     * @var array
     */
    protected $primaryKeys = ['vendor_id', 'vendor_name'];

    public function importSummary()
    {
        return $this->compositeHasOne(TaskImportSummary::class);
    }
}

class TaskImportSummary extends Models
{
    public function task()
    {
        return $this->compositeBelongsTo(TaskImportSummary::class);
    }
}

3. Joining through Composite Relations

This package is compatible with reedware/laravel-relation-joins, meaning you can join through composite relations just like anything else:

$task->joinRelation('importSummary', function($join) {
    $join->where('task_import_summaries.name', 'like', '%Relation joins are cool!%');
});

You must separately include reedware/laravel-relation-joins for this to work.

4. Using composite and glue

The default glue between composite keys is 'or'. Meaning your query will be like:

where (("foreign_1" = ? or "foreign_2" = ?) or ("foreign_1" = ? or "foreign_2" = ?))

You can change that by passing 'and' for the glue parameter:

public function myCompositeBelongsToRelation()
{
    return $this->compositeBelongsTo(MyRelated::class, ['local_1', 'local_2'], ['foreign_1', 'foreign_2'], null, 'and');
}

public function myCompositeHasOneRelation()
{
    return $this->compositeHasOne(MyRelated::class, ['foreign_1', 'foreign_2'], ['local_1', 'local_2'], 'and');
}

public function myCompositeHasManyRelation()
{
    return $this->compositeHasMany(MyRelated::class, ['foreign_1', 'foreign_2'], ['local_1', 'local_2'], 'and');
}

Giving this result :

where (("foreign_1" = ? and "foreign_2" = ?) or ("foreign_1" = ? and "foreign_2" = ?))
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.
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon
itsemon245/lamet
baks-dev/dashboard
amoifr/pickle-panther-bundle
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle