db = $db; } public function listForAdmin( array $filters, string $sortColumn = 'id', string $sortDir = 'ASC', int $page = 1, int $perPage = 15 ): array { $allowedSortColumns = [ 'id' => 'u.id', 'text' => 'text', ]; $sortSql = $allowedSortColumns[$sortColumn] ?? 'u.id'; $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 = []; $text = trim((string)($filters['text'] ?? '')); if (strlen($text) > 255) { $text = substr($text, 0, 255); } if ($text !== '') { $where[] = 'EXISTS (SELECT 1 FROM pp_units_langs AS ul2 WHERE ul2.unit_id = u.id AND ul2.text LIKE :text)'; $params[':text'] = '%' . $text . '%'; } $whereSql = implode(' AND ', $where); $sqlCount = " SELECT COUNT(0) FROM pp_units AS u WHERE {$whereSql} "; $stmtCount = $this->db->query($sqlCount, $params); $countRows = $stmtCount ? $stmtCount->fetchAll() : []; $total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0; $sql = " SELECT u.*, ( SELECT ul.text FROM pp_units_langs AS ul INNER JOIN pp_langs AS l ON l.id = ul.lang_id WHERE ul.unit_id = u.id AND ul.text <> '' ORDER BY l.o ASC LIMIT 1 ) AS text FROM pp_units AS u WHERE {$whereSql} ORDER BY {$sortSql} {$sortDir}, u.id {$sortDir} LIMIT {$perPage} OFFSET {$offset} "; $stmt = $this->db->query($sql, $params); $items = $stmt ? $stmt->fetchAll() : []; return [ 'items' => is_array($items) ? $items : [], 'total' => $total, ]; } public function allUnits(): array { $sql = " SELECT u.*, ( SELECT ul.text FROM pp_units_langs AS ul INNER JOIN pp_langs AS l ON l.id = ul.lang_id WHERE ul.unit_id = u.id AND ul.text <> '' ORDER BY l.o ASC LIMIT 1 ) AS text FROM pp_units AS u ORDER BY u.id ASC "; $stmt = $this->db->query($sql); $rows = $stmt ? $stmt->fetchAll(\PDO::FETCH_ASSOC) : []; if (!is_array($rows)) { return []; } $units = []; foreach ($rows as $row) { $units[(int)$row['id']] = $row; } return $units; } public function find(int $unitId): ?array { $unit = $this->db->get('pp_units', '*', ['id' => $unitId]); if (!$unit) { return null; } $unit['languages'] = []; $translations = $this->db->select('pp_units_langs', '*', [ 'unit_id' => $unitId, 'ORDER' => ['lang_id' => 'ASC', 'id' => 'ASC'], ]); if (is_array($translations)) { foreach ($translations as $row) { $unit['languages'][(string)$row['lang_id']] = $row; } } return $unit; } public function save(array $data) { $unitId = isset($data['id']) ? (int)$data['id'] : 0; if ($unitId <= 0) { $this->db->insert('pp_units', []); $unitId = (int)$this->db->id(); if ($unitId <= 0) { return false; } } $translations = $this->normalizeTranslations($data); foreach ($translations as $langId => $text) { $this->upsertTranslation($unitId, $langId, $text); } $this->clearCache(); return $unitId; } public function delete(int $unitId): bool { if ($unitId <= 0) { return false; } $this->db->delete('pp_units_langs', ['unit_id' => $unitId]); $result = $this->db->delete('pp_units', ['id' => $unitId]); $this->clearCache(); return $result !== false; } public function getUnitNameById(int $unitId, $langId): string { $langId = trim((string)$langId); if ($unitId <= 0 || $langId === '') { return ''; } $cacheKey = "get_name_by_id:$unitId:$langId"; $unitName = $this->cacheFetch($cacheKey); if ($unitName === false) { $unitName = $this->db->get('pp_units_langs', 'text', [ 'AND' => [ 'unit_id' => $unitId, 'lang_id' => $langId, ], ]); $this->cacheStore($cacheKey, $unitName ?: ''); } return (string)$unitName; } private function normalizeTranslations(array $data): array { $translations = []; if (isset($data['translations']) && is_array($data['translations'])) { foreach ($data['translations'] as $langId => $fields) { $translations[(string)$langId] = trim((string)($fields['text'] ?? '')); } return $translations; } if (isset($data['text']) && is_array($data['text'])) { foreach ($data['text'] as $langId => $text) { $translations[(string)$langId] = trim((string)$text); } } return $translations; } private function upsertTranslation(int $unitId, $langId, string $text): void { $langId = trim((string)$langId); if ($langId === '') { return; } $translationId = $this->db->get('pp_units_langs', 'id', [ 'AND' => [ 'unit_id' => $unitId, 'lang_id' => $langId, ], ]); if ($translationId) { $this->db->update('pp_units_langs', [ 'text' => $text, ], [ 'id' => (int)$translationId, ]); return; } $this->db->insert('pp_units_langs', [ 'unit_id' => $unitId, 'lang_id' => $langId, 'text' => $text, ]); } private function clearCache(): void { \Shared\Helpers\Helpers::delete_dir('../temp/'); \Shared\Helpers\Helpers::delete_dir('../temp/dictionaries'); } private function cacheFetch(string $key) { $cacheHandler = new \Shared\Cache\CacheHandler(); $cached = $cacheHandler->get(self::CACHE_SUBDIR . ':' . $key); if ($cached) { return unserialize($cached); } return false; } private function cacheStore(string $key, string $value): void { $cacheHandler = new \Shared\Cache\CacheHandler(); $cacheHandler->set(self::CACHE_SUBDIR . ':' . $key, $value, self::CACHE_TTL); } }