db = $db; } /** * Pobiera stan magazynowy produktu * * @param int $productId ID produktu * @return int|null Ilość produktu lub null jeśli nie znaleziono */ public function getQuantity(int $productId): ?int { $quantity = $this->db->get('pp_shop_products', 'quantity', ['id' => $productId]); // Medoo zwraca false jeśli nie znaleziono return $quantity !== false ? (int)$quantity : null; } /** * Pobiera produkt po ID * * @param int $productId ID produktu * @return array|null Dane produktu lub null */ public function find(int $productId): ?array { $product = $this->db->get('pp_shop_products', '*', ['id' => $productId]); return $product ?: null; } /** * Zwraca liste produktow z archiwum do panelu admin. * * @return array{items: array>, total: int} */ public function listArchivedForAdmin( array $filters, string $sortColumn = 'id', string $sortDir = 'DESC', int $page = 1, int $perPage = 10 ): array { $allowedSortColumns = [ 'id' => 'psp.id', 'name' => 'name', 'price_brutto' => 'psp.price_brutto', 'price_brutto_promo' => 'psp.price_brutto_promo', 'quantity' => 'psp.quantity', 'combinations' => 'combinations', ]; $sortSql = $allowedSortColumns[$sortColumn] ?? 'psp.id'; $sortDir = strtoupper(trim($sortDir)) === 'ASC' ? 'ASC' : 'DESC'; $page = max(1, $page); $perPage = min(self::MAX_PER_PAGE, max(1, $perPage)); $offset = ($page - 1) * $perPage; $where = ['psp.archive = 1', 'psp.parent_id IS NULL']; $params = []; $phrase = trim((string)($filters['phrase'] ?? '')); if (strlen($phrase) > 255) { $phrase = substr($phrase, 0, 255); } if ($phrase !== '') { $where[] = '( psp.ean LIKE :phrase OR psp.sku LIKE :phrase OR EXISTS ( SELECT 1 FROM pp_shop_products_langs AS pspl2 WHERE pspl2.product_id = psp.id AND pspl2.name LIKE :phrase ) )'; $params[':phrase'] = '%' . $phrase . '%'; } $whereSql = implode(' AND ', $where); $sqlCount = " SELECT COUNT(0) FROM pp_shop_products AS psp WHERE {$whereSql} "; $stmtCount = $this->db->query($sqlCount, $params); $countRows = $stmtCount ? $stmtCount->fetchAll() : []; $total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0; $sql = " SELECT psp.id, psp.price_brutto, psp.price_brutto_promo, psp.quantity, psp.sku, psp.ean, ( SELECT pspl.name FROM pp_shop_products_langs AS pspl INNER JOIN pp_langs AS pl ON pl.id = pspl.lang_id WHERE pspl.product_id = psp.id AND pspl.name <> '' ORDER BY pl.o ASC LIMIT 1 ) AS name, ( SELECT pspi.src FROM pp_shop_products_images AS pspi WHERE pspi.product_id = psp.id ORDER BY pspi.o ASC, pspi.id ASC LIMIT 1 ) AS image_src, ( SELECT pspi.alt FROM pp_shop_products_images AS pspi WHERE pspi.product_id = psp.id ORDER BY pspi.o ASC, pspi.id ASC LIMIT 1 ) AS image_alt, ( SELECT COUNT(0) FROM pp_shop_products AS pspc WHERE pspc.parent_id = psp.id ) AS combinations FROM pp_shop_products AS psp WHERE {$whereSql} ORDER BY {$sortSql} {$sortDir}, psp.id {$sortDir} LIMIT {$perPage} OFFSET {$offset} "; $stmt = $this->db->query($sql, $params); $items = $stmt ? $stmt->fetchAll() : []; return [ 'items' => is_array($items) ? $items : [], 'total' => $total, ]; } /** * Pobiera cenę produktu (promocyjną jeśli jest niższa, w przeciwnym razie regularną) * * @param int $productId ID produktu * @return float|null Cena brutto lub null jeśli nie znaleziono */ public function getPrice(int $productId): ?float { $prices = $this->db->get('pp_shop_products', ['price_brutto', 'price_brutto_promo'], ['id' => $productId]); if (!$prices) { return null; } if ($prices['price_brutto_promo'] != '' && $prices['price_brutto_promo'] < $prices['price_brutto']) { return (float)$prices['price_brutto_promo']; } return (float)$prices['price_brutto']; } /** * Pobiera nazwę produktu w danym języku * * @param int $productId ID produktu * @param string $langId ID języka * @return string|null Nazwa produktu lub null jeśli nie znaleziono */ public function getName(int $productId, string $langId): ?string { $name = $this->db->get('pp_shop_products_langs', 'name', ['AND' => ['product_id' => $productId, 'lang_id' => $langId]]); return $name ?: null; } /** * Aktualizuje ilość produktu * * @param int $productId ID produktu * @param int $quantity Nowa ilość * @return bool Czy aktualizacja się powiodła */ public function updateQuantity(int $productId, int $quantity): bool { $result = $this->db->update( 'pp_shop_products', ['quantity' => $quantity], ['id' => $productId] ); return $result !== false; } /** * Przywraca produkt z archiwum (wraz z kombinacjami) * * @param int $productId ID produktu * @return bool Czy operacja się powiodła */ public function unarchive(int $productId): bool { $this->db->update( 'pp_shop_products', [ 'status' => 1, 'archive' => 0 ], [ 'id' => $productId ] ); $this->db->update( 'pp_shop_products', [ 'status' => 1, 'archive' => 0 ], [ 'parent_id' => $productId ] ); return true; } /** * Przenosi produkt do archiwum (wraz z kombinacjami) * * @param int $productId ID produktu * @return bool Czy operacja się powiodła */ public function archive(int $productId): bool { $this->db->update( 'pp_shop_products', [ 'status' => 0, 'archive' => 1 ], [ 'id' => $productId ] ); $this->db->update( 'pp_shop_products', [ 'status' => 0, 'archive' => 1 ], [ 'parent_id' => $productId ] ); return true; } }