> */ public function popularPreview(int $limit = 10): array { $limit = max(1, min($limit, 30)); $sql = $this->previewSelectSql( 'ORDER BY p.sales_count DESC, RAND()', $limit ); $statement = $this->pdo()->query($sql); return $this->attachPriceTiers($statement->fetchAll()); } /** * @return array> */ public function catalogPreview(int $limit = 24): array { $limit = max(1, min($limit, 60)); $sql = $this->previewSelectSql( 'ORDER BY p.sort_order, p.name', $limit ); $statement = $this->pdo()->query($sql); return $this->attachPriceTiers($statement->fetchAll()); } private function previewSelectSql(string $orderBy, int $limit): string { return 'SELECT p.id, p.name, p.slug, p.legacy_path, p.h1, p.seo_title, p.seo_description, p.seo_keywords, c.name AS category_name, c.slug AS category_slug, p.main_image_path, p.base_unit, p.package_display_mode, p.sales_count, v.id AS variant_id, v.name AS variant_name, v.unit, v.package_quantity, v.price_per_unit, v.package_price FROM products p LEFT JOIN categories c ON c.id = p.category_id LEFT JOIN product_variants v ON v.id = ( SELECT pv.id FROM product_variants pv WHERE pv.product_id = p.id AND pv.is_published = 1 AND pv.is_available = 1 ORDER BY pv.is_default DESC, pv.sort_order, pv.id LIMIT 1 ) WHERE p.is_published = 1 AND p.is_available = 1 ' . $orderBy . ' LIMIT ' . $limit; } /** * @param array> $products * @return array> */ private function attachPriceTiers(array $products): array { $priceTierService = new PriceTierService(); foreach ($products as &$product) { $basePrice = $product['price_per_unit'] ?? $product['package_price'] ?? null; $product['price_tiers'] = $basePrice === null ? [] : $priceTierService->forAmount((float) $basePrice); } unset($product); return $products; } }