检索所有morphedBy关系

时间:2015-07-26 14:38:49

标签: php laravel laravel-5 eloquent

Order有许多订购商品

Order订购商品可以是UserProduct

我正在寻找的是一种将所有变形对象检索到Order的方法。而不是$order->users$order->products我想$order->items

我的进展

到目前为止,我的进展涉及Many To Many Polymorphic Relationship

我的表格:

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

关于orderables表格外观的示例 orderables table (a orders items)

这是我创建订单并添加用户和产品的方式:

/**
 * 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');
    }

目前我可以做到

foreach($order->users as $user) {
    echo $user->id;
}

或..

foreach($order->products as $product) {
    echo $product->id;
}

但我希望能够按照......的方式做点什么。

foreach($order->items as $item) {
    // $item is either User or Product class
}

我发现了this问题,这是我能找到的最接近我想要做的事情,但我不能让它在我的需求方面发挥作用,它已经过时了,也似乎是一个非常讨厌的解决方案。

有不同的方法吗?

如果您的方法与多态关系不同,请告诉我。

2 个答案:

答案 0 :(得分:3)

就个人而言,我的Order模型有很多OrderItemsOrderItems具有多态关系。这样,我可以获取订单的所有项目,无论它们是什么类型的模型:

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');
    }
}

然后我将创建一个界面和特征,我可以应用于使其“可订购”的Eloquent模型:

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;
}

如您所见,我的OrderItem实例可以是ProductEventTicket,也可以是实现Orderable接口的任何其他模型。然后,您可以获取所有订单的商品,如下所示:

$orderItem = Order::find($orderId)->items;

OrderItem实例变换为什么类型并不重要。

编辑:要向订单添加商品:

// Create an order instance
$order = new Order;

// Add an item to the order
$order->addItem(User::find($userId), $quantity);

答案 1 :(得分:0)

我认为您的解决方案很好。我只是添加这个辅助方法:

Order.php

public function items() {
    return collect($this->products)->merge($this->users);
}

然后你可以用以下内容遍历项目:

foreach ($order->items() as $item) {