在没有额外查询的情况下从Laravel的Child获取Parent

时间:2016-10-09 17:37:16

标签: php laravel

我正在尝试制作一个包含两个模型的小型系统:ProductProductPrice

以下是产品型号:

class Product extends Model
{
    protected $with = ['prices'];

    public $tax_rate = 0.2;

    public function prices ()
    {
        return $this->hasMany(ProductPrice::class);
    }
}

我将tax_rate常量放在此处以获得更清晰,但在现实世界中,它由另一种关系处理。

最重要的是,tax_rateProduct模型的属性

以下是ProductPrice型号:

class ProductPrice extends Model
{
    protected $appends = ['tax_included_price'];

    public function getTaxIncludedPriceAttribute()
    {
        return (1 + $this->product->tax_rate) * $this->price;
    }

    public function product ()
    {
        return $this->belongsTo(Product::class);
    }
}

现在让我们想象一下,我需要在某些模型上使用$product->toArray()。在这个例子中,我将得到一个无限循环的异常,因为我的getTaxIncludedPriceAttribute()方法发出了一个新的请求来查找product属性。

我可以访问Product模型中的ProductPrice父级,如果我通过父级访问它,而无需进行额外查询

1 个答案:

答案 0 :(得分:0)

所以,我用一个手工制作的解决方案解决了这个问题,不确定实现,但它的工作原理就像我希望它能够工作一样。

class Product extends Model
{
    protected $with = ['pricesRelation'];

    protected $appends = ['prices'];

    public $tax_rate = 0.2;

    public function pricesRelation ()
    {
        return $this->hasMany(ProductPrice::class);
    }

    public function getPricesAttribute ()
    {
        $collection = new Collection();

        foreach($this->pricesRelation as $relation) {
            $relation->loadProduct($this);
            $collection->add($relation);
        }

        return $relation;
    }
}

如您所见,我运行$relation->loadProduct($this);来定义父关系,而无需重新查询...

class ProductPrice extends Model
{
    protected $appends = ['tax_included_price'];

    protected $loaded_product;

    public function getTaxIncludedPriceAttribute()
    {
        $tax_rate = is_null($loaded_product) ? $this->product->tax_rate : $this->loaded_product->tax_rate;
        return (1 + $tax_rate) * $this->price;
    }

    public function loadProduct (Product $product) 
    {
        $this->loaded_product = $product;
    }

    public function product ()
    {
        return $this->belongsTo(Product::class);
    }
}