fagundes / compoships
Laravel relationships with support for composite/multiple keys
Fund package maintenance!
paypal.me/awobaz
Requires
- illuminate/database: >=5.6 <12.0
Requires (Dev)
- ext-sqlite3: *
- fakerphp/faker: ^1.18
- phpunit/phpunit: ^6.0|^8.0|^9.0|^10.0
Suggests
- awobaz/blade-active: Blade directives for the Laravel 'Active' package
- awobaz/eloquent-auto-append: Automatically append accessors to model serialization
- awobaz/eloquent-mutators: Reusable mutators (getters/setters) for Laravel 5's Eloquent
- awobaz/syntactic: Syntactic sugar for named and indexed parameters call.
This package is auto-updated.
Last update: 2024-10-19 12:38:13 UTC
README
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
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->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:
- Relationship on multiple keys
- Querying relations with extra conditions not working as expected
- Querying relations with extra conditions in Eager Loading not working
- BelongsTo relationship with 2 foreign keys
- Laravel Eloquent: multiple foreign keys for relationship
- Laravel hasMany association with multiple columns
Installation
The recommended way to install Compoships is through Composer
$ composer require awobaz/compoships
Usage
Using the Awobaz\Compoships\Database\Eloquent\Model
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
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
... 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
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 ->has() method. Just use the
Awobaz\Compoships\Database\Eloquent\Factories\ComposhipsFactory
trait in your factory classes to be able
to use relationships correctly.
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
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
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
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
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests.
Versioning
We use SemVer for versioning. For the versions available, see the tags on this repository.
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
- Claudin J. Daniel - Initial work
Support This Project
License
Compoships is licensed under the MIT License.