Php 从Laravel中的子级获取父级,无需额外查询

Php 从Laravel中的子级获取父级,无需额外查询,php,laravel,Php,Laravel,我正在尝试用两种型号制作一个小型系统:Product,ProductPrice 以下是产品型号: class Product extends Model { protected $with = ['prices']; public $tax_rate = 0.2; public function prices () { return $this->hasMany(ProductPrice::class); } } 为了更清楚,我

我正在尝试用两种型号制作一个小型系统:
Product
ProductPrice

以下是产品型号:

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

    public $tax_rate = 0.2;

    public function prices ()
    {
        return $this->hasMany(ProductPrice::class);
    }
}
为了更清楚,我将
税率设置为常量,但在现实世界中,它是由另一个关系处理的

这里最重要的是
税率是
产品
模型的一个属性

以下是
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
属性


因此,如果我通过父级访问
ProductPrice
模型中的
产品,并且不进行额外查询,那么我可以访问
产品
父级

因此,我用手工解决方案解决了这个问题,不确定是否实现,但它的工作方式与我希望的一样

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

所以,我用一个手工解决方案解决了这个问题,不确定是否能实现,但它的工作方式和我希望的一样

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