844 lines
27 KiB
PHP
844 lines
27 KiB
PHP
<?php
|
|
namespace Domain\Article;
|
|
|
|
/**
|
|
* Repository odpowiedzialny za dostep do danych artykulow
|
|
*/
|
|
class ArticleRepository
|
|
{
|
|
private const MAX_PER_PAGE = 100;
|
|
|
|
private $db;
|
|
|
|
public function __construct($db)
|
|
{
|
|
$this->db = $db;
|
|
}
|
|
|
|
/**
|
|
* Pobiera artykul po ID wraz z tlumaczeniami, obrazami, plikami i powiazanymi stronami
|
|
*/
|
|
public function find(int $articleId): ?array
|
|
{
|
|
$article = $this->db->get('pp_articles', '*', ['id' => $articleId]);
|
|
|
|
if (!$article) {
|
|
return null;
|
|
}
|
|
|
|
$results = $this->db->select('pp_articles_langs', '*', ['article_id' => $articleId]);
|
|
if (is_array($results)) {
|
|
foreach ($results as $row) {
|
|
$article['languages'][$row['lang_id']] = $row;
|
|
}
|
|
}
|
|
|
|
$article['images'] = $this->db->select('pp_articles_images', '*', [
|
|
'article_id' => $articleId,
|
|
'ORDER' => ['o' => 'ASC', 'id' => 'DESC']
|
|
]);
|
|
try {
|
|
$article['files'] = $this->db->select('pp_articles_files', '*', [
|
|
'article_id' => $articleId,
|
|
'ORDER' => ['o' => 'ASC', 'id' => 'DESC']
|
|
]);
|
|
} catch (\Throwable $e) {
|
|
// Fallback for instances where pp_articles_files does not yet have "o" column.
|
|
$article['files'] = $this->db->select('pp_articles_files', '*', ['article_id' => $articleId]);
|
|
}
|
|
$article['pages'] = $this->db->select('pp_articles_pages', 'page_id', ['article_id' => $articleId]);
|
|
|
|
return $article;
|
|
}
|
|
|
|
/**
|
|
* Zapisuje artykul (tworzy nowy lub aktualizuje istniejacy).
|
|
* Zwraca ID artykulu.
|
|
*/
|
|
public function save(int $articleId, array $data, int $userId): int
|
|
{
|
|
if (!$articleId) {
|
|
return $this->createArticle($data, $userId);
|
|
}
|
|
|
|
return $this->updateArticle($articleId, $data, $userId);
|
|
}
|
|
|
|
private function createArticle(array $data, int $userId): int
|
|
{
|
|
$this->db->insert('pp_articles', $this->buildArticleRow($data, $userId, true));
|
|
|
|
$id = $this->db->id();
|
|
|
|
if (!$id) {
|
|
return 0;
|
|
}
|
|
|
|
$this->saveTranslations($id, $data, true);
|
|
$this->savePages($id, $data['pages'] ?? null, true);
|
|
$this->assignTempFiles($id);
|
|
$this->assignTempImages($id);
|
|
$this->applyGalleryOrderIfProvided($id, $data);
|
|
$this->applyFilesOrderIfProvided($id, $data);
|
|
|
|
\S::htacces();
|
|
\S::delete_dir('../temp/');
|
|
|
|
return (int)$id;
|
|
}
|
|
|
|
private function updateArticle(int $articleId, array $data, int $userId): int
|
|
{
|
|
$this->db->update('pp_articles', $this->buildArticleRow($data, $userId, false), [
|
|
'id' => $articleId
|
|
]);
|
|
|
|
$this->saveTranslations($articleId, $data, false);
|
|
$this->savePages($articleId, $data['pages'] ?? null, false);
|
|
$this->assignTempFiles($articleId);
|
|
$this->assignTempImages($articleId);
|
|
$this->applyGalleryOrderIfProvided($articleId, $data);
|
|
$this->applyFilesOrderIfProvided($articleId, $data);
|
|
$this->deleteMarkedImages($articleId);
|
|
$this->deleteMarkedFiles($articleId);
|
|
|
|
\S::htacces();
|
|
\S::delete_dir('../temp/');
|
|
|
|
return $articleId;
|
|
}
|
|
|
|
private function buildArticleRow(array $data, int $userId, bool $isNew): array
|
|
{
|
|
$row = [
|
|
'show_title' => $this->isCheckedValue($data['show_title'] ?? null) ? 1 : 0,
|
|
'show_date_add' => $this->isCheckedValue($data['show_date_add'] ?? null) ? 1 : 0,
|
|
'show_date_modify' => $this->isCheckedValue($data['show_date_modify'] ?? null) ? 1 : 0,
|
|
'date_modify' => date('Y-m-d H:i:s'),
|
|
'modify_by' => $userId,
|
|
'layout_id' => !empty($data['layout_id']) ? (int)$data['layout_id'] : null,
|
|
'status' => $this->isCheckedValue($data['status'] ?? null) ? 1 : 0,
|
|
'repeat_entry' => $this->isCheckedValue($data['repeat_entry'] ?? null) ? 1 : 0,
|
|
'social_icons' => $this->isCheckedValue($data['social_icons'] ?? null) ? 1 : 0,
|
|
'show_table_of_contents' => $this->isCheckedValue($data['show_table_of_contents'] ?? null) ? 1 : 0,
|
|
];
|
|
|
|
if ($isNew) {
|
|
$row['date_add'] = date('Y-m-d H:i:s');
|
|
}
|
|
|
|
return $row;
|
|
}
|
|
|
|
private function buildLangRow($langId, array $data): array
|
|
{
|
|
return [
|
|
'lang_id' => $langId,
|
|
'title' => ($data['title'][$langId] ?? '') != '' ? $data['title'][$langId] : null,
|
|
'main_image' => ($data['main_image'][$langId] ?? '') != '' ? $data['main_image'][$langId] : null,
|
|
'entry' => ($data['entry'][$langId] ?? '') != '' ? $data['entry'][$langId] : null,
|
|
'text' => ($data['text'][$langId] ?? '') != '' ? $data['text'][$langId] : null,
|
|
'table_of_contents' => ($data['table_of_contents'][$langId] ?? '') != '' ? $data['table_of_contents'][$langId] : null,
|
|
'meta_title' => ($data['meta_title'][$langId] ?? '') != '' ? $data['meta_title'][$langId] : null,
|
|
'meta_description' => ($data['meta_description'][$langId] ?? '') != '' ? $data['meta_description'][$langId] : null,
|
|
'meta_keywords' => ($data['meta_keywords'][$langId] ?? '') != '' ? $data['meta_keywords'][$langId] : null,
|
|
'seo_link' => \S::seo($data['seo_link'][$langId] ?? '') != '' ? \S::seo($data['seo_link'][$langId]) : null,
|
|
'noindex' => $this->isCheckedValue($data['noindex'][$langId] ?? null) ? 1 : 0,
|
|
'copy_from' => ($data['copy_from'][$langId] ?? '') != '' ? $data['copy_from'][$langId] : null,
|
|
'block_direct_access' => $this->isCheckedValue($data['block_direct_access'][$langId] ?? null) ? 1 : 0,
|
|
];
|
|
}
|
|
|
|
private function applyGalleryOrderIfProvided(int $articleId, array $data): void
|
|
{
|
|
$order = trim((string)($data['gallery_order'] ?? ''));
|
|
if ($order === '') {
|
|
return;
|
|
}
|
|
|
|
$this->saveGalleryOrder($articleId, $order);
|
|
}
|
|
|
|
private function applyFilesOrderIfProvided(int $articleId, array $data): void
|
|
{
|
|
$order = trim((string)($data['files_order'] ?? ''));
|
|
if ($order === '') {
|
|
return;
|
|
}
|
|
|
|
$this->saveFilesOrder($articleId, $order);
|
|
}
|
|
|
|
private function saveTranslations(int $articleId, array $data, bool $isNew): void
|
|
{
|
|
$titles = $data['title'] ?? [];
|
|
|
|
foreach ($titles as $langId => $val) {
|
|
$langRow = $this->buildLangRow($langId, $data);
|
|
|
|
if ($isNew) {
|
|
$langRow['article_id'] = $articleId;
|
|
$this->db->insert('pp_articles_langs', $langRow);
|
|
} else {
|
|
$translationId = $this->db->get('pp_articles_langs', 'id', [
|
|
'AND' => ['article_id' => $articleId, 'lang_id' => $langId]
|
|
]);
|
|
|
|
if ($translationId) {
|
|
$this->db->update('pp_articles_langs', $langRow, ['id' => $translationId]);
|
|
} else {
|
|
$langRow['article_id'] = $articleId;
|
|
$this->db->insert('pp_articles_langs', $langRow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private function savePages(int $articleId, $pages, bool $isNew): void
|
|
{
|
|
if (!$isNew) {
|
|
$notIn = [0];
|
|
|
|
if (is_array($pages)) {
|
|
foreach ($pages as $page) {
|
|
$notIn[] = $page;
|
|
}
|
|
} elseif ($pages) {
|
|
$notIn[] = $pages;
|
|
}
|
|
|
|
$this->db->delete('pp_articles_pages', [
|
|
'AND' => ['article_id' => $articleId, 'page_id[!]' => $notIn]
|
|
]);
|
|
|
|
$existingPages = $this->db->select('pp_articles_pages', 'page_id', ['article_id' => $articleId]);
|
|
|
|
if (!is_array($pages)) {
|
|
$pages = [$pages];
|
|
}
|
|
|
|
$pages = array_diff($pages, is_array($existingPages) ? $existingPages : []);
|
|
} else {
|
|
if (!is_array($pages)) {
|
|
$pages = $pages ? [$pages] : [];
|
|
}
|
|
}
|
|
|
|
if (is_array($pages)) {
|
|
foreach ($pages as $page) {
|
|
$order = $this->maxPageOrder() + 1;
|
|
|
|
$this->db->insert('pp_articles_pages', [
|
|
'article_id' => $articleId,
|
|
'page_id' => (int)$page,
|
|
'o' => $order,
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function assignTempFiles(int $articleId): void
|
|
{
|
|
$results = $this->db->select('pp_articles_files', '*', ['article_id' => null]);
|
|
|
|
if (!is_array($results)) {
|
|
return;
|
|
}
|
|
|
|
$created = false;
|
|
$dir = '/upload/article_files/article_' . $articleId;
|
|
|
|
foreach ($results as $row) {
|
|
$newFileName = str_replace('/upload/article_files/tmp', $dir, $row['src']);
|
|
|
|
if (file_exists('..' . $row['src'])) {
|
|
if (!is_dir('../' . $dir) && $created !== true) {
|
|
if (mkdir('../' . $dir, 0755, true)) {
|
|
$created = true;
|
|
}
|
|
}
|
|
rename('..' . $row['src'], '..' . $newFileName);
|
|
}
|
|
|
|
$this->db->update('pp_articles_files', [
|
|
'src' => $newFileName,
|
|
'article_id' => $articleId,
|
|
], ['id' => $row['id']]);
|
|
}
|
|
}
|
|
|
|
private function assignTempImages(int $articleId): void
|
|
{
|
|
$results = $this->db->select('pp_articles_images', '*', ['article_id' => null]);
|
|
|
|
if (!is_array($results)) {
|
|
return;
|
|
}
|
|
|
|
$created = false;
|
|
$dir = '/upload/article_images/article_' . $articleId;
|
|
|
|
foreach ($results as $row) {
|
|
$newFileName = str_replace('/upload/article_images/tmp', $dir, $row['src']);
|
|
|
|
if (file_exists('../' . $newFileName)) {
|
|
$ext = strrpos($newFileName, '.');
|
|
$fileNameA = substr($newFileName, 0, $ext);
|
|
$fileNameB = substr($newFileName, $ext);
|
|
|
|
$count = 1;
|
|
while (file_exists('../' . $fileNameA . '_' . $count . $fileNameB)) {
|
|
$count++;
|
|
}
|
|
|
|
$newFileName = $fileNameA . '_' . $count . $fileNameB;
|
|
}
|
|
|
|
if (file_exists('..' . $row['src'])) {
|
|
if (!is_dir('../' . $dir) && $created !== true) {
|
|
if (mkdir('../' . $dir, 0755, true)) {
|
|
$created = true;
|
|
}
|
|
}
|
|
rename('..' . $row['src'], '..' . $newFileName);
|
|
}
|
|
|
|
$this->db->update('pp_articles_images', [
|
|
'src' => $newFileName,
|
|
'article_id' => $articleId,
|
|
], ['id' => $row['id']]);
|
|
}
|
|
}
|
|
|
|
private function deleteMarkedImages(int $articleId): void
|
|
{
|
|
$results = $this->db->select('pp_articles_images', '*', [
|
|
'AND' => ['article_id' => $articleId, 'to_delete' => 1]
|
|
]);
|
|
|
|
if (is_array($results)) {
|
|
foreach ($results as $row) {
|
|
if (file_exists('../' . $row['src'])) {
|
|
unlink('../' . $row['src']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->db->delete('pp_articles_images', [
|
|
'AND' => ['article_id' => $articleId, 'to_delete' => 1]
|
|
]);
|
|
}
|
|
|
|
private function deleteMarkedFiles(int $articleId): void
|
|
{
|
|
$results = $this->db->select('pp_articles_files', '*', [
|
|
'AND' => ['article_id' => $articleId, 'to_delete' => 1]
|
|
]);
|
|
|
|
if (is_array($results)) {
|
|
foreach ($results as $row) {
|
|
if (file_exists('../' . $row['src'])) {
|
|
unlink('../' . $row['src']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->db->delete('pp_articles_files', [
|
|
'AND' => ['article_id' => $articleId, 'to_delete' => 1]
|
|
]);
|
|
}
|
|
|
|
private function maxPageOrder(): int
|
|
{
|
|
$max = $this->db->max('pp_articles_pages', 'o');
|
|
return $max ? (int)$max : 0;
|
|
}
|
|
|
|
/**
|
|
* Archiwizuje artykul (ustawia status = -1).
|
|
*/
|
|
public function archive(int $articleId): bool
|
|
{
|
|
$result = $this->db->update('pp_articles', ['status' => -1], ['id' => $articleId]);
|
|
return (bool)$result;
|
|
}
|
|
|
|
/**
|
|
* Przywraca artykul z archiwum (status = 0).
|
|
*/
|
|
public function restore(int $articleId): bool
|
|
{
|
|
$result = $this->db->update('pp_articles', ['status' => 0], ['id' => $articleId]);
|
|
return (bool)$result;
|
|
}
|
|
|
|
/**
|
|
* Trwale usuwa artykul wraz z relacjami i plikami z dysku.
|
|
*/
|
|
public function deletePermanently(int $articleId): bool
|
|
{
|
|
$this->db->delete('pp_articles_pages', ['article_id' => $articleId]);
|
|
$this->db->delete('pp_articles_langs', ['article_id' => $articleId]);
|
|
$this->db->delete('pp_articles_images', ['article_id' => $articleId]);
|
|
$this->db->delete('pp_articles_files', ['article_id' => $articleId]);
|
|
$this->db->delete('pp_articles', ['id' => $articleId]);
|
|
|
|
\S::delete_dir('../upload/article_images/article_' . $articleId . '/');
|
|
\S::delete_dir('../upload/article_files/article_' . $articleId . '/');
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Zwraca liste artykulow do panelu admin z filtrowaniem, sortowaniem i paginacja.
|
|
*
|
|
* @return array{items: array<int, array<string, mixed>>, total: int}
|
|
*/
|
|
public function listForAdmin(
|
|
array $filters,
|
|
string $sortColumn = 'date_add',
|
|
string $sortDir = 'DESC',
|
|
int $page = 1,
|
|
int $perPage = 15
|
|
): array {
|
|
$sortColumn = trim($sortColumn);
|
|
$sortDir = strtoupper(trim($sortDir));
|
|
|
|
$allowedSortColumns = [
|
|
'title' => 'title',
|
|
'status' => 'pa.status',
|
|
'date_add' => 'pa.date_add',
|
|
'date_modify' => 'pa.date_modify',
|
|
'user' => 'user',
|
|
];
|
|
|
|
$sortSql = $allowedSortColumns[$sortColumn] ?? 'pa.date_add';
|
|
$sortDir = $sortDir === 'ASC' ? 'ASC' : 'DESC';
|
|
$page = max(1, $page);
|
|
$perPage = min(self::MAX_PER_PAGE, max(1, $perPage));
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$where = ['pa.status != -1'];
|
|
$params = [];
|
|
|
|
$title = trim((string)($filters['title'] ?? ''));
|
|
if (strlen($title) > 255) {
|
|
$title = substr($title, 0, 255);
|
|
}
|
|
if ($title !== '') {
|
|
$where[] = "(
|
|
SELECT title
|
|
FROM pp_articles_langs AS pal, pp_langs AS pl
|
|
WHERE lang_id = pl.id AND article_id = pa.id AND title != ''
|
|
ORDER BY o ASC
|
|
LIMIT 1
|
|
) LIKE :title";
|
|
$params[':title'] = '%' . $title . '%';
|
|
}
|
|
|
|
if (($filters['status'] ?? '') !== '' && ($filters['status'] === '0' || $filters['status'] === '1')) {
|
|
$where[] = 'pa.status = :status';
|
|
$params[':status'] = (int)$filters['status'];
|
|
}
|
|
|
|
$this->appendDateRangeFilter($where, $params, 'pa.date_add', 'date_add_from', 'date_add_to', $filters);
|
|
$this->appendDateRangeFilter($where, $params, 'pa.date_modify', 'date_modify_from', 'date_modify_to', $filters);
|
|
|
|
$whereSql = implode(' AND ', $where);
|
|
|
|
$sqlCount = "
|
|
SELECT COUNT(0)
|
|
FROM pp_articles AS pa
|
|
WHERE {$whereSql}
|
|
";
|
|
|
|
$stmtCount = $this->db->query($sqlCount, $params);
|
|
$countRows = $stmtCount ? $stmtCount->fetchAll() : [];
|
|
$total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0;
|
|
|
|
$sql = "
|
|
SELECT
|
|
pa.id,
|
|
pa.date_add,
|
|
pa.date_modify,
|
|
pa.status,
|
|
(
|
|
SELECT title
|
|
FROM pp_articles_langs AS pal, pp_langs AS pl
|
|
WHERE lang_id = pl.id AND article_id = pa.id AND title != ''
|
|
ORDER BY o ASC
|
|
LIMIT 1
|
|
) AS title,
|
|
(
|
|
SELECT login
|
|
FROM pp_users AS pu
|
|
WHERE pu.id = pa.modify_by
|
|
) AS user
|
|
FROM pp_articles AS pa
|
|
WHERE {$whereSql}
|
|
ORDER BY {$sortSql} {$sortDir}, pa.id {$sortDir}
|
|
LIMIT {$perPage} OFFSET {$offset}
|
|
";
|
|
|
|
$stmt = $this->db->query($sql, $params);
|
|
$items = $stmt ? $stmt->fetchAll() : [];
|
|
|
|
return [
|
|
'items' => is_array($items) ? $items : [],
|
|
'total' => $total,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Zwraca liste artykulow z archiwum do panelu admin z filtrowaniem, sortowaniem i paginacja.
|
|
*
|
|
* @return array{items: array<int, array<string, mixed>>, total: int}
|
|
*/
|
|
public function listArchivedForAdmin(
|
|
array $filters,
|
|
string $sortColumn = 'date_add',
|
|
string $sortDir = 'DESC',
|
|
int $page = 1,
|
|
int $perPage = 15
|
|
): array {
|
|
$sortColumn = trim($sortColumn);
|
|
$sortDir = strtoupper(trim($sortDir));
|
|
|
|
$allowedSortColumns = [
|
|
'title' => 'title',
|
|
'date_add' => 'pa.date_add',
|
|
'date_modify' => 'pa.date_modify',
|
|
];
|
|
|
|
$sortSql = $allowedSortColumns[$sortColumn] ?? 'pa.date_add';
|
|
$sortDir = $sortDir === 'ASC' ? 'ASC' : 'DESC';
|
|
$page = max(1, $page);
|
|
$perPage = min(self::MAX_PER_PAGE, max(1, $perPage));
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$where = ['pa.status = -1'];
|
|
$params = [];
|
|
|
|
$title = trim((string)($filters['title'] ?? ''));
|
|
if (strlen($title) > 255) {
|
|
$title = substr($title, 0, 255);
|
|
}
|
|
if ($title !== '') {
|
|
$where[] = "(
|
|
SELECT title
|
|
FROM pp_articles_langs AS pal, pp_langs AS pl
|
|
WHERE lang_id = pl.id AND article_id = pa.id AND title != ''
|
|
ORDER BY o ASC
|
|
LIMIT 1
|
|
) LIKE :title";
|
|
$params[':title'] = '%' . $title . '%';
|
|
}
|
|
|
|
$this->appendDateRangeFilter($where, $params, 'pa.date_add', 'date_add_from', 'date_add_to', $filters);
|
|
$this->appendDateRangeFilter($where, $params, 'pa.date_modify', 'date_modify_from', 'date_modify_to', $filters);
|
|
|
|
$whereSql = implode(' AND ', $where);
|
|
|
|
$sqlCount = "
|
|
SELECT COUNT(0)
|
|
FROM pp_articles AS pa
|
|
WHERE {$whereSql}
|
|
";
|
|
|
|
$stmtCount = $this->db->query($sqlCount, $params);
|
|
$countRows = $stmtCount ? $stmtCount->fetchAll() : [];
|
|
$total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0;
|
|
|
|
$sql = "
|
|
SELECT
|
|
pa.id,
|
|
pa.date_add,
|
|
pa.date_modify,
|
|
(
|
|
SELECT title
|
|
FROM pp_articles_langs AS pal, pp_langs AS pl
|
|
WHERE lang_id = pl.id AND article_id = pa.id AND title != ''
|
|
ORDER BY o ASC
|
|
LIMIT 1
|
|
) AS title
|
|
FROM pp_articles AS pa
|
|
WHERE {$whereSql}
|
|
ORDER BY {$sortSql} {$sortDir}, pa.id {$sortDir}
|
|
LIMIT {$perPage} OFFSET {$offset}
|
|
";
|
|
|
|
$stmt = $this->db->query($sql, $params);
|
|
$items = $stmt ? $stmt->fetchAll() : [];
|
|
|
|
return [
|
|
'items' => is_array($items) ? $items : [],
|
|
'total' => $total,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Zapisuje kolejnosc zdjec galerii artykulu.
|
|
*/
|
|
public function saveGalleryOrder(int $articleId, string $order): bool
|
|
{
|
|
$imageIds = explode(';', $order);
|
|
if (!is_array($imageIds) || empty($imageIds)) {
|
|
return true;
|
|
}
|
|
|
|
$position = 0;
|
|
foreach ($imageIds as $imageId) {
|
|
if ($imageId === '' || $imageId === null) {
|
|
continue;
|
|
}
|
|
|
|
$this->db->update('pp_articles_images', [
|
|
'o' => $position++,
|
|
], [
|
|
'AND' => [
|
|
'article_id' => $articleId,
|
|
'id' => (int)$imageId,
|
|
],
|
|
]);
|
|
}
|
|
|
|
\S::delete_dir('../temp/');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Zapisuje kolejnosc zalacznikow artykulu.
|
|
*/
|
|
public function saveFilesOrder(int $articleId, string $order): bool
|
|
{
|
|
$fileIds = explode(';', $order);
|
|
if (!is_array($fileIds) || empty($fileIds)) {
|
|
return true;
|
|
}
|
|
|
|
$position = 0;
|
|
foreach ($fileIds as $fileId) {
|
|
if ($fileId === '' || $fileId === null) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
$this->db->update('pp_articles_files', [
|
|
'o' => $position++,
|
|
], [
|
|
'AND' => [
|
|
'article_id' => $articleId,
|
|
'id' => (int)$fileId,
|
|
],
|
|
]);
|
|
} catch (\Throwable $e) {
|
|
// Fallback for instances where pp_articles_files does not yet have "o" column.
|
|
return true;
|
|
}
|
|
}
|
|
|
|
\S::delete_dir('../temp/');
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Zwraca mape: article_id => etykieta stron (np. " - Strona A / Strona B").
|
|
*
|
|
* @param array<int, int> $articleIds
|
|
* @return array<int, string>
|
|
*/
|
|
public function pagesSummaryForArticles(array $articleIds): array
|
|
{
|
|
$normalizedIds = [];
|
|
foreach ($articleIds as $articleId) {
|
|
$id = (int)$articleId;
|
|
if ($id > 0) {
|
|
$normalizedIds[$id] = $id;
|
|
}
|
|
}
|
|
|
|
if (empty($normalizedIds)) {
|
|
return [];
|
|
}
|
|
|
|
$placeholders = [];
|
|
$params = [];
|
|
foreach (array_values($normalizedIds) as $index => $id) {
|
|
$key = ':article_id_' . $index;
|
|
$placeholders[] = $key;
|
|
$params[$key] = $id;
|
|
}
|
|
|
|
$sql = "
|
|
SELECT
|
|
ap.article_id,
|
|
ap.page_id,
|
|
(
|
|
SELECT title
|
|
FROM pp_pages_langs AS ppl, pp_langs AS pl
|
|
WHERE ppl.lang_id = pl.id AND ppl.page_id = ap.page_id AND ppl.title != ''
|
|
ORDER BY pl.o ASC
|
|
LIMIT 1
|
|
) AS title
|
|
FROM pp_articles_pages AS ap
|
|
WHERE ap.article_id IN (" . implode(', ', $placeholders) . ")
|
|
ORDER BY ap.article_id ASC, ap.o ASC, ap.page_id ASC
|
|
";
|
|
|
|
$stmt = $this->db->query($sql, $params);
|
|
$rows = $stmt ? $stmt->fetchAll() : [];
|
|
if (!is_array($rows)) {
|
|
return [];
|
|
}
|
|
|
|
$titlesByArticle = [];
|
|
foreach ($rows as $row) {
|
|
$articleId = (int)($row['article_id'] ?? 0);
|
|
if ($articleId <= 0) {
|
|
continue;
|
|
}
|
|
|
|
$title = trim((string)($row['title'] ?? ''));
|
|
if ($title === '') {
|
|
continue;
|
|
}
|
|
|
|
$titlesByArticle[$articleId][] = $title;
|
|
}
|
|
|
|
$summary = [];
|
|
foreach (array_values($normalizedIds) as $articleId) {
|
|
if (empty($titlesByArticle[$articleId])) {
|
|
$summary[$articleId] = '';
|
|
continue;
|
|
}
|
|
|
|
$summary[$articleId] = ' - ' . implode(' / ', $titlesByArticle[$articleId]);
|
|
}
|
|
|
|
return $summary;
|
|
}
|
|
|
|
public function updateImageAlt(int $imageId, string $imageAlt): bool
|
|
{
|
|
$result = $this->db->update('pp_articles_images', [
|
|
'alt' => $imageAlt,
|
|
], [
|
|
'id' => $imageId,
|
|
]);
|
|
|
|
\S::delete_cache();
|
|
|
|
return (bool)$result;
|
|
}
|
|
|
|
public function updateFileName(int $fileId, string $fileName): bool
|
|
{
|
|
$result = $this->db->update('pp_articles_files', [
|
|
'name' => $fileName,
|
|
], [
|
|
'id' => $fileId,
|
|
]);
|
|
|
|
return (bool)$result;
|
|
}
|
|
|
|
public function markFileToDelete(int $fileId): bool
|
|
{
|
|
$result = $this->db->update('pp_articles_files', [
|
|
'to_delete' => 1,
|
|
], [
|
|
'id' => $fileId,
|
|
]);
|
|
|
|
return (bool)$result;
|
|
}
|
|
|
|
public function markImageToDelete(int $imageId): bool
|
|
{
|
|
$result = $this->db->update('pp_articles_images', [
|
|
'to_delete' => 1,
|
|
], [
|
|
'id' => $imageId,
|
|
]);
|
|
|
|
return (bool)$result;
|
|
}
|
|
|
|
private function isCheckedValue($value): bool
|
|
{
|
|
if (is_bool($value)) {
|
|
return $value;
|
|
}
|
|
|
|
if (is_numeric($value)) {
|
|
return ((int)$value) === 1;
|
|
}
|
|
|
|
if (is_string($value)) {
|
|
$normalized = strtolower(trim($value));
|
|
return in_array($normalized, ['1', 'on', 'true', 'yes'], true);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function appendDateRangeFilter(
|
|
array &$where,
|
|
array &$params,
|
|
string $column,
|
|
string $fromKey,
|
|
string $toKey,
|
|
array $filters
|
|
): void {
|
|
$from = trim((string)($filters[$fromKey] ?? ''));
|
|
$to = trim((string)($filters[$toKey] ?? ''));
|
|
|
|
if ($from !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $from)) {
|
|
$fromParam = ':' . str_replace('.', '_', $column) . '_from';
|
|
$where[] = "{$column} >= {$fromParam}";
|
|
$params[$fromParam] = $from . ' 00:00:00';
|
|
}
|
|
|
|
if ($to !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $to)) {
|
|
$toParam = ':' . str_replace('.', '_', $column) . '_to';
|
|
$where[] = "{$column} <= {$toParam}";
|
|
$params[$toParam] = $to . ' 23:59:59';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Usuwa nieprzypisane pliki artykulow (article_id = null) wraz z plikami z dysku.
|
|
*/
|
|
public function deleteNonassignedFiles(): void
|
|
{
|
|
$results = $this->db->select('pp_articles_files', '*', ['article_id' => null]);
|
|
if (is_array($results)) {
|
|
foreach ($results as $row) {
|
|
if (file_exists('../' . $row['src'])) {
|
|
unlink('../' . $row['src']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->db->delete('pp_articles_files', ['article_id' => null]);
|
|
}
|
|
|
|
/**
|
|
* Usuwa nieprzypisane zdjecia artykulow (article_id = null) wraz z plikami z dysku.
|
|
*/
|
|
public function deleteNonassignedImages(): void
|
|
{
|
|
$results = $this->db->select('pp_articles_images', '*', ['article_id' => null]);
|
|
if (is_array($results)) {
|
|
foreach ($results as $row) {
|
|
if (file_exists('../' . $row['src'])) {
|
|
unlink('../' . $row['src']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->db->delete('pp_articles_images', ['article_id' => null]);
|
|
}
|
|
}
|