Laravel Dynamic Polymorphic Relation

Viewed 494

So I'm trying to make dynamic relationships for order items in Laravel. I have 3 main types of models:

  • Order
  • Order Item (has orderable_type and orderable_id that refer to Product models)
  • Product (multiple models)

And my goal is to have the Order model to be able to have order items but also include their respective product models (orderable).

These are my models:

class Order extends Model
{
    public function items()
    {
        return $this->hasMany(OrderItem::class);
    }
}

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

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

class ProductType extends Model
{
    public function orderItem()
    {
        return $this->morphOne(OrderItem::class, 'orderable');
    }
}

So, when I call Order::with('items')->get() I get the collection of \App\Models\OrderItem included:

Illuminate\Database\Eloquent\Collection {#4059
  all: [
    App\Models\Order {#4016
      id: 1,
      ...
      items: Illuminate\Database\Eloquent\Collection {#4026
        all: [
          App\Models\OrderItem {#4063
            id: 1,
            orderable_type: "ProductType",
            orderable_id: 1,
            ...
          },
        ],
      },
    },
  ],
}

And what I expect to have is:

Illuminate\Database\Eloquent\Collection {#4059
  all: [
    App\Models\Order {#4016
      id: 1,
      ...
      items: Illuminate\Database\Eloquent\Collection {#4026
        all: [
          App\Models\OrderItem {#4063
            id: 1,
            orderable_type: "ProductType",
            orderable_id: 1,
            orderable: App\Models\Products\ProductType {
              ...
            }
            ...
          },
        ],
      },
    },
  ],
}

So it's kind of a nested with(), but not sure how to make it happen. The purpose is to have everything in a single Eloquent call instead of calling the relationship afterward (meant to be on an API Resource as well).

1 Answers

You are looking for nested eager loading. You can use them in your case like:

Order::with('items.orderable')->get();
Related