Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Adgower's avatar
Level 14

withCount morph through?

I have the following setup: Products has many items/variations, items has many inventories, and an inventory belongs to a morph (stockable which is a warehouse or a store), and the stockable (warehouse or store) belongs to 1 a region.

Maybe I am making this complicated, but I am trying to see how many regions a product is in and return for example: "Coding Product 1 is in 5 regions", so it returns the count of regions for each product.

I have setup a has Many through (Inventory::class, Item::class) on the Product to get the inventories for example $product->inventories. This is the part where I am stuck. If I $product->inventories->first()->stockable->region->id, gives me the region->id. This seems inefficient, and I was hoping I could deploy a has one through, but the inventory contains the stockable morphto relationship...

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    use HasFactory;

    public function items()
    {
        return $this->hasMany(Item::class);
    }

    public function inventories()
    {
        return $this->hasManyThrough(Inventory::class, Item::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    use HasFactory;

    public function inventories()
    {
        return $this->hasMany(Inventory::class);
    }

    public function product()
    {
        return $this->belongsTo(Product::class);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Lukeraymonddowning\Mula\Facades\Mula;

class Inventory extends Model
{
    use HasFactory;

    public function stockable()
    {
        return $this->morphTo();
    }

    public function item()
    {
        return $this->belongsTo(Item::class);
    }

    public function getValueAttribute()
    {
        return $this->quantity * $this->item->price;
    }

    public function getFormattedValueAttribute()
    {
        return Mula::parse($this->value, 'USD')->display();
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Lukeraymonddowning\Mula\Facades\Mula;

class Store extends Model
{
    use HasFactory;

    public function region()
    {
        return $this->belongsTo(Region::class);
    }

    public function itemInventory()
    {
        return $this->morphMany(Inventory::class, 'stockable');
    }

    public function getInventoryValueAttribute()
    {
        $total = 0;

        foreach($this->itemInventory as $inventory) {
            $total += $inventory->value;
        }

        return $total;
    }

    public function getFormattedInventoryValueAttribute()
    {
        return Mula::parse($this->inventory_value, 'USD')->display();
    }
}

Here is the query i'm currently building:

$products = Product::when($this->searchProducts != '', function($query) {
            $query->where('title', 'like', '%'.$this->searchProducts.'%');
        })->withCount(['items', 'inventories as store_count' => function($query) {
            $query->where('stockable_type', 'App\Models\Store');
        }, 'inventories as warehouse_count' => function($query) {
            $query->where('stockable_type', 'App\Models\Warehouse');
        }])->withAvg('items', 'price')->withAvg(['inventories as store_avg_quantity' => function($query) {
            $query->where('stockable_type', 'App\Models\Store');
        }, 'inventories as warehouse_avg_quantity' => function($query) {
            $query->where('stockable_type', 'App\Models\Warehouse');
        }], 'quantity')->withSum(['inventories as store_quantity' => function($query) {
            $query->where('stockable_type', 'App\Models\Store');
        }, 'inventories as warehouse_quantity' => function($query) {
            $query->where('stockable_type', 'App\Models\Warehouse');
        }, 'inventories as total_quantity'], 'quantity')->when($this->sortQuantity == true, function($query) {
            $query->orderBy('total_quantity', $this->sortDirection ? 'asc' : 'desc' );
        })->get();

I want to add withCount and get regions_count

any tips?

0 likes
0 replies

Please or to participate in this conversation.