Как представить средние значения и другие агрегаты в ООП?

У меня есть модель под названием Product. Product помимо прочего имеет цену, категорию и дату создания.

Я хочу показать таблицу, показывающую среднюю цену и средний возраст по категориям во многих местах. Иногда мне нужна только одна категория, иногда все, иногда только товары, которые были в наличии более определенного времени и т. д.

На данный момент я использую Laravel Query Builder для генерации этих чисел в моем контроллере, а затем передаю их в представление.

Чтобы попытаться повторно использовать его, у меня есть это в методах, прежде чем мне это понадобится:

$product_averages_base_query = DB::table('products')
    ->leftJoin('categories', 'products.MakeDescription', '=', 'categories.id')
    ->select(
        DB::raw('count(products.id) as TotalNumber'),
        DB::raw('AVG(Datediff("'.date('Y-m-d').'",products.created)) as AvgDaysInStock'),
        DB::raw('AVG(Price) as AvgPrice')
    );

Затем, когда для конкретного случая использования я использую:

$averages = $product_averages_base_query->where('categories.name', '=', 'Example 1')->get();

или любой другой вариант.

Это кажется действительно «неправильным», потому что я, конечно, в конечном итоге копирую этот код повсюду.

Как мне представить эти данные таким образом, чтобы мне было легче их повторно использовать? Должен ли я иметь класс? Как он должен называться и что в нем?

Должен ли я как-то иметь модель?

Любые советы приветствуются!


person Rich Bradshaw    schedule 03.09.2014    source источник


Ответы (2)


Что касается подходящего места, вы можете очень легко использовать области запроса и удалить все в своей модели. Вероятно, вы захотите начать с базового запроса...

public function scopeBaseQuery($query)
{
    return $query->leftJoin('categories', 'products.MakeDescription', '=', 'categories.id')
        ->select(
            DB::raw('count(products.id) as TotalNumber'),
            DB::raw('AVG(Datediff("'.date('Y-m-d').'",products.created)) as AvgDaysInStock'),
            DB::raw('AVG(Price) as AvgPrice')
        );
}

А затем продолжите с областью имени категории...

public function scopeOfName($query, $name)
{
    return $query->where('categories.name', $name);
}

Добавьте дополнительные области по мере необходимости.

Тогда использовать это было бы довольно легко...

$averages = Product::baseQuery()->ofName('Example 1')->get();
person user1669496    schedule 03.09.2014
comment
Но имеет ли это смысл, поскольку это не свойство Продукта, а свойство всех Продуктов? - person Rich Bradshaw; 03.09.2014

Одним из решений было бы создать класс Eloquent для модели, а затем поместить функциональность в область видимости.

class Product extends Eloquent {

    public function scopeAveragesByCategoryName($q, $catName) {
        return $q->leftJoin('categories', 'products.MakeDescription', '=', 'categories.id')
                 ->select(DB::raw('count(products.id) as TotalNumber'),
                          DB::raw('AVG(Datediff("'.date('Y-m-d').'",products.created)) as AvgDaysInStock'),
                          DB::raw('AVG(Price) as AvgPrice'))
                 ->where('categories.name', '=', $catName);
    }

}

$products = Product::averagesByCategoryName('Example 1')->get();
var_dump($products);

Или вы могли бы так же легко поместить все это в функцию.

person Dave    schedule 03.09.2014