*/ private const PAGE_TYPES = [ 0 => 'pelne artykuly', 1 => 'wprowadzenia', 2 => 'miniaturki', 3 => 'link', 4 => 'kontakt', 5 => 'kategoria sklepu', ]; /** * @var array */ private const SORT_TYPES = [ 0 => 'data dodania - najstarsze na poczatku', 1 => 'data dodania - najnowsze na poczatku', 2 => 'data modyfikacji - rosnaco', 3 => 'data modyfikacji - malejaco', 4 => 'reczne', 5 => 'alfabetycznie - A - Z', 6 => 'alfabetycznie - Z - A', ]; private $db; public function __construct($db) { $this->db = $db; } /** * @return array */ public function pageTypes(): array { return self::PAGE_TYPES; } /** * @return array */ public function sortTypes(): array { return self::SORT_TYPES; } /** * @return array> */ public function menusList(): array { $rows = $this->db->select('pp_menus', '*', ['ORDER' => ['id' => 'ASC']]); return is_array($rows) ? $rows : []; } /** * @return array> */ public function menusWithPages(): array { $menus = $this->menusList(); foreach ($menus as $index => $menu) { $menuId = (int)($menu['id'] ?? 0); $menus[$index]['pages'] = $this->menuPages($menuId); } return $menus; } /** * @return array> */ public function menuPages(int $menuId, ?int $parentId = null): array { if ($menuId <= 0) { return []; } $rows = $this->db->select('pp_pages', ['id', 'menu_id', 'status', 'parent_id', 'start'], [ 'AND' => [ 'menu_id' => $menuId, 'parent_id' => $parentId, ], 'ORDER' => ['o' => 'ASC'], ]); if (!is_array($rows)) { return []; } $pages = []; foreach ($rows as $row) { $pageId = (int)($row['id'] ?? 0); if ($pageId <= 0) { continue; } $row['title'] = $this->pageTitle($pageId); $row['languages'] = $this->pageLanguages($pageId); $row['subpages'] = $this->menuPages($menuId, $pageId); $pages[] = $row; } return $pages; } public function menuDelete(int $menuId): bool { if ($menuId <= 0) { return false; } if ((int)$this->db->count('pp_pages', ['menu_id' => $menuId]) > 0) { return false; } return (bool)$this->db->delete('pp_menus', ['id' => $menuId]); } public function pageDelete(int $pageId): bool { if ($pageId <= 0) { return false; } if ((int)$this->db->count('pp_pages', ['parent_id' => $pageId]) > 0) { return false; } return (bool)$this->db->delete('pp_pages', ['id' => $pageId]); } /** * @return array */ public function menuDetails(int $menuId): array { if ($menuId <= 0) { return [ 'id' => 0, 'name' => '', 'status' => 1, ]; } $menu = $this->db->get('pp_menus', '*', ['id' => $menuId]); if (!is_array($menu)) { return [ 'id' => 0, 'name' => '', 'status' => 1, ]; } return $menu; } public function menuSave(int $menuId, string $name, $status): bool { $statusValue = $this->toSwitchValue($status); if ($menuId <= 0) { $result = $this->db->insert('pp_menus', [ 'name' => $name, 'status' => $statusValue, ]); if ($result) { \S::delete_dir('../temp/'); } return (bool)$result; } $this->db->update('pp_menus', [ 'name' => $name, 'status' => $statusValue, ], [ 'id' => $menuId, ]); \S::delete_dir('../temp/'); return true; } /** * @return array */ public function pageDetails(int $pageId): array { if ($pageId <= 0) { return $this->defaultPage(); } $page = $this->db->get('pp_pages', '*', ['id' => $pageId]); if (!is_array($page)) { return $this->defaultPage(); } $translations = $this->db->select('pp_pages_langs', '*', ['page_id' => $pageId]); if (is_array($translations)) { foreach ($translations as $row) { $langId = (string)($row['lang_id'] ?? ''); if ($langId !== '') { $page['languages'][$langId] = $row; } } } $page['layout_id'] = (int)$this->db->get('pp_layouts_pages', 'layout_id', ['page_id' => $pageId]); return $page; } /** * @return array> */ public function pageArticles(int $pageId): array { if ($pageId <= 0) { return []; } $sql = ' SELECT ap.article_id, ap.o, a.status, ( SELECT title FROM pp_articles_langs AS pal JOIN pp_langs AS pl ON pal.lang_id = pl.id WHERE pal.article_id = ap.article_id AND pal.title != "" ORDER BY pl.o ASC LIMIT 1 ) AS title FROM pp_articles_pages AS ap JOIN pp_articles AS a ON a.id = ap.article_id WHERE ap.page_id = :page_id AND a.status != -1 ORDER BY ap.o ASC '; $stmt = $this->db->query($sql, [':page_id' => $pageId]); $rows = $stmt ? $stmt->fetchAll() : []; return is_array($rows) ? $rows : []; } public function saveArticlesOrder(int $pageId, $articles): bool { if ($pageId <= 0) { return false; } if (!is_array($articles)) { return true; } $this->db->update('pp_articles_pages', ['o' => 0], ['page_id' => $pageId]); $position = 0; foreach ($articles as $item) { $articleId = (int)($item['item_id'] ?? 0); if ($articleId <= 0) { continue; } $position++; $this->db->update('pp_articles_pages', ['o' => $position], [ 'AND' => [ 'page_id' => $pageId, 'article_id' => $articleId, ], ]); } \S::delete_dir('../temp/'); return true; } public function savePagesOrder(int $menuId, $pages): bool { if ($menuId <= 0) { return false; } if (!is_array($pages)) { return true; } $this->db->update('pp_pages', ['o' => 0], ['menu_id' => $menuId]); $position = 0; foreach ($pages as $item) { $itemId = (int)($item['item_id'] ?? 0); $depth = (int)($item['depth'] ?? 0); if ($itemId <= 0 || $depth <= 1) { continue; } $parentId = (int)($item['parent_id'] ?? 0); if ($depth === 2) { $parentId = null; } $position++; $this->db->update('pp_pages', [ 'o' => $position, 'parent_id' => $parentId, ], [ 'id' => $itemId, ]); } \S::delete_dir('../temp/'); return true; } public function pageSave(array $data): ?int { $pageId = (int)($data['id'] ?? 0); $menuId = (int)($data['menu_id'] ?? 0); $parentId = $this->normalizeNullableInt($data['parent_id'] ?? null); $pageType = (int)($data['page_type'] ?? 0); $sortType = (int)($data['sort_type'] ?? 0); $layoutId = (int)($data['layout_id'] ?? 0); $articlesLimit = (int)($data['articles_limit'] ?? 0); $showTitle = $this->toSwitchValue($data['show_title'] ?? 0); $status = $this->toSwitchValue($data['status'] ?? 0); $start = $this->toSwitchValue($data['start'] ?? 0); $categoryId = $this->normalizeNullableInt($data['category_id'] ?? null); if ($pageType !== 5) { $categoryId = null; } if ($pageId <= 0) { $order = $this->maxPageOrder() + 1; $result = $this->db->insert('pp_pages', [ 'menu_id' => $menuId, 'page_type' => $pageType, 'sort_type' => $sortType, 'articles_limit' => $articlesLimit, 'show_title' => $showTitle, 'status' => $status, 'o' => $order, 'parent_id' => $parentId, 'start' => $start, 'category_id' => $categoryId, ]); if (!$result) { return null; } $pageId = (int)$this->db->id(); if ($pageId <= 0) { return null; } } else { $this->db->update('pp_pages', [ 'menu_id' => $menuId, 'page_type' => $pageType, 'sort_type' => $sortType, 'articles_limit' => $articlesLimit, 'show_title' => $showTitle, 'status' => $status, 'parent_id' => $parentId, 'start' => $start, 'category_id' => $categoryId, ], [ 'id' => $pageId, ]); } if ($start === 1) { $this->db->update('pp_pages', ['start' => 0], ['id[!]' => $pageId]); $this->db->update('pp_pages', ['start' => 1], ['id' => $pageId]); } $this->db->delete('pp_layouts_pages', ['page_id' => $pageId]); if ($layoutId > 0) { $this->db->insert('pp_layouts_pages', [ 'layout_id' => $layoutId, 'page_id' => $pageId, ]); } $this->saveTranslations($pageId, $pageType, $data); $this->updateSubpagesMenuId($pageId, $menuId); \S::htacces(); \S::delete_dir('../temp/'); return $pageId; } public function generateSeoLink(string $title, int $pageId = 0, int $articleId = 0, int $categoryId = 0): string { $base = trim((string)\S::seo($title)); if ($base === '') { return ''; } $candidate = $base; $suffix = 0; while ($this->isSeoLinkUsed('pp_pages_langs', 'page_id', $candidate, $pageId) || $this->isSeoLinkUsed('pp_articles_langs', 'article_id', $candidate, $articleId) || $this->isSeoLinkUsed('pp_shop_categories_langs', 'category_id', $candidate, $categoryId)) { $suffix++; $candidate = $base . '-' . $suffix; } return $candidate; } public function pageUrlPreview(int $pageId, string $langId, string $title, string $seoLink, string $defaultLanguageId): string { $url = trim($seoLink) !== '' ? '/' . ltrim($seoLink, '/') : '/s-' . $pageId . '-' . \S::seo($title); if ($langId !== '' && $langId !== $defaultLanguageId && $url !== '#') { $url = '/' . $langId . $url; } return $url; } public function toggleCookieValue(string $cookieName, int $itemId): void { if ($cookieName === '' || $itemId <= 0) { return; } $state = []; if (!empty($_COOKIE[$cookieName])) { $decoded = @unserialize((string)$_COOKIE[$cookieName], ['allowed_classes' => false]); if (is_array($decoded)) { $state = $decoded; } } $state[$itemId] = empty($state[$itemId]) ? 1 : 0; setcookie($cookieName, serialize($state), time() + 3600 * 24 * 365); } public function pageTitle(int $pageId): string { if ($pageId <= 0) { return ''; } $rows = $this->db->select('pp_pages_langs', [ '[><]pp_langs' => ['lang_id' => 'id'], ], 'title', [ 'AND' => [ 'page_id' => $pageId, 'title[!]' => '', ], 'ORDER' => ['o' => 'ASC'], 'LIMIT' => 1, ]); if (!is_array($rows) || !isset($rows[0])) { return ''; } return (string)$rows[0]; } /** * @return array> */ public function pageLanguages(int $pageId): array { if ($pageId <= 0) { return []; } $rows = $this->db->select('pp_pages_langs', '*', [ 'AND' => [ 'page_id' => $pageId, 'title[!]' => null, ], ]); return is_array($rows) ? $rows : []; } /** * @return array */ private function defaultPage(): array { return [ 'id' => 0, 'menu_id' => 0, 'page_type' => 0, 'sort_type' => 0, 'articles_limit' => 2, 'show_title' => 1, 'status' => 1, 'start' => 0, 'parent_id' => null, 'category_id' => null, 'layout_id' => 0, 'languages' => [], ]; } private function saveTranslations(int $pageId, int $pageType, array $data): void { $titles = is_array($data['title'] ?? null) ? $data['title'] : []; $seoLinks = is_array($data['seo_link'] ?? null) ? $data['seo_link'] : []; $metaTitles = is_array($data['meta_title'] ?? null) ? $data['meta_title'] : []; $metaDescriptions = is_array($data['meta_description'] ?? null) ? $data['meta_description'] : []; $metaKeywords = is_array($data['meta_keywords'] ?? null) ? $data['meta_keywords'] : []; $noindexValues = is_array($data['noindex'] ?? null) ? $data['noindex'] : []; $pageTitles = is_array($data['page_title'] ?? null) ? $data['page_title'] : []; $links = is_array($data['link'] ?? null) ? $data['link'] : []; $canonicals = is_array($data['canonical'] ?? null) ? $data['canonical'] : []; foreach ($titles as $langId => $title) { $langId = (string)$langId; if ($langId === '') { continue; } $row = [ 'lang_id' => $langId, 'title' => $this->nullIfEmpty($title), 'meta_description' => $this->nullIfEmpty($metaDescriptions[$langId] ?? null), 'meta_keywords' => $this->nullIfEmpty($metaKeywords[$langId] ?? null), 'meta_title' => $this->nullIfEmpty($metaTitles[$langId] ?? null), 'seo_link' => $this->nullIfEmpty(\S::seo((string)($seoLinks[$langId] ?? ''))), 'noindex' => (int)($noindexValues[$langId] ?? 0), 'page_title' => $this->nullIfEmpty($pageTitles[$langId] ?? null), 'link' => $pageType === 3 ? $this->nullIfEmpty($links[$langId] ?? null) : null, 'canonical' => $this->nullIfEmpty($canonicals[$langId] ?? null), ]; $translationId = (int)$this->db->get('pp_pages_langs', 'id', [ 'AND' => [ 'page_id' => $pageId, 'lang_id' => $langId, ], ]); if ($translationId > 0) { $this->db->update('pp_pages_langs', $row, ['id' => $translationId]); } else { $row['page_id'] = $pageId; $this->db->insert('pp_pages_langs', $row); } } } private function updateSubpagesMenuId(int $parentId, int $menuId): void { if ($parentId <= 0 || $menuId <= 0) { return; } $this->db->update('pp_pages', ['menu_id' => $menuId], ['parent_id' => $parentId]); $children = $this->db->select('pp_pages', ['id'], ['parent_id' => $parentId]); if (!is_array($children)) { return; } foreach ($children as $row) { $childId = (int)($row['id'] ?? 0); if ($childId > 0) { $this->updateSubpagesMenuId($childId, $menuId); } } } private function isSeoLinkUsed(string $table, string $idColumn, string $seoLink, int $exceptId): bool { $where = [ 'seo_link' => $seoLink, ]; if ($exceptId > 0) { $where[$idColumn . '[!]'] = $exceptId; } return (int)$this->db->count($table, ['AND' => $where]) > 0; } private function maxPageOrder(): int { $max = $this->db->max('pp_pages', 'o'); return $max ? (int)$max : 0; } private function toSwitchValue($value): int { if ($value === 'on' || $value === '1' || $value === 1 || $value === true) { return 1; } return 0; } private function normalizeNullableInt($value): ?int { if ($value === null || $value === '' || (int)$value === 0) { return null; } return (int)$value; } private function nullIfEmpty($value): ?string { $value = trim((string)$value); return $value === '' ? null : $value; } }