PHPackages                             stancl/laravel-hasmanywithinverse - 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. stancl/laravel-hasmanywithinverse

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

stancl/laravel-hasmanywithinverse
=================================

Define HasMany while also setting the inverse relationship in Laravel.

v1.4.2(3y ago)693.9k5[1 issues](https://github.com/archtechx/laravel-hasmanywithinverse/issues)MITPHP

Since Apr 2Pushed 3y ago1 watchersCompare

[ Source](https://github.com/archtechx/laravel-hasmanywithinverse)[ Packagist](https://packagist.org/packages/stancl/laravel-hasmanywithinverse)[ RSS](/packages/stancl-laravel-hasmanywithinverse/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (7)Dependencies (3)Versions (8)Used By (0)

stancl/laravel-hasmanywithinverse
=================================

[](#stancllaravel-hasmanywithinverse)

Why?
----

[](#why)

[Jonathan Reinink](https://github.com/reinink) wrote a great blog post about [Optimizing circular relationships in Laravel](https://reinink.ca/articles/optimizing-circular-relationships-in-laravel)

By manually setting the (`belongsTo`) relationship to a parent model on related (`hasMany`) child models, you can save unnecessary queries for the parent model -- when the child needs an instance of the parent model.

This probably sounds confusing, so just read the blog post. It's very good.

Jonathan's approach suggests using something like this:

```
$category->products->each->setRelation('category', $category);
```

This works, but it's not very clean and there are cases when it doesn't work. For example, on model creation.

If you're accessing the parent model in `creating` and `saving` events on the children, the `->each->setRelation()` approach won't help you at all. (And if you're building a complex app with [Laravel Nova](https://nova.laravel.com), there's a high chance you're using lots of such events.)

Practical Example &amp; Benchmarks
----------------------------------

[](#practical-example--benchmarks)

I have an e-commerce application where an `Order` has child models: `OrderProduct`, `OrderStatus` and `OrderFee` (think shipping costs, payment fees, etc).

When some of those models are **being created** (`creating` Eloquent event), they are accessing the parent model.

For example, `OrderProduct`s convert their prices to `$this->order->currency`. `OrderFee`s check for other order fees, and they prevent creating themselves if a fee with the same code already exists (so that you can't have, say, the shipping cost counted twice). Etc.

This results in order creation being expensive, resulting in a large amount of n+1 queries.

### Benchmark

[](#benchmark)

I haven't run a huge amount of tests, so I won't present the time differences here. I will only talk about database query count.

I have created an order with 6 products.

#### This is the amount of queries made with regular `hasMany()`

[](#this-is-the-amount-of-queries-made-with-regular-hasmany)

[![Query count with hasMany()](https://camo.githubusercontent.com/75b384920c83025860a7c847300025f45086a33d072b93ffa1f23cd6304a8622/68747470733a2f2f692e696d6775722e636f6d2f5973733761566c2e706e67)](https://camo.githubusercontent.com/75b384920c83025860a7c847300025f45086a33d072b93ffa1f23cd6304a8622/68747470733a2f2f692e696d6775722e636f6d2f5973733761566c2e706e67)

And now I just replace all of these calls:

```
return $this->hasMany(...);
```

with these calls

```
return $this->hasManyWithInverse(..., 'order');
```

inside the `Order` model.

#### And this is the amount of queries made with `hasManyWithInverse()`

[](#and-this-is-the-amount-of-queries-made-with-hasmanywithinverse)

[![Query count with hasManyWithInverse()](https://camo.githubusercontent.com/35edb3411230b49a173646c3872efb3cbe3af390a0c5f7ec5a33081d5abb7576/68747470733a2f2f692e696d6775722e636f6d2f58696d573654372e706e67)](https://camo.githubusercontent.com/35edb3411230b49a173646c3872efb3cbe3af390a0c5f7ec5a33081d5abb7576/68747470733a2f2f692e696d6775722e636f6d2f58696d573654372e706e67)

See the query count reduction.

The duration was also decreased from 114ms to 45ms on my machine, though note that I did not run this test a million times to calculate an average duration, so that benchmark might not be very accurate.

This is pretty impressive for **a free improvement that only requires changing a few simple calls to a similar method**.

But note that this is not a silver bullet for solving all n+1 queries. As you can see, even with this implemented, my app still has many duplicated queries. (Although not all are unintentional n+1s as there are a few `$this->refresh()` calls to keep the order up-to-date after state transitions).

Installation
------------

[](#installation)

Laravel 9.x and 10.x are supported.

```
composer require stancl/laravel-hasmanywithinverse

```

Usage
-----

[](#usage)

```
namespace App;

use Stancl\HasManyWithInverse\HasManyWithInverse;

class Order extends Model
{
    use HasManyWithInverse;

    public function products()
    {
        // 'order' is the name of the relationship in the other model, see below
        return $this->hasManyWithInverse(OrderProduct::class, 'order');
    }
}

class OrderProduct extends Model
{
    public function order()
    {
        return $this->belongsTo(Order::class);
    }
}
```

You may also want to use the trait in a base Eloquent model and then use `$this->hasManyWithInverse()` without thinking about traits in the specific models.

Details
-------

[](#details)

The (simple) internals of the package are just methods copied from Eloquent source code, with a few lines added to them. The `hasManyWithInverse()` method signature is the same as `hasMany()` (you can set `$foreignKey` and `$localKey`), except the second argument (`$inverse`) was added to let you define the name of the relationship on the child model, and the last argument (`$config`) was added to let you configure the relation setting's behavior.

**This package sets the parent relation on children both when creating children (`$child = $parent->children()->create()`) and when resolving parent's children (`$children = $parent->children`).** You can customize this behavior for every relationship.

To disable setting the relationship during child **creation**, do this:

```
class Parent extends Model
{
    public function children()
    {
        return $this->hasManyWithInverse(Child::class, 'parent', null, null, ['setRelationOnCreation' => false]);
    }
}
```

To disable setting the relationship during child **resolution**, do this:

```
class Parent extends Model
{
    public function children()
    {
        return $this->hasManyWithInverse(Child::class, 'parent', null, null, ['setRelationOnResolution' => false]);
    }
}
```

You may also pass a callable as the config value. This is useful if you want to disable this behavior on some requests. See example below.

Laravel Nova
------------

[](#laravel-nova)

It's a good idea to disable setting the relationship on resolution for Nova requests. They tend to make a lot of queries and this can slow the page down (or result in 502 errors).

Here's an example implementation using a base model and adding config to filter out Nova requests.

```
abstract class Model extends EloquentModel
{
    use HasManyWithInverse {
        hasManyWithInverse as originalHasManyWithInverse;
    }

    public function hasManyWithInverse($related, $inverse, $foreignKey = null, $localKey = null, $config = [])
    {
        $config = array_merge(['setRelationOnResolution' => function () {
            if (request()->route() && in_array('nova', request()->route()->middleware())) {
                return false;
            }
        }], $config);

        return $this->originalHasManyWithInverse($related, $inverse, $foreignKey, $localKey, $config);
    }
}
```

###  Health Score

35

—

LowBetter than 79% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity32

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

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

###  Release Activity

Cadence

Every ~174 days

Recently: every ~261 days

Total

7

Last Release

1181d ago

PHP version history (3 changes)v1.1.0PHP ^7.2

v1.3.0PHP ^7.2|^7.3

v1.4.0PHP ^7.2|^7.3|^8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/d62e0fd56f0d6c0e97a7e62e82dc753de23ad9e32f7d78741118d6cb089d697c?d=identicon)[stancl](/maintainers/stancl)

---

Top Contributors

[![stancl](https://avatars.githubusercontent.com/u/33033094?v=4)](https://github.com/stancl "stancl (20 commits)")[![mr4rtur](https://avatars.githubusercontent.com/u/7056661?v=4)](https://github.com/mr4rtur "mr4rtur (6 commits)")[![lukinovec](https://avatars.githubusercontent.com/u/34375937?v=4)](https://github.com/lukinovec "lukinovec (3 commits)")[![szepeviktor](https://avatars.githubusercontent.com/u/952007?v=4)](https://github.com/szepeviktor "szepeviktor (3 commits)")[![abrardev99](https://avatars.githubusercontent.com/u/54532330?v=4)](https://github.com/abrardev99 "abrardev99 (2 commits)")

---

Tags

eloquentlaravel

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/stancl-laravel-hasmanywithinverse/health.svg)

```
[![Health](https://phpackages.com/badges/stancl-laravel-hasmanywithinverse/health.svg)](https://phpackages.com/packages/stancl-laravel-hasmanywithinverse)
```

###  Alternatives

[owen-it/laravel-auditing

Audit changes of your Eloquent models in Laravel

3.4k33.0M95](/packages/owen-it-laravel-auditing)[staudenmeir/eloquent-json-relations

Laravel Eloquent relationships with JSON keys

1.1k5.8M24](/packages/staudenmeir-eloquent-json-relations)[bavix/laravel-wallet

It's easy to work with a virtual wallet.

1.3k1.1M11](/packages/bavix-laravel-wallet)[dragon-code/migrate-db

Easy data transfer from one database to another

15717.4k](/packages/dragon-code-migrate-db)[gearbox-solutions/eloquent-filemaker

A package for getting FileMaker records as Eloquent models in Laravel

6454.8k2](/packages/gearbox-solutions-eloquent-filemaker)[cybercog/laravel-ownership

Laravel Ownership simplify management of Eloquent model's owner.

9126.6k3](/packages/cybercog-laravel-ownership)

PHPackages © 2026

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