staudenmeir/belongs-to-through

Laravel Eloquent BelongsToThrough relationships

Maintainers

👁 staudenmeir

Package info

github.com/staudenmeir/belongs-to-through

pkg:composer/staudenmeir/belongs-to-through

Fund package maintenance!

paypal.me/JonasStaudenmeir

Statistics

Installs: 10 318 364

Dependents: 25

Suggesters: 1

Stars: 1 266

Open Issues: 0

v2.18 2026-02-28 16:25 UTC

Requires

Suggests

None

Provides

None

Conflicts

None

Replaces

None

MIT accb37643cf4829319617923877d11b55558a099

  • Rahul Kadyan <hi.woop@znck.me>
  • Jonas Staudenmeir <mail.woop@jonas-staudenmeir.de>

README

👁 CI
👁 Code Coverage
👁 PHPStan
👁 Latest Stable Version
👁 Total Downloads
👁 License

This inverse version of HasManyThrough allows BelongsToThrough relationships with unlimited intermediate models.

Supports Laravel 5.0+.

Installation

composer require staudenmeir/belongs-to-through:"^2.5"

Use this command if you are in PowerShell on Windows (e.g. in VS Code):

composer require staudenmeir/belongs-to-through:"^^^^2.5"

Versions

Laravel Package
13.x 2.18
12.x 2.17
11.x 2.16
10.x 2.13
9.x 2.12
8.x 2.11
7.x 2.10
6.x 2.6
5.x 2.5

Usage

Consider this HasManyThrough relationship:
Country → has many → User → has many → Post

class Country extends Model
{
 public function posts()
 {
 return $this->hasManyThrough(Post::class, User::class);
 }
}

Use the BelongsToThrough trait in your model to define the inverse relationship:
Post → belongs to → User → belongs to → Country

class Post extends Model
{
 use \Znck\Eloquent\Traits\BelongsToThrough;

 public function country(): \Znck\Eloquent\Relations\BelongsToThrough
 {
 return $this->belongsToThrough(Country::class, User::class);
 }
}

You can also define deeper relationships:
Comment → belongs to → Post → belongs to → User → belongs to → Country

Supply an array of intermediate models as the second argument, from the related (Country) to the parent model (Comment):

class Comment extends Model
{
 use \Znck\Eloquent\Traits\BelongsToThrough;

 public function country(): \Znck\Eloquent\Relations\BelongsToThrough
 {
 return $this->belongsToThrough(Country::class, [User::class, Post::class]);
 }
}

Custom Foreign Keys

You can specify custom foreign keys as the fifth argument:

class Comment extends Model
{
 use \Znck\Eloquent\Traits\BelongsToThrough;

 public function country(): \Znck\Eloquent\Relations\BelongsToThrough
 {
 return $this->belongsToThrough(
 Country::class,
 [User::class, Post::class], 
 foreignKeyLookup: [User::class => 'custom_user_id']
 );
 }
}

Custom Local Keys

You can specify custom local keys for the relations:

VendorCustomerAddress → belongs to → VendorCustomer in VendorCustomerAddress.vendor_customer_id VendorCustomerAddress → belongs to → CustomerAddress in VendorCustomerAddress.address_id

You can access VendorCustomer from CustomerAddress by the following

class CustomerAddress extends Model
{
 use \Znck\Eloquent\Traits\BelongsToThrough;

 public function vendorCustomer(): \Znck\Eloquent\Relations\BelongsToThrough
 {
 return $this->belongsToThrough(
 VendorCustomer::class,
 VendorCustomerAddress::class,
 foreignKeyLookup: [VendorCustomerAddress::class => 'id'],
 localKeyLookup: [VendorCustomerAddress::class => 'address_id'],
 );
 } 
}

Table Aliases

If your relationship path contains the same model multiple times, you can specify a table alias (Laravel 6+):

class Comment extends Model
{
 use \Znck\Eloquent\Traits\BelongsToThrough;

 public function grandparent(): \Znck\Eloquent\Relations\BelongsToThrough
 {
 return $this->belongsToThrough(
 Comment::class,
 Comment::class . ' as alias',
 foreignKeyLookup: [Comment::class => 'parent_id']
 );
 }
}

Use the HasTableAlias trait in the models you are aliasing:

class Comment extends Model
{
 use \Znck\Eloquent\Traits\HasTableAlias;
}

Soft Deleting

By default, soft-deleted intermediate models will be excluded from the result. Use withTrashed() to include them:

class Comment extends Model
{
 use \Znck\Eloquent\Traits\BelongsToThrough;

 public function country(): \Znck\Eloquent\Relations\BelongsToThrough
 {
 return $this->belongsToThrough(Country::class, [User::class, Post::class])
 ->withTrashed('users.deleted_at');
 }
}

class User extends Model
{
 use SoftDeletes;
}

Contributing

Please see CONTRIBUTING and CODE OF CONDUCT for details.

Credits