PHPackages                             webelightdev/eager-join - 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. webelightdev/eager-join

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

webelightdev/eager-join
=======================

This package introduces the join capability for sorting and filtering on eloquent relations.

021PHP

Since Feb 16Pushed 7y ago3 watchersCompare

[ Source](https://github.com/webelightdev/eager-join)[ Packagist](https://packagist.org/packages/webelightdev/eager-join)[ RSS](/packages/webelightdev-eager-join/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependenciesVersions (1)Used By (0)

Thanks to
============================================================

[](#thanks-to-httpsgithubcomolegramlaravel-eloquent-join)

Laravel Eloquent Join
=====================

[](#laravel-eloquent-join)

This package introduces the join capability for sorting and filtering on eloquent relations.

Eloquent Problems
-----------------

[](#eloquent-problems)

You can't perform sorting on the relationship field without manually joining related table which is very awkward. Let me give you a few reasons why. If you have a table with posts and related categories your code might look like this:

```
$posts = Post::select('posts.*')
    ->join('categories', 'categories.id', '=', 'posts.category_id')
    ->groupBy('posts.id')
    ->where('categories.deleted_at', '=', null)
    ->orderBy('categories.name');

if(request()->get('date')){
    $posts->where('posts.date', $date)
}

$posts = $posts->get();

```

1.The first problem is that you need to worry about select.

```
->select('posts.*')

```

reason : without select() id from category can be selected and hydrated into Post model.

2.The second problem is that you need to worry about groupBy.

```
->groupBy('posts.id');

```

reason : if the relation is HasOne and there are more than one categories for the post, the query will return more rows for categories.

3.The third problem is that you need to change all other where clauses from :

```
->where('date', $date)

```

to

```
->where('posts.date', $date)

```

reason : post and category can have "date" attribute and in that case without selecting attribute with table "ambiguous column" error will be thrown.

4.The fourth problem is that you are using table names(not models) and this is also bad and awkward.

```
->where('posts.date', $date)

```

5.The fifth problem is that you need to worry about soft deletes for joined tables. If the category is using SoftDeletes trait you must add :

```
->where('categories.deleted_at', '=', null)

```

This package will take care of all above problems for you out of the box. You can perform filtering on the relationship field without joining but this package will give you the ability to do this easier.

Version Compatibility
---------------------

[](#version-compatibility)

Laravel VersionPackage TagSupportedDevelopment Branch5.6.\*2.2.\*yesmaster5.5.\*2.1.\*yes2.15.4.\*2.0.\*yes2.05.3.\*1.3.\*yes1.35.2.\*1.2.\*yes1.2&lt;5.2-noInstall
-------

[](#install)

1.Install package with composer

```
composer require fico7489/laravel-eloquent-join:"*"

```

With this statement, a composer will install highest available package version for your current laravel version.

2.Use Fico7489\\Laravel\\EloquentJoin\\Traits\\EloquentJoinTrait trait in your base model or only in particular models.

```
...
use Fico7489\Laravel\EloquentJoin\Traits\EloquentJoinTrait;
use Illuminate\Database\Eloquent\Model;

abstract class BaseModel extends Model
{
    use EloquentJoinTrait;
...

```

and that's it, you are ready to go.

Options
-------

[](#options)

##### Use table alias

[](#use-table-alias)

Should we use alias for joined tables (default = false)

With true query will look like this :

```
select "sellers".* from "sellers"
    left join "locations" as "5b5c093d2e00f"
    on "5b5c093d2e00f"."seller_id" = "sellers"."id" and "5b5c093d2e00f"."is_primary" = ?
    and "5b5c093d2e00f"."is_secondary" = ?
    and "5b5c093d2e00f"."deleted_at" is null
    group by "sellers"."id" order by "5b5c093d2e00f"."id" desc

```

With false query will look like this :

```
select "sellers".* from "sellers" left join "locations"
    on "locations"."seller_id"     = "sellers"."id"
    and "locations"."is_primary"     = ?
    and "locations"."is_secondary"     = ?
    and "locations"."deleted_at" is null
    group by "sellers"."id" order by "locations"."id" desc

```

Set option in your base model :

```
    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);

        $this->useTableAlias = true;
    }

```

Instructions for use
--------------------

[](#instructions-for-use)

##### Currently available relations for join queries

[](#currently-available-relations-for-join-queries)

- **BelongsTo**
- **HasOne**.

##### New clauses for eloquent builder on BelongsTo and HasOne relations

[](#new-clauses-for-eloquent-builder-on-belongsto-and-hasone-relations)

- **orderByJoin($column, $sortBy = 'asc')**$sortBy argument is same as in default eloquent sortBy()
- **whereJoin($column, $operator = null, $value = null, $boolean = 'and')**$operator, $value, $boolean arguments are the same as in default eloquent where()
- **orWhereJoin($column, $operator = null, $value)**$operator and $value arguments are the same as in default eloquent orWhere()

##### Rules for column parameter in whereJoin, orWhereJoin and orderByJoin

[](#rules-for-column-parameter-in-wherejoin-orwherejoin-and-orderbyjoin)

- current table attributes
- related table attributes (relationship names with dots)
- related tables can be nested unlimited with any combination of HasOne and BelongsTo relations, they only need to meet **relation rules** for join queries.

```
->where('title', '=', 'test')
->where('relationName.title', '=', 'test')
->where('relationName.relationNameSecond.title', '=', 'test')

```

##### Allowed clauses on BelongsTo and HasOne relations on which you want use join clauses on the query

[](#allowed-clauses-on-belongsto-and-hasone-relations-on-which-you-want-use-join-clauses-on-the-query)

- Relations that you want to use for join queries can only have this clauses : **where**, **orWhere**, **withTrashed**, **onlyTrashed**, **withoutTrashed**.
- Clauses **where** and **orWhere** can only have this variation **-&gt;where($columnn, $operator, $attribute)**, closures are not allowed.
- Other clauses like whereHas, orderBy etc. are not allowed.
- You can add not allowed clauses on relations and use them in the normal eloquent way, but in that case, you can't use those relations for join queries.
- If **withTrashed**, **onlyTrashed** or **withoutTrashed** is not applied for relation modes that use SoftDeletes, default behavior is **withoutTrashed**, this means that join query will by default only look for related tables that are not soft deleted.

Allowed relation

```
public function locationPrimary()
{
    return $this->hasOne(Location::class)
        ->where('is_primary', '=', 1)
        ->orWhere('is_primary', '=', 1)
        ->withTrashed();
}

```

Not allowed relation :

```
public function locationPrimary()
{
    return $this->hasOne(Location::class)
        ->where('is_primary', '=', 1)
        ->orWhere('is_primary', '=', 1)
        ->withTrashed()
        ->whereHas('state', function($query){return $query;}
        ->orderBy('name');
}

```

The reason why the second relation is not allowed is that this package applies where, orWhere and other clauses on the left join (all eloquent clauses can't be performed on join). Eloquent can use all those clauses because eloquent use subqueries not join.

##### Other

[](#other)

- You can combine new clauses unlimited times
- If you combine clauses more times on same relation package will join related table only once
- You can combine join clauses e.g. whereJoin() with elaquent clauses e.g. orderBy()

```
Seller::whereJoin('title', 'test')->whereJoin('city.title', 'test')->orderByJoin('city.title')->get();

```

You might get a picture that there are many rules and restriction, but it is really not like that. Don't worry, if you anyway create the query that is not allowed **EloquentJoinException** will be thrown with explaining what happened.

See action on real example
--------------------------

[](#see-action-on-real-example)

Database schema :

[![Database schema](https://raw.githubusercontent.com/fico7489/laravel-eloquent-join/master/readme/era.png)](https://raw.githubusercontent.com/fico7489/laravel-eloquent-join/master/readme/era.png)

Models :

```
class Seller extends BaseModel
{
    public function locationPrimary()
    {
        return $this->hasOne(Location::class)
            ->where('is_primary', '=', 1);
    }

    public function city()
    {
        return $this->belongsTo(City::class);
    }

```

```
class Location extends BaseModel
{
    public function locationAddressPrimary()
    {
        return $this->hasOne(LocationAddress::class)
            ->where('is_primary', '=', 1);
    }

```

```
class LocationAddress extends BaseModel
{

```

```
class City extends BaseModel
{
    public function state()
    {
        return $this->belongsTo(State::class);
    }
}

```

```
class State extends BaseModel
{

```

### Ordering

[](#ordering)

##### Order sellers by seller title

[](#order-sellers-by-seller-title)

`Seller::orderByJoin('title')`

##### Order sellers by city name

[](#order-sellers-by-city-name)

`Seller::orderByJoin('city.title')`

##### Order sellers by state name

[](#order-sellers-by-state-name)

`Seller::orderByJoin('city.state.title')`

##### Order sellers by primary location address

[](#order-sellers-by-primary-location-address)

`Seller::orderByJoin('locationPrimary.address')`

##### Order sellers by locationAddress name of primary location

[](#order-sellers-by-locationaddress-name-of-primary-location)

`Seller::orderByJoin('locationPrimary.locationAddressPrimary.address')`

##### You can also combine orderBy more times

[](#you-can-also-combine-orderby-more-times)

`Seller::orderByJoin('title')->orderBy('city.title')`

### Filtering

[](#filtering)

##### Filter sellers which have title = 'test'

[](#filter-sellers-which-have-title--test)

`Seller::whereJoin('title', 'test')`

##### Filter sellers which have city name = 'test'

[](#filter-sellers-which-have-city-name--test)

`Seller::whereJoin('city.title', '=', 'test')`

##### Filter sellers which have state name = 'test'

[](#filter-sellers-which-have-state-name--test)

`Seller::whereJoin('city.state.title', '=', 'test')`

##### Filter sellers which have primary location address = 'test'

[](#filter-sellers-which-have-primary-location-address--test)

`Seller::whereJoin('locationPrimary.address', '=', 'test')`

##### Filter sellers which have locationAddress name of primary location = 'test'

[](#filter-sellers-which-have-locationaddress-name-of-primary-location--test)

`Seller::whereJoin('locationPrimary.locationAddressPrimary.address', '=', 'test')`

##### You can also combine orderBy more times

[](#you-can-also-combine-orderby-more-times-1)

`Seller::whereJoin('title', 'test')->whereJoin('city.title', 'test')`

Lets look how first example from documentation now looks like. This code :

```
$posts = Post::select('posts.*')
    ->join('categories', 'categories.id', '=', 'posts.category_id')
    ->groupBy('posts.id')
    ->where('categories.deleted_at', '=', null)
    ->orderBy('categories.name');

if(request()->get('date')){
    $posts->where('posts.date', $date)
}

$posts = $posts->get();

```

is now :

```
$posts = Post::orderByJoin('category.name');

if(request()->get('date')){
    $posts->where('posts.date', $date)
}

$posts = $posts->get();

```

Both snippets generates the same MySql query.

Tests
-----

[](#tests)

This package is well covered with tests. If you want run tests just run **composer update** and then run tests with **"vendor/bin/phpunit"**

Contribution
------------

[](#contribution)

Feel free to create new issue for :

- bug
- notice
- request new feature
- question
- clarification
- etc...

License
-------

[](#license)

MIT

**Free Software, Hell Yeah!**

###  Health Score

19

—

LowBetter than 9% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity3

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 75% 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.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/6562115?v=4)[Yash Barot](/maintainers/yashbarot)[@yashbarot](https://github.com/yashbarot)

---

Top Contributors

[![yashbarot](https://avatars.githubusercontent.com/u/6562115?v=4)](https://github.com/yashbarot "yashbarot (3 commits)")[![jigneshwebelight](https://avatars.githubusercontent.com/u/40360228?v=4)](https://github.com/jigneshwebelight "jigneshwebelight (1 commits)")

### Embed Badge

![Health badge](/badges/webelightdev-eager-join/health.svg)

```
[![Health](https://phpackages.com/badges/webelightdev-eager-join/health.svg)](https://phpackages.com/packages/webelightdev-eager-join)
```

###  Alternatives

[jdorn/sql-formatter

a PHP SQL highlighting library

3.9k117.2M117](/packages/jdorn-sql-formatter)[propel/propel1

Propel is an open-source Object-Relational Mapping (ORM) for PHP5.

8351.6M87](/packages/propel-propel1)[pgvector/pgvector

pgvector support for PHP

198741.5k11](/packages/pgvector-pgvector)[jfelder/oracledb

Oracle DB driver for Laravel

11518.4k](/packages/jfelder-oracledb)

PHPackages © 2026

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