Restricting hasMany relationship where child.field != parent.field without joins

Viewed 29

I'm looking for a way to qualify a hasMany relationship to exclude/include children where the value a specific child field does/not match that of a specific parent field without using joins.

The issue with joins is that the ->select() filters out many descendant relationships (unless they are each added to the join, which is too much to manage). The descendant relationships for example would be order_item.options which is a belongsToMany of OrderItem.

Case in point:

class Order extends Model
{

    public function items()
    {
        return $this->hasMany(OrderItem::class, 'order_id', 'id');
    }

    public function items_removed_by_store()
    {
        return $this->hasMany(OrderItem::class, 'order_id', 'id')
            //->join('order', 'order_item.order_id', 'order.id')
            //->where('order_item.deleted_by', '!=', 'order.customer_id')
            //->select('order_item.*', 'order.customer_id')
            ->onlyTrashed();
    }

    public function items_removed_by_customer()
    {
        return $this->hasMany(OrderItem::class, 'order_id', 'id')
            //->join('order', 'order_item.order_id', 'order.id')
            //->where('order_item.deleted_by', '=', 'order.customer_id')
            //->select('order_item.*', 'order.customer_id')
            ->onlyTrashed();
    }

}

and I'm looking to query it like:

Location::has('orders.items_removed_by_customer')->get()

Get me locations where customers have removed items from their orders.

1 Answers

It seems like you are currently joining the relationship on its parent. Note you already have the parent data

Maybe try something like this

class Order extends Model
{

    public function items()
    {
        // Note: it is not required to pass 'order_id', 'id' to this method as thats the default value
        return $this->hasMany(OrderItem::class);
    }

    public function items_removed_by_store()
    {
        return $this->items()
            ->where('order_items.deleted_by', '!=', $this->customer_id)
            ->onlyTrashed();
    }

    public function items_removed_by_customer()
    {
        return $this->items()
            ->where('order_item.deleted_by', '=', $this->customer_id)
            ->onlyTrashed();
    }

}
Related