【问题标题】:Complicated Eloquent relationship using `Model::query`使用 `Model::query` 的复杂 Eloquent 关系
【发布时间】:2017-09-05 08:30:16
【问题描述】:

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

目标是使用$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 表:

supplier
- id

items:
- id
- supplier_id

item_order:
- id
- order_id
- item_id

orders:
- id

其他 Eloquent 模型:

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

【问题讨论】:

    标签: laravel laravel-5 eloquent


    【解决方案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

    【讨论】:

    • 你说得对,这是一个具有多对多关系的 hasManyThrough。我是否正确理解如果不扩展关系类就不可能创建关系?如果有一种方法可以为特定实例使用闭包或匿名类,那就太好了。或者如果有一个包含关系的包。
    【解决方案2】:

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

    创建 Eloquent 关系
    $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 关系,有很多方法可以给猫剥皮(甚至包括所有在一个查询中)......但我倾向于通过将它分解成几个可读的位来保持它更简单。

    希望这会有所帮助。

    【讨论】:

    • 感谢您的回答。不幸的是,这行不通,因为供应商和订单之间没有直接关系,这意味着要复制供应商和订单的信息存储位置。
    猜你喜欢
    • 1970-01-01
    • 2020-01-12
    • 2015-01-27
    • 2015-04-18
    • 2019-01-02
    • 2015-10-19
    • 2022-01-09
    • 2016-12-21
    • 1970-01-01
    相关资源
    最近更新 更多