ardalanamini / laravel-custom-relation
Create your own custom relation for when stock relations aren't enough
Requires
- php: >=7.0.0
- laravel/framework: ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0
This package is not auto-updated.
Last update: 2024-11-09 21:42:41 UTC
README
Create your own custom relation for when stock relations aren't enough
[TOC]
Use this if...
- None of the stock Relations fit the bill. (BelongsToManyThrough, etc)
Installation
The recommended way to install is with composer:
composer require ardalanamini/laravel-custom-relation
Example
Let's say we have 3 models:
User
Role
Permission
Let's also say User
has a many-to-many relation with Role
, and Role
has a many-to-many relation with Permission
.
So their models might look something like this. (I kept them brief on purpose.)
class User { public function roles() { return $this->belongsToMany(Role::class); } }
class Role { public function users() { return $this->belongsToMany(User::class); } public function permissions() { return $this->belongsToMany(Permission::class); } }
class Permission { public function roles() { return $this->belongsToMany(Role::class); } }
What if you wanted to get all the Permission
s for a User
, or all the User
s with a particular Permission
? There no stock Relation in Laravel to descibe this. What we need is a BelongsToManyThrough
but no such thing exists in stock Laravel.
Solution
First, make sure your models are using the HasCustomRelations
trait. Then, define custom relations like this.
use LaravelCustomRelation\HasCustomRelations; class User { use HasCustomRelations; /** * Get the related permissions * * @return Illuminate\Database\Eloquent\Relations\Relation */ public function permissions() { return $this->custom( Permission::class, // add constraints function ($relation) { $relation->getQuery() // join the pivot table for permission and roles ->join('permission_role', 'permission_role.permission_id', '=', 'permissions.id') // join the pivot table for users and roles ->join('role_user', 'role_user.role_id', '=', 'permission_role.role_id') // for this user ->where('role_user.user_id', $this->id); }, // add eager constraints function ($relation, $models) { $relation->getQuery()->whereIn( 'role_user.user_id', collect($models)->map(function ($value) { return $value->getKey(); })->values()->unique()->sort()->all() ); } ); } }
use LaravelCustomRelation\HasCustomRelations; class Permission { use HasCustomRelations; /** * Get the related users * * @return Illuminate\Database\Eloquent\Relations\Relation */ public function users() { return $this->custom( User::class, // constraints function ($relation) { $relation->getQuery() // join the pivot table for users and roles ->join('role_user', 'role_user.user_id', '=', 'users.id') // join the pivot table for permission and roles ->join('permission_role', 'permission_role.role_id', '=', 'role_user.role_id') // for this permission ->where('permission_role.permission_id', $this->id); }, // eager constraints function ($relation, $models) { $relation->getQuery()->whereIn( 'permission_role.permission_id', collect($models)->map(function ($value) { return $value->getKey(); })->values()->unique()->sort()->all() ); } ); } }
You could now do all the normal stuff for relations without having to query in-between relations first.