db = $db; } /** * Lista producentów dla panelu admin (paginowana, filtrowalna, sortowalna). * * @return array{items: array>, total: int} */ public function listForAdmin( array $filters, string $sortColumn = 'name', string $sortDir = 'ASC', int $page = 1, int $perPage = 15 ): array { $allowedSortColumns = [ 'id' => 'p.id', 'name' => 'p.name', 'status' => 'p.status', ]; $sortSql = $allowedSortColumns[$sortColumn] ?? 'p.name'; $sortDir = strtoupper(trim($sortDir)) === 'DESC' ? 'DESC' : 'ASC'; $page = max(1, $page); $perPage = min(self::MAX_PER_PAGE, max(1, $perPage)); $offset = ($page - 1) * $perPage; $where = ['1 = 1']; $params = []; $name = trim((string)($filters['name'] ?? '')); if ($name !== '') { if (strlen($name) > 255) { $name = substr($name, 0, 255); } $where[] = 'p.name LIKE :name'; $params[':name'] = '%' . $name . '%'; } $status = trim((string)($filters['status'] ?? '')); if ($status === '0' || $status === '1') { $where[] = 'p.status = :status'; $params[':status'] = (int)$status; } $whereSql = implode(' AND ', $where); $sqlCount = " SELECT COUNT(0) FROM pp_shop_producer AS p WHERE {$whereSql} "; $stmtCount = $this->db->query($sqlCount, $params); $countRows = $stmtCount ? $stmtCount->fetchAll() : []; $total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0; $sql = " SELECT p.id, p.name, p.status, p.img FROM pp_shop_producer AS p WHERE {$whereSql} ORDER BY {$sortSql} {$sortDir}, p.id DESC LIMIT {$perPage} OFFSET {$offset} "; $stmt = $this->db->query($sql, $params); $items = $stmt ? $stmt->fetchAll() : []; if (!is_array($items)) { $items = []; } foreach ($items as &$item) { $item['id'] = (int)($item['id'] ?? 0); $item['status'] = $this->toSwitchValue($item['status'] ?? 0); } unset($item); return [ 'items' => $items, 'total' => $total, ]; } /** * Pobiera producenta z tłumaczeniami. */ public function find(int $id): array { if ($id <= 0) { return $this->defaultProducer(); } $producer = $this->db->get('pp_shop_producer', '*', ['id' => $id]); if (!is_array($producer)) { return $this->defaultProducer(); } $producer['id'] = (int)($producer['id'] ?? 0); $producer['status'] = $this->toSwitchValue($producer['status'] ?? 0); // Tłumaczenia $rows = $this->db->select('pp_shop_producer_lang', '*', ['producer_id' => $id]); $languages = []; if (is_array($rows)) { foreach ($rows as $row) { $langId = $row['lang_id'] ?? ''; $languages[$langId] = [ 'description' => $row['description'] ?? null, 'data' => $row['data'] ?? null, 'meta_title' => $row['meta_title'] ?? null, ]; } } $producer['languages'] = $languages; return $producer; } /** * Zapisuje producenta (insert / update) wraz z tłumaczeniami. * * @return int|null ID producenta lub null przy błędzie */ public function save( int $id, string $name, int $status, ?string $img, array $description, array $data, array $metaTitle, array $langs ): ?int { $row = [ 'name' => trim($name), 'status' => $status === 1 ? 1 : 0, 'img' => $img, ]; if ($id <= 0) { $this->db->insert('pp_shop_producer', $row); $id = (int)$this->db->id(); if ($id <= 0) { return null; } } else { $this->db->update('pp_shop_producer', $row, ['id' => $id]); } // Tłumaczenia foreach ($langs as $lg) { $langId = $lg['id'] ?? ''; $translationData = [ 'description' => $description[$langId] ?? null, 'data' => $data[$langId] ?? null, 'meta_title' => $metaTitle[$langId] ?? null, ]; $translationId = $this->db->get( 'pp_shop_producer_lang', 'id', ['AND' => ['producer_id' => $id, 'lang_id' => $langId]] ); if ($translationId) { $this->db->update('pp_shop_producer_lang', $translationData, ['id' => $translationId]); } else { $this->db->insert('pp_shop_producer_lang', array_merge($translationData, [ 'producer_id' => $id, 'lang_id' => $langId, ])); } } return $id; } /** * Usuwa producenta (kaskadowo z pp_shop_producer_lang przez FK). */ public function delete(int $id): bool { if ($id <= 0) { return false; } $result = (bool)$this->db->delete('pp_shop_producer', ['id' => $id]); return $result; } /** * Wszystkie producenty (do select w edycji produktu). * * @return array */ public function allProducers(): array { $rows = $this->db->select('pp_shop_producer', ['id', 'name'], ['ORDER' => ['name' => 'ASC']]); if (!is_array($rows)) { return []; } $producers = []; foreach ($rows as $row) { $producers[] = [ 'id' => (int)($row['id'] ?? 0), 'name' => (string)($row['name'] ?? ''), ]; } return $producers; } /** * Pobiera producenta z tłumaczeniami dla danego języka (frontend). */ public function findForFrontend(int $id, string $langId): ?array { if ($id <= 0) { return null; } $producer = $this->db->get('pp_shop_producer', '*', ['id' => $id]); if (!is_array($producer)) { return null; } $producer['id'] = (int)($producer['id'] ?? 0); $langRow = $this->db->get('pp_shop_producer_lang', '*', [ 'AND' => ['producer_id' => $id, 'lang_id' => $langId], ]); $producer['languages'] = []; if (is_array($langRow)) { $producer['languages'][$langId] = [ 'description' => $langRow['description'] ?? null, 'data' => $langRow['data'] ?? null, 'meta_title' => $langRow['meta_title'] ?? null, ]; } return $producer; } /** * Produkty producenta (paginowane) — frontend. * * @return array{products: array, ls: int} */ public function producerProducts(int $producerId, int $perPage = 12, int $page = 1): array { $count = $this->db->count('pp_shop_products', [ 'AND' => ['producer_id' => $producerId, 'status' => 1], ]); $totalPages = max(1, (int)ceil($count / $perPage)); $page = max(1, min($page, $totalPages)); $offset = $perPage * ($page - 1); $products = $this->db->select('pp_shop_products', 'id', [ 'AND' => ['producer_id' => $producerId, 'status' => 1], 'LIMIT' => [$offset, $perPage], ]); return [ 'products' => is_array($products) ? $products : [], 'ls' => $totalPages, ]; } /** * Aktywni producenci (frontend lista). * * @return array */ public function allActiveIds(): array { $rows = $this->db->select('pp_shop_producer', 'id', [ 'status' => 1, 'ORDER' => ['name' => 'ASC'], ]); return is_array($rows) ? array_map('intval', $rows) : []; } /** * Aktywni producenci z pelnym danymi (frontend lista). * * @return array */ public function allActiveProducers(): array { $rows = $this->db->select('pp_shop_producer', ['id', 'name', 'img'], [ 'status' => 1, 'ORDER' => ['name' => 'ASC'], ]); if (!is_array($rows)) { return []; } $producers = []; foreach ($rows as $row) { $producers[] = [ 'id' => (int)($row['id'] ?? 0), 'name' => (string)($row['name'] ?? ''), 'img' => $row['img'] ?? null, ]; } return $producers; } private function defaultProducer(): array { return [ 'id' => 0, 'name' => '', 'status' => 1, 'img' => null, 'languages' => [], ]; } private function toSwitchValue($value): int { if (is_bool($value)) { return $value ? 1 : 0; } if (is_numeric($value)) { return ((int)$value) === 1 ? 1 : 0; } if (is_string($value)) { $normalized = strtolower(trim($value)); return in_array($normalized, ['1', 'on', 'true', 'yes'], true) ? 1 : 0; } return 0; } /** * Znajdź producenta po nazwie lub utwórz nowego (dla API). * * @return array{id: int, created: bool} */ public function ensureProducerForApi(string $name): array { $name = trim($name); if ($name === '') { return ['id' => 0, 'created' => false]; } $existing = $this->db->get('pp_shop_producer', 'id', ['name' => $name]); if (!empty($existing)) { return ['id' => (int)$existing, 'created' => false]; } $this->db->insert('pp_shop_producer', [ 'name' => $name, 'status' => 1, 'img' => null, ]); $id = (int)$this->db->id(); if ($id <= 0) { return ['id' => 0, 'created' => false]; } return ['id' => $id, 'created' => true]; } }