kitloong/eloquent-power-joins-with-compoships
composer require kitloong/eloquent-power-joins-with-compoships
PowerJoins and Compoships traits:
use Awobaz\Compoships\Compoships;
use Kirschbaum\PowerJoins\PowerJoins;
class User extends Model
{
use PowerJoins, Compoships;
}
hasMany):
public function posts()
{
return $this->hasMany(
Post::class,
['team_id', 'category_id'], // Foreign keys
['team_id', 'category_id'] // Local keys
);
}
joinRelationship() to execute a join query:
$usersWithPosts = User::joinRelationship('posts')->get();
Query Construction:
joinRelationship() to join tables with composite keys seamlessly:
User::joinRelationship('posts')->where('posts.title', 'like', '%test%')->get();
where, select, with).Composite Key Handling:
$this->belongsToMany(
Role::class,
'user_roles',
['user_id', 'department_id'], // Foreign keys
['user_id', 'department_id'] // Local keys
);
ON clause in SQL.Eager Loading with Joins:
joinRelationship() with with() for optimized queries:
User::with(['posts' => function ($query) {
$query->joinRelationship('comments'); // Nested joins
}])->get();
Dynamic Joins:
join() with composite keys manually if needed:
User::join('posts', ['users.team_id', 'users.category_id'], ['posts.team_id', 'posts.category_id'])
->select('users.*', 'posts.title')
->get();
joinRelationship() to fetch joined data in a single query, reducing N+1 issues:
return User::joinRelationship('posts')->get()->map(function ($user) {
return [
'name' => $user->name,
'posts' => $user->posts,
];
});
morphTo/morphWith):
public function comments()
{
return $this->morphToMany(
Comment::class,
'commentable',
'commentables',
['user_id', 'scope_id'], // Composite foreign keys
['user_id', 'scope_id'] // Composite local keys
);
}
class UserQueryBuilder extends Builder
{
public function scopeWithTeamPosts($query)
{
return $query->joinRelationship('posts')->where('posts.team_id', auth()->user()->team_id);
}
}
Register the scope in your User model’s boot() method.Key Mismatch Errors:
hasMany, belongsTo, or belongsToMany:
// Wrong: Keys are swapped or misaligned
$this->hasMany(Post::class, ['category_id', 'team_id'], ['team_id', 'category_id']);
dd($this->posts->getQuery()->toSql()) to inspect the generated SQL.Composite Key Ambiguity:
team_id exists in both users and posts).User::joinRelationship('posts')
->select('users.*', 'posts.title as post_title')
->get();
Performance with Large Datasets:
select() to limit columns:
User::joinRelationship('posts')->select('users.id', 'users.name', 'posts.title')->get();
whereIn or whereExists for filtering.Caching Quirks:
fresh():
User::joinRelationship('posts')->fresh()->get();
toSql() and getBindings() to verify queries:
$query = User::joinRelationship('posts');
dd($query->toSql(), $query->getBindings());
// Test with one key, then add the second
$this->hasMany(Post::class, ['team_id'], ['team_id']);
PowerJoins or Compoships traits.Custom Join Logic:
joinRelationship method in your model to add pre/post-processing:
public function scopeCustomJoin($query, $relation)
{
return $query->joinRelationship($relation)->where('posts.published', true);
}
User::customJoin('posts')->get();
Dynamic Composite Keys:
public function posts()
{
$keys = request()->has('dynamic') ? ['team_id', 'category_id'] : ['team_id'];
return $this->hasMany(Post::class, $keys, $keys);
}
Event Hooks:
eloquent.powerjoins.joining events to modify join behavior:
Event::listen('eloquent.powerjoins.joining', function ($model, $relation) {
if ($relation === 'posts') {
$model->query->where('posts.active', true);
}
});
Testing:
$user = User::factory()->create();
$post = Post::factory()->create(['team_id' => $user->team_id, 'category_id' => $user->category_id]);
$user->posts()->save($post);
$this->assertCount(1, User::joinRelationship('posts')->get());
How can I help you explore Laravel packages today?