使用`Model :: query`的复杂Eloquent关系

时间:2017-09-04 17:12:45

标签: laravel laravel-5 eloquent

我有一个复杂的关系,我试图在两个模型之间建立。

目标是使用$supplier->supply_orders来访问用户提供商品的订单。

抛出:LogicException: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

使用我得到的代码我可以使用$supplier->supply_orders()->get(),但是,当我尝试将其用作关系时,它会抛出。由于这是一种关系,我应该能够将它包含在一段关系中,但我该如何去做呢?

供应商型号:

class Supplier extends Model {
    public function supply_orders() {
        return Order::query()
            ->select('order.*')
            ->join('item_order', 'order.id', '=', 'item_order.order_id')
            ->join('item', 'item_order.item_id', '=', 'item.id')
            ->where('item.supplier_id', '=', $this->id);
    }
}

~~~我认为你不需要的很多背信息可能会~~~

sql tables:

supplier
- id

items:
- id
- supplier_id

item_order:
- id
- order_id
- item_id

orders:
- id

其他雄辩模特:

class Item extends Model {
    public function orders() {
        return $this->belongsToMany('Order');
    }
}

class Order extends Model {}

这应该如何运作的例子:

$supplier = factory(Supplier::class)->create();
$item = factory(Item::class)->create([
    'supplier_id' => $supplier->id,
]);
$order = factory(Order::class)->create();
$order->items()->attach($item);
$orders = $supplier->supply_orders // Throws LogicException

抛出:LogicException: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation

2 个答案:

答案 0 :(得分:1)

听起来像是一个拥有多对多关系的hasManyThrough。 Laravel没有内置的支持,但你可以随时写下你自己的关系:https://laravel.io/forum/03-04-2014-hasmanythrough-with-many-to-many

如果你不想要人际关系,你总是可以这样做:

Order::whereHas('items.supplier', function($query) use($supplier) { 
    $query->where('id', $supplier->id);
});

为此,您需要在订单模型中使用关系函数items,在商品模型中使用关系函数supplier

答案 1 :(得分:0)

我认为它引发关系错误的原因是你没有为

创建一个雄辩的关系
$supplier->supply_orders.

相反,Laravel会将您的supply_orders()视为类中的方法,因此无法确定将哪个表用作数据透视表。要使基本关系在Eloquent中工作,您需要为供应商和订单之间的关系创建一个新的数据透视表,例如:

suppliers
    -id

orders
    -id

order_supplier
    -id
    -order_id
    -supplier_id

从这里开始,Laravel将接受两者之间简单的多对多关系(这不会导致失败):

Supplier Class:
 /**
 * Get all orders associated with this supplier via order_supplier table
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
 */
public function orders(){
    return $this->belongsToMany("\App\Order");
}

既然供应商和订单之间的关系以及订单和物品之间的关系都很稳定,那么您可以急切地加载所有方向的关系。使用当前数据库设置使您的特定需求变得复杂的情况是,您有一个来自items表的第三个参数,它不是直接的枢轴。无需重新构建数据库,我认为最简单的方法是加载供应商和正常的关系:

$suppliers = Supplier::with('orders', function($query) { 
    $query->with('items');
});

从这里开始,你已经加载了所有的关系,并且可以在$ suppliers集合的后续内容中使用正确的item-> id来绘制这些关系。现在有很多方法可以让猫(甚至包括所有在一个查询中),因为你有Eloquent关系...但我倾向于通过将它分成几个可读的位来保持它更简单。

希望这有帮助。