以正确的方式在模型中进行热切加载和范围

时间:2021-02-06 11:11:02

标签: laravel eager-loading

基本上,我尽可能地遵循胖模型和瘦控制器的原则。我想出了这个想法: 在我网站上的许多页面上,我想加载我所有的产品,但我想指出我想要加载的关系,因为我并不总是需要它们。 这是我支持的函数,如果我将任何参数设置为 true,它会急切地加载该关系,以便我尽可能高效地进行查询。

public static function getProducts($brand = null, $categories = null, $image = null, $images = null, $tags = null, $ratings = null, $attributes = null)
{
 $query = Product::query();

 if ($brand) {
 $query->whereHas('brand', $brand = function ($query) {
 $query->where('active', 1);
        })->with('brand', $brand);
    }

 if ($image) {
 $query->whereHas('images', $images = function ($query) {
 $query->where('active', 1)->where('main', 1);
        })->with('images', $images);
    }

 if ($images) {
 $query->whereHas('images', $images = function ($query) {
 $query->where('active', 1);
        })->with('images', $images);
    }

 if ($tags) {
 $query->whereHas('tags', $tags = function ($query) {
 $query->where('active', 1);
        })->with('tags', $tags);
    }

 if ($categories) {
 $query->whereHas('categories', $categories = function ($query) {
 $query->where('active', 1);
        })->with('categories', $categories);
    }

 if ($ratings) {
 $query->whereHas('ratings', $ratings = function ($query) {
 $query->where('active', 1);
        })->with('ratings', $ratings);
    }

 if ($attributes) {
 $query->whereHas('attributes', $attributes = function ($query) {
 $query->where('active', 1);
        })->with('attributes', $attributes);
    }

 return $query;
}

我不知道所有 whereHas() 是否都像我想象的那样高效,因为每次我急切加载关系时它都像 1 个子查询一样。 这解决了我必须在控制器中一直执行 ->with() 的问题,但想象一下我还想按特定类别或几个类别进行过滤。 我可以为此使用范围吗? 假设我只想获得活性产品,我可以在模型中创建这个函数:

public function scopeActive($query)
{
    return $query->where('active', 1);
}

拿到我的产品后这样称呼它:

$query = Product::getProducts(false, false, false, false, false, false, false)
$query->active();

或者,如果我想按类别过滤,我可以在产品模型中创建此函数:

public function scopeCategories($query, $categories)
{
 $query->with(['categories' => function ($query) use ($categories) {
 $query->whereIn('categories', $categories);
    }]);

 return $query;
}

然后再次调用它以过滤仅属于那些类别/类别的产品。

$query->categories($categoryIds);

我正在模型中完成所有这些工作,因此我可以从控制器调用该函数 1 次,预先加载我想要的关系,然后按我需要的进行过滤。但我不知道这是否是最好的方法。这是正确的做法吗?

我正在努力进入中级水平,并且尝试抽象一切比我想象的更难。

提前致谢!

0 个答案:

没有答案