Get all relationships morphedBy
An Order
has many ordered elements
And the Order
ordered items can be either User
orProduct
What I'm looking for is a way to get all changed objects in Order
. Instead of $order->users
or $order->products
I would like to do $order->items
.
My progress
My progress so far includes Lots of polymorphic relationships .
My tables:
orders
id - integer
orderables (the order items)
order_id - integer
orderable_id - integer
orderable_type - string
quantity - integer
price - double
-----------
users
id - integer
name - string
products
id - integer
name - string
An example of what a table looks like orderables
This is how I create an order and add user and product:
/**
* Order
* @var Order
*/
$order = new App\Order;
$order->save();
/**
* Add user to order
* @var [type]
*/
$user = \App\User::find(1);
$order->users()->sync([
$user->id => [
'quantity' => 1,
'price' => $user->price()
]
]);
/**
* Add product to order
* @var [type]
*/
$product = \App\product::find(1);
$order->products()->sync([
$product->id => [
'quantity' => 1,
'price' => $product->price()
]
]);
Order.php
/**
* Ordered users
* @return [type] [description]
*/
public function users() {
return $this->morphedByMany('Athliit\User', 'orderable');
}
/**
* Ordered products
*/
public function products() {
return $this->morphedByMany('Athliit\Product', 'orderable');
}
Currently I can do
foreach($order->users as $user) {
echo $user->id;
}
or..
foreach($order->products as $product) {
echo $product->id;
}
But I would like to be able to do something like ...
foreach($order->items as $item) {
// $item is either User or Product class
}
I found this question, which was the closest I could find to what I am trying to do, but I cannot get it to work for my requires, it is outdated and also seems like a very hackish solution.
Have a different approach?
If you have a different approach than Polymorphic relationships, please let me know.
source to share
Personally, my models Order
have a lot OrderItems
, and those OrderItems
that have a polymorphic relationship. This way I can get all the order items regardless of the model type:
class Order extends Model
{
public function items()
{
return $this->hasMany(OrderItem::class);
}
public function addItem(Orderable $item, $quantity)
{
if (!is_int($quantity)) {
throw new InvalidArgumentException('Quantity must be an integer');
}
$item = OrderItem::createFromOrderable($item);
$item->quantity = $quantity;
$this->items()->save($item);
}
}
class OrderItem extends Model
{
public static function createFromOrderable(Orderable $item)
{
$this->orderable()->associate($item);
}
public function order()
{
return $this->belongsTo(Order::class);
}
public function orderable()
{
return $this->morphTo('orderable');
}
}
Then, create an interface and trait that I can apply to Eloquent, making them "ordered":
interface Orderable
{
public function getPrice();
}
trait Orderable
{
public function orderable()
{
return $this->morphMany(OrderItem::class, 'orderable');
}
}
use App\Contracts\Orderable as OrderableContract; // interface
use App\Orderable; // trait
class Product extends Model implements OrderableContract
{
use Orderable;
}
class EventTicket extends Model implements OrderableContract
{
use Orderable;
}
As you can see, my copy OrderItem
may be either Product
, EventTicket
or any other model that implements the interface Orderable
. Then you can get all your orders, for example:
$orderItem = Order::find($orderId)->items;
And it doesn't matter what type the instances are OrderItem
.
EDIT: To add items to your orders:
// Create an order instance
$order = new Order;
// Add an item to the order
$order->addItem(User::find($userId), $quantity);
source to share