feat: Migrate article_save and article_delete to Domain Architecture
Move article save/delete logic from monolithic factory to ArticleRepository with DI-based controller actions, following the established refactoring pattern. - ArticleRepository: add save() with 9 private helpers, archive() method - ArticlesController: add save() and delete() actions with DI - Factory methods delegate to repository (backward compatibility) - Router: add article_save/article_delete action mappings - Old controls methods marked @deprecated - 59 tests, 123 assertions passing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -246,10 +246,27 @@ tests/
|
||||
│ └── ProductArchiveControllerTest.php # 6 testów
|
||||
└── Integration/
|
||||
```
|
||||
**Łącznie: 50 tests, 95 assertions**
|
||||
**Łącznie: 59 tests, 123 assertions**
|
||||
|
||||
## Ostatnie modyfikacje
|
||||
|
||||
### 2026-02-06: Migracja Articles::article_delete do DI (ver. 0.245)
|
||||
- **UPDATE:** `Domain\Article\ArticleRepository` - dodano `archive()` (ustawia status = -1)
|
||||
- **UPDATE:** `admin\Controllers\ArticlesController` - nowa akcja `delete()` z DI
|
||||
- **UPDATE:** Router `admin\Site` - dodano `'article_delete' => 'delete'` do `$actionMap`
|
||||
- **UPDATE:** `admin\factory\Articles::articles_set_archive()` deleguje do `ArticleRepository::archive()`
|
||||
- **UPDATE:** `admin\controls\Articles::article_delete()` oznaczone `@deprecated`
|
||||
- Testy: 59 tests, 123 assertions
|
||||
|
||||
### 2026-02-06: Migracja Articles::article_save do DI (ver. 0.244)
|
||||
- **UPDATE:** `Domain\Article\ArticleRepository` - dodano `save()` + prywatne helpery (`buildArticleRow`, `buildLangRow`, `saveTranslations`, `savePages`, `assignTempFiles`, `assignTempImages`, `deleteMarkedFiles`, `deleteMarkedImages`, `maxPageOrder`)
|
||||
- **UPDATE:** `admin\Controllers\ArticlesController` - nowa akcja `save()` z DI
|
||||
- **UPDATE:** Router `admin\Site` - dodano `'article_save' => 'save'` do `$actionMap`
|
||||
- **UPDATE:** `admin\factory\Articles::article_save()` deleguje do `ArticleRepository::save()` (backward compatibility)
|
||||
- **UPDATE:** `admin\controls\Articles::article_save()` oznaczone `@deprecated`
|
||||
- **UPDATE:** `tests/bootstrap.php` - dodano stub `S::seo()`
|
||||
- Testy: 57 tests, 119 assertions
|
||||
|
||||
### 2026-02-06: Articles cleanup moved to repository (ver. 0.243)
|
||||
- **UPDATE:** `Domain\Article\ArticleRepository` - added `deleteNonassignedImages()` and `deleteNonassignedFiles()`
|
||||
- **UPDATE:** `admin\Controllers\ArticlesController::edit()` uses repository cleanup methods
|
||||
|
||||
@@ -181,8 +181,20 @@ grep -r "Product::getQuantity" .
|
||||
- Zmigrowana akcja: `article_edit` -> `edit` (mapowanie w `admin\Site::$actionMap`)
|
||||
- Kompatybilność: `admin\factory\Articles::article_details()` deleguje do nowego repozytorium
|
||||
- Legacy cleanup: metody przejęte przez nowe kontrolery oznaczone `@deprecated` w `admin\controls\Articles|Banners|Settings`
|
||||
- Testy repozytorium rozszerzone o czyszczenie nieprzypisanych plik<69>w/zdj<64><6A>
|
||||
- Testy repozytorium rozszerzone o czyszczenie nieprzypisanych plik<69>w/zdj<64><6A>
|
||||
- Aktualizacja: ver. 0.243
|
||||
- ✅ ArticleRepository::save() - **ZMIGROWANE** (2026-02-06) 🎉
|
||||
- Metoda `save()` z prywatnych helperow (buildArticleRow, buildLangRow, saveTranslations, savePages, assignTempFiles, assignTempImages, deleteMarkedFiles, deleteMarkedImages)
|
||||
- Zmigrowana akcja: `article_save` -> `save` (mapowanie w `admin\Site::$actionMap`)
|
||||
- Kompatybilnosc: `admin\factory\Articles::article_save()` deleguje do repozytorium
|
||||
- Testy: 7 nowych testow save (create, update, translations, pages, marked delete)
|
||||
- Aktualizacja: ver. 0.244
|
||||
- ✅ ArticleRepository::archive() - **ZMIGROWANE** (2026-02-06) 🎉
|
||||
- Metoda `archive()` (ustawia status = -1)
|
||||
- Zmigrowana akcja: `article_delete` -> `delete` (mapowanie w `admin\Site::$actionMap`)
|
||||
- Kompatybilnosc: `admin\factory\Articles::articles_set_archive()` deleguje do repozytorium
|
||||
- Testy: 2 nowe testy archive (success, failure)
|
||||
- Aktualizacja: ver. 0.245
|
||||
|
||||
- **Settings** (migracja kontrolera - krok pośredni)
|
||||
- ✅ SettingsRepository - **ZMIGROWANE** (2026-02-05) 🎉
|
||||
|
||||
@@ -41,6 +41,294 @@ class ArticleRepository
|
||||
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);
|
||||
|
||||
\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->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' => ($data['show_title'] ?? '') == 'on' ? 1 : 0,
|
||||
'show_date_add' => ($data['show_date_add'] ?? '') == 'on' ? 1 : 0,
|
||||
'show_date_modify' => ($data['show_date_modify'] ?? '') == 'on' ? 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' => ($data['status'] ?? '') == 'on' ? 1 : 0,
|
||||
'repeat_entry' => ($data['repeat_entry'] ?? '') == 'on' ? 1 : 0,
|
||||
'social_icons' => ($data['social_icons'] ?? '') == 'on' ? 1 : 0,
|
||||
'show_table_of_contents' => ($data['show_table_of_contents'] ?? '') == 'on' ? 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' => ($data['noindex'][$langId] ?? '') == 'on' ? 1 : 0,
|
||||
'copy_from' => ($data['copy_from'][$langId] ?? '') != '' ? $data['copy_from'][$langId] : null,
|
||||
'block_direct_access' => ($data['block_direct_access'][$langId] ?? '') == 'on' ? 1 : 0,
|
||||
];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Usuwa nieprzypisane pliki artykulow (article_id = null) wraz z plikami z dysku.
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,37 @@ class ArticlesController
|
||||
return \admin\view\Articles::articles_list();
|
||||
}
|
||||
|
||||
/**
|
||||
* Zapis artykulu (AJAX)
|
||||
*/
|
||||
public function save(): void
|
||||
{
|
||||
global $user;
|
||||
|
||||
$values = json_decode(\S::get('values'), true);
|
||||
$response = ['status' => 'error', 'msg' => 'Podczas zapisywania artykułu wystąpił błąd. Proszę spróbować ponownie.'];
|
||||
|
||||
if ($id = $this->repository->save((int)($values['id'] ?? 0), $values, (int)$user['id'])) {
|
||||
$response = ['status' => 'ok', 'msg' => 'Artykuł został zapisany.', 'id' => $id];
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Archiwizacja artykulu (ustawia status = -1)
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
if ($this->repository->archive((int)\S::get('id'))) {
|
||||
\S::alert('Artykuł został przeniesiony do archiwum.');
|
||||
}
|
||||
|
||||
header('Location: /admin/articles/view_list/');
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edycja artykulu
|
||||
*/
|
||||
|
||||
@@ -255,6 +255,8 @@ class Site
|
||||
private static $actionMap = [
|
||||
'view_list' => 'list',
|
||||
'article_edit' => 'edit',
|
||||
'article_save' => 'save',
|
||||
'article_delete' => 'delete',
|
||||
'banner_edit' => 'edit',
|
||||
'banner_save' => 'save',
|
||||
'banner_delete' => 'delete',
|
||||
|
||||
@@ -16,6 +16,10 @@ class Articles
|
||||
return \admin\view\Articles::browse_list();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\ArticlesController::delete().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function article_delete()
|
||||
{
|
||||
if ( \admin\factory\Articles::articles_set_archive( \S::get( 'id' ) ) )
|
||||
@@ -24,6 +28,10 @@ class Articles
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\ArticlesController::save().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function article_save()
|
||||
{
|
||||
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania artykułu wystąpił błąd. Proszę spróbować ponownie.' ];
|
||||
|
||||
@@ -93,10 +93,14 @@ class Articles
|
||||
return $results[0]['title'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Logika przeniesiona do Domain\Article\ArticleRepository::archive().
|
||||
*/
|
||||
public static function articles_set_archive( $article_id )
|
||||
{
|
||||
global $mdb;
|
||||
return $mdb -> update( 'pp_articles', [ 'status' => -1 ], [ 'id' => (int)$article_id ] );
|
||||
$repository = new \Domain\Article\ArticleRepository( $mdb );
|
||||
return $repository->archive( (int)$article_id );
|
||||
}
|
||||
|
||||
public static function file_name_change( $file_id, $file_name )
|
||||
@@ -133,301 +137,31 @@ class Articles
|
||||
return $mdb -> max( 'pp_articles_pages', 'o' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Logika przeniesiona do Domain\Article\ArticleRepository::save().
|
||||
* Ta metoda pozostaje jako fasada dla backward compatibility.
|
||||
*/
|
||||
public static function article_save(
|
||||
$article_id, $title, $main_image, $entry, $text, $table_of_contents, $status, $show_title, $show_table_of_contents, $show_date_add, $date_add, $show_date_modify, $date_modify, $seo_link, $meta_title, $meta_description, $meta_keywords, $layout_id, $pages,
|
||||
$noindex, $repeat_entry, $copy_from, $social_icons, $block_direct_access )
|
||||
{
|
||||
global $mdb, $user;
|
||||
|
||||
if ( !$article_id )
|
||||
{
|
||||
$mdb -> insert( 'pp_articles', [
|
||||
'show_title' => $show_title == 'on' ? 1 : 0,
|
||||
'show_date_add' => $show_date_add == 'on' ? 1 : 0,
|
||||
'show_date_modify' => $show_date_modify == 'on' ? 1 : 0,
|
||||
'date_add' => date( 'Y-m-d H:i:s' ),
|
||||
'date_modify' => date( 'Y-m-d H:i:s' ),
|
||||
'modify_by' => $user['id'],
|
||||
'layout_id' => $layout_id ? (int)$layout_id : null,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
'repeat_entry' => $repeat_entry == 'on' ? 1 : 0,
|
||||
'social_icons' => $social_icons == 'on' ? 1 : 0,
|
||||
'show_table_of_contents' => $show_table_of_contents == 'on' ? 1 : 0,
|
||||
] );
|
||||
$repository = new \Domain\Article\ArticleRepository( $mdb );
|
||||
|
||||
$id = $mdb -> id();
|
||||
|
||||
if ( $id )
|
||||
{
|
||||
foreach ( $title as $key => $val )
|
||||
{
|
||||
$mdb -> insert( 'pp_articles_langs', [
|
||||
'article_id' => (int)$id,
|
||||
'lang_id' => $key,
|
||||
'title' => $title[$key] != '' ? $title[$key] : null,
|
||||
'main_image' => $main_image[$key] != '' ? $main_image[$key] : null,
|
||||
'entry' => $entry[$key] != '' ? $entry[$key] : null,
|
||||
'text' => $text[$key] != '' ? $text[$key] : null,
|
||||
'table_of_contents' => $table_of_contents[$key] != '' ? $table_of_contents[$key] : null,
|
||||
'meta_title' => $meta_title[$key] != '' ? $meta_title[$key] : null,
|
||||
'meta_description' => $meta_description[$key] != '' ? $meta_description[$key] : null,
|
||||
'meta_keywords' => $meta_keywords[$key] != '' ? $meta_keywords[$key] : null,
|
||||
'seo_link' => \S::seo( $seo_link[$key] ) != '' ? \S::seo( $seo_link[$key] ) : null,
|
||||
'noindex' => $noindex[$key] == 'on' ? 1 : 0,
|
||||
'copy_from' => $copy_from[$key] != '' ? $copy_from[$key] : null,
|
||||
'block_direct_access' => $block_direct_access[$key] == 'on' ? 1 : 0
|
||||
] );
|
||||
}
|
||||
|
||||
if ( is_array( $pages ) ) foreach ( $pages as $page )
|
||||
{
|
||||
$order = self::max_order() + 1;
|
||||
|
||||
$mdb -> insert( 'pp_articles_pages', [
|
||||
'article_id' => (int)$id,
|
||||
'page_id' => (int)$page,
|
||||
'o' => (int)$order
|
||||
] );
|
||||
}
|
||||
else if ( $pages )
|
||||
{
|
||||
$order = self::max_order() + 1;
|
||||
|
||||
$mdb -> insert( 'pp_articles_pages', [
|
||||
'article_id' => (int)$id,
|
||||
'page_id' => (int)$pages,
|
||||
'o' => (int)$order
|
||||
] );
|
||||
}
|
||||
|
||||
$results = $mdb -> select( 'pp_articles_files', '*', [ 'article_id' => null ] );
|
||||
if ( is_array( $results ) ) foreach ( $results as $row )
|
||||
{
|
||||
$dir = '/upload/article_files/article_' . $id;
|
||||
|
||||
$new_file_name = str_replace( '/upload/article_files/tmp', $dir, $row['src'] );
|
||||
|
||||
if ( file_exists( '..' . $row['src'] ) )
|
||||
{
|
||||
if ( !is_dir( '../' . $dir ) and $created !== true )
|
||||
{
|
||||
if ( mkdir( '../' . $dir, 0755, true ) )
|
||||
$created = true;
|
||||
}
|
||||
rename( '..' . $row['src'], '..' . $new_file_name );
|
||||
}
|
||||
|
||||
$mdb -> update( 'pp_articles_files', [ 'src' => $new_file_name, 'article_id' => $id ], [ 'id' => $row['id'] ] );
|
||||
}
|
||||
|
||||
$created = false;
|
||||
|
||||
/* zdjęcia */
|
||||
$results = $mdb -> select( 'pp_articles_images', '*', [ 'article_id' => null ] );
|
||||
if ( is_array( $results ) ) foreach ( $results as $row )
|
||||
{
|
||||
$dir = '/upload/article_images/article_' . $id;
|
||||
|
||||
$new_file_name = str_replace( '/upload/article_images/tmp', $dir, $row['src'] );
|
||||
|
||||
if ( file_exists( '../' . $new_file_name ) )
|
||||
{
|
||||
$ext = strrpos( $new_file_name, '.' );
|
||||
$fileName_a = substr( $new_file_name, 0, $ext );
|
||||
$fileName_b = substr( $new_file_name, $ext );
|
||||
|
||||
$count = 1;
|
||||
|
||||
while ( file_exists( '../' . $fileName_a . '_' . $count . $fileName_b ) )
|
||||
$count++;
|
||||
|
||||
$new_file_name = $fileName_a . '_' . $count . $fileName_b;
|
||||
}
|
||||
|
||||
if ( file_exists( '..' . $row['src'] ) )
|
||||
{
|
||||
if ( !is_dir( '../' . $dir ) and $created !== true )
|
||||
{
|
||||
if ( mkdir( '../' . $dir, 0755, true ) )
|
||||
$created = true;
|
||||
}
|
||||
rename( '..' . $row['src'], '..' . $new_file_name );
|
||||
}
|
||||
|
||||
$mdb -> update( 'pp_articles_images', [ 'src' => $new_file_name, 'article_id' => (int)$id ], [ 'id' => $row['id'] ] );
|
||||
}
|
||||
|
||||
\S::htacces();
|
||||
|
||||
\S::delete_dir( '../temp/' );
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$mdb -> update( 'pp_articles', [
|
||||
'show_title' => $show_title == 'on' ? 1 : 0,
|
||||
'show_date_add' => $show_date_add == 'on' ? 1 : 0,
|
||||
'show_date_modify' => $show_date_modify == 'on' ? 1 : 0,
|
||||
'date_modify' => date( 'Y-m-d H:i:s' ),
|
||||
'modify_by' => $user['id'],
|
||||
'layout_id' => $layout_id ? (int)$layout_id : null,
|
||||
'status' => $status == 'on' ? 1 : 0,
|
||||
'repeat_entry' => $repeat_entry == 'on' ? 1 : 0,
|
||||
'social_icons' => $social_icons == 'on' ? 1 : 0,
|
||||
'show_table_of_contents' => $show_table_of_contents == 'on' ? 1 : 0,
|
||||
], [
|
||||
'id' => (int)$article_id
|
||||
] );
|
||||
|
||||
foreach ( $title as $key => $val )
|
||||
{
|
||||
if ( $translation_id = $mdb -> get( 'pp_articles_langs', 'id', [ 'AND' => [ 'article_id' => $article_id, 'lang_id' => $key ] ] ) )
|
||||
$mdb -> update( 'pp_articles_langs', [
|
||||
'lang_id' => $key,
|
||||
'title' => $title[$key] != '' ? $title[$key] : null,
|
||||
'main_image' => $main_image[$key] != '' ? $main_image[$key] : null,
|
||||
'entry' => $entry[$key] != '' ? $entry[$key] : null,
|
||||
'text' => $text[$key] != '' ? $text[$key] : null,
|
||||
'table_of_contents' => $table_of_contents[$key] != '' ? $table_of_contents[$key] : null,
|
||||
'meta_title' => $meta_title[$key] != '' ? $meta_title[$key] : null,
|
||||
'meta_description' => $meta_description[$key] != '' ? $meta_description[$key] : null,
|
||||
'meta_keywords' => $meta_keywords[$key] != '' ? $meta_keywords[$key] : null,
|
||||
'seo_link' => \S::seo( $seo_link[$key] ) != '' ? \S::seo( $seo_link[$key] ) : null,
|
||||
'noindex' => $noindex[$key] == 'on' ? 1 : 0,
|
||||
'copy_from' => $copy_from[$key] != '' ? $copy_from[$key] : null,
|
||||
'block_direct_access' => $block_direct_access[$key] == 'on' ? 1 : 0
|
||||
], [
|
||||
'id' => $translation_id
|
||||
] );
|
||||
else
|
||||
$mdb -> insert( 'pp_articles_langs', [
|
||||
'article_id' => (int)$article_id,
|
||||
'lang_id' => $key,
|
||||
'title' => $title[$key] != '' ? $title[$key] : null,
|
||||
'main_image' => $main_image[$key] != '' ? $main_image[$key] : null,
|
||||
'entry' => $entry[$key] != '' ? $entry[$key] : null,
|
||||
'text' => $text[$key] != '' ? $text[$key] : null,
|
||||
'table_of_contents' => $table_of_contents[$key] != '' ? $table_of_contents[$key] : null,
|
||||
'meta_title' => $meta_title[$key] != '' ? $meta_title[$key] : null,
|
||||
'meta_description' => $meta_description[$key] != '' ? $meta_description[$key] : null,
|
||||
'meta_keywords' => $meta_keywords[$key] != '' ? $meta_keywords[$key] : null,
|
||||
'seo_link' => \S::seo( $seo_link[$key] ) != '' ? \S::seo( $seo_link[$key] ) : null,
|
||||
'noindex' => $noindex[$key] == 'on' ? 1 : 0,
|
||||
'copy_from' => $copy_from[$key] != '' ? $copy_from[$key] : null,
|
||||
'block_direct_access' => $block_direct_access[$key] == 'on' ? 1 : 0
|
||||
] );
|
||||
}
|
||||
|
||||
$not_in = [ 0 ];
|
||||
|
||||
if ( is_array( $pages ) ) foreach ( $pages as $page )
|
||||
$not_in[] = $page;
|
||||
else if ( $pages )
|
||||
$not_in[] = $pages;
|
||||
|
||||
$mdb -> delete( 'pp_articles_pages', [ 'AND' => [ 'article_id' => (int)$article_id, 'page_id[!]' => $not_in ] ] );
|
||||
|
||||
$pages_tmp = $mdb -> select( 'pp_articles_pages', 'page_id', [ 'article_id' => (int)$article_id ] );
|
||||
|
||||
if ( !is_array( $pages ) )
|
||||
$pages = [ $pages ];
|
||||
|
||||
$pages = array_diff( $pages, $pages_tmp );
|
||||
|
||||
if ( is_array( $pages ) ) foreach ( $pages as $page )
|
||||
{
|
||||
$order = self::max_order() + 1;
|
||||
|
||||
$mdb -> insert( 'pp_articles_pages', [
|
||||
'article_id' => (int)$article_id,
|
||||
'page_id' => (int)$page,
|
||||
'o' => (int)$order
|
||||
] );
|
||||
}
|
||||
|
||||
$results = $mdb -> select( 'pp_articles_files', '*', [ 'article_id' => null ] );
|
||||
if ( is_array( $results ) ) foreach ( $results as $row )
|
||||
{
|
||||
$dir = '/upload/article_files/article_' . $article_id;
|
||||
|
||||
$new_file_name = str_replace( '/upload/article_files/tmp', $dir, $row['src'] );
|
||||
|
||||
if ( file_exists( '..' . $row['src'] ) )
|
||||
{
|
||||
if ( !is_dir( '../' . $dir ) and $created !== true )
|
||||
{
|
||||
if ( mkdir( '../' . $dir, 0755, true ) )
|
||||
$created = true;
|
||||
}
|
||||
rename( '..' . $row['src'], '..' . $new_file_name );
|
||||
}
|
||||
|
||||
$mdb -> update( 'pp_articles_files', [ 'src' => $new_file_name, 'article_id' => (int)$article_id ], [ 'id' => $row['id'] ] );
|
||||
}
|
||||
|
||||
$created = false;
|
||||
|
||||
/* zdjęcia */
|
||||
$results = $mdb -> select( 'pp_articles_images', '*', [ 'article_id' => null ] );
|
||||
if ( is_array( $results ) ) foreach ( $results as $row )
|
||||
{
|
||||
$dir = '/upload/article_images/article_' . $article_id;
|
||||
|
||||
$new_file_name = str_replace( '/upload/article_images/tmp', $dir, $row['src'] );
|
||||
|
||||
if ( file_exists( '../' . $new_file_name ) )
|
||||
{
|
||||
$ext = strrpos( $new_file_name, '.' );
|
||||
$fileName_a = substr( $new_file_name, 0, $ext );
|
||||
$fileName_b = substr( $new_file_name, $ext );
|
||||
|
||||
$count = 1;
|
||||
|
||||
while ( file_exists( '../' . $fileName_a . '_' . $count . $fileName_b ) )
|
||||
$count++;
|
||||
|
||||
$new_file_name = $fileName_a . '_' . $count . $fileName_b;
|
||||
}
|
||||
|
||||
if ( file_exists( '..' . $row['src'] ) )
|
||||
{
|
||||
if ( !is_dir( '../' . $dir ) and $created !== true )
|
||||
{
|
||||
if ( mkdir( '../' . $dir, 0755, true ) )
|
||||
$created = true;
|
||||
}
|
||||
rename( '..' . $row['src'], '..' . $new_file_name );
|
||||
}
|
||||
|
||||
$mdb -> update( 'pp_articles_images', [ 'src' => $new_file_name, 'article_id' => (int)$article_id ], [ 'id' => $row['id'] ] );
|
||||
}
|
||||
|
||||
$results = $mdb -> select( 'pp_articles_images', '*', [ 'AND' => [ 'article_id' => (int)$article_id, 'to_delete' => 1 ] ] );
|
||||
if ( is_array( $results ) ) foreach ( $results as $row )
|
||||
{
|
||||
if ( file_exists( '../' . $row['src'] ) )
|
||||
unlink( '../' . $row['src'] );
|
||||
}
|
||||
|
||||
$mdb -> delete( 'pp_articles_images', [ 'AND' => [ 'article_id' => (int)$article_id, 'to_delete' => 1 ] ] );
|
||||
|
||||
$results = $mdb -> select( 'pp_articles_files', '*', [ 'AND' => [ 'article_id' => (int)$article_id, 'to_delete' => 1 ] ] );
|
||||
if ( is_array( $results ) ) foreach ( $results as $row )
|
||||
{
|
||||
if ( file_exists( '../' . $row['src'] ) )
|
||||
unlink( '../' . $row['src'] );
|
||||
}
|
||||
|
||||
$mdb -> delete( 'pp_articles_files', [ 'AND' => [ 'article_id' => (int)$article_id, 'to_delete' => 1 ] ] );
|
||||
|
||||
\S::htacces();
|
||||
|
||||
\S::delete_dir( '../temp/' );
|
||||
|
||||
return $article_id;
|
||||
}
|
||||
return $repository->save( (int)$article_id, [
|
||||
'title' => $title, 'main_image' => $main_image, 'entry' => $entry,
|
||||
'text' => $text, 'table_of_contents' => $table_of_contents,
|
||||
'status' => $status, 'show_title' => $show_title,
|
||||
'show_table_of_contents' => $show_table_of_contents,
|
||||
'show_date_add' => $show_date_add, 'date_add' => $date_add,
|
||||
'show_date_modify' => $show_date_modify, 'date_modify' => $date_modify,
|
||||
'seo_link' => $seo_link, 'meta_title' => $meta_title,
|
||||
'meta_description' => $meta_description, 'meta_keywords' => $meta_keywords,
|
||||
'layout_id' => $layout_id, 'pages' => $pages, 'noindex' => $noindex,
|
||||
'repeat_entry' => $repeat_entry, 'copy_from' => $copy_from,
|
||||
'social_icons' => $social_icons, 'block_direct_access' => $block_direct_access,
|
||||
], (int)$user['id'] );
|
||||
}
|
||||
|
||||
public static function delete_nonassigned_files()
|
||||
|
||||
@@ -99,4 +99,297 @@ class ArticleRepositoryTest extends TestCase
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
private function getSampleData(): array
|
||||
{
|
||||
return [
|
||||
'title' => ['pl' => 'Testowy artykul', 'en' => 'Test article'],
|
||||
'main_image' => ['pl' => '/img/pl.jpg', 'en' => ''],
|
||||
'entry' => ['pl' => 'Wstep', 'en' => 'Entry'],
|
||||
'text' => ['pl' => 'Tresc', 'en' => 'Content'],
|
||||
'table_of_contents' => ['pl' => '', 'en' => ''],
|
||||
'status' => 'on',
|
||||
'show_title' => 'on',
|
||||
'show_table_of_contents' => '',
|
||||
'show_date_add' => 'on',
|
||||
'date_add' => '',
|
||||
'show_date_modify' => '',
|
||||
'date_modify' => '',
|
||||
'seo_link' => ['pl' => 'testowy-artykul', 'en' => 'test-article'],
|
||||
'meta_title' => ['pl' => 'Meta PL', 'en' => ''],
|
||||
'meta_description' => ['pl' => '', 'en' => ''],
|
||||
'meta_keywords' => ['pl' => '', 'en' => ''],
|
||||
'layout_id' => '2',
|
||||
'pages' => ['1', '3'],
|
||||
'noindex' => ['pl' => '', 'en' => 'on'],
|
||||
'repeat_entry' => '',
|
||||
'copy_from' => ['pl' => '', 'en' => ''],
|
||||
'social_icons' => 'on',
|
||||
'block_direct_access' => ['pl' => '', 'en' => ''],
|
||||
];
|
||||
}
|
||||
|
||||
public function testSaveCreatesNewArticle(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$data = $this->getSampleData();
|
||||
|
||||
$insertCalls = [];
|
||||
$mockDb->method('insert')
|
||||
->willReturnCallback(function ($table, $row) use (&$insertCalls) {
|
||||
$insertCalls[] = ['table' => $table, 'row' => $row];
|
||||
return true;
|
||||
});
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('id')
|
||||
->willReturn(42);
|
||||
|
||||
$mockDb->method('select')->willReturn([]);
|
||||
$mockDb->method('max')->willReturn(5);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$result = $repository->save(0, $data, 1);
|
||||
|
||||
$this->assertEquals(42, $result);
|
||||
|
||||
// Verify article insert
|
||||
$articleInsert = $insertCalls[0];
|
||||
$this->assertEquals('pp_articles', $articleInsert['table']);
|
||||
$this->assertEquals(1, $articleInsert['row']['status']);
|
||||
$this->assertEquals(1, $articleInsert['row']['show_title']);
|
||||
$this->assertEquals(2, $articleInsert['row']['layout_id']);
|
||||
$this->assertArrayHasKey('date_add', $articleInsert['row']);
|
||||
}
|
||||
|
||||
public function testSaveReturnsZeroWhenInsertFails(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$mockDb->method('insert');
|
||||
$mockDb->method('id')->willReturn(null);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$result = $repository->save(0, $this->getSampleData(), 1);
|
||||
|
||||
$this->assertEquals(0, $result);
|
||||
}
|
||||
|
||||
public function testSaveUpdatesExistingArticle(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$data = $this->getSampleData();
|
||||
|
||||
$updateCalls = [];
|
||||
$mockDb->method('update')
|
||||
->willReturnCallback(function ($table, $row, $where = null) use (&$updateCalls) {
|
||||
$updateCalls[] = ['table' => $table, 'row' => $row, 'where' => $where];
|
||||
return true;
|
||||
});
|
||||
|
||||
$mockDb->method('get')->willReturn(99);
|
||||
$mockDb->method('select')->willReturn([]);
|
||||
$mockDb->method('max')->willReturn(0);
|
||||
$mockDb->method('insert')->willReturn(true);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$result = $repository->save(10, $data, 1);
|
||||
|
||||
$this->assertEquals(10, $result);
|
||||
|
||||
// Verify article update
|
||||
$articleUpdate = $updateCalls[0];
|
||||
$this->assertEquals('pp_articles', $articleUpdate['table']);
|
||||
$this->assertEquals(1, $articleUpdate['row']['status']);
|
||||
$this->assertArrayNotHasKey('date_add', $articleUpdate['row']);
|
||||
$this->assertEquals(['id' => 10], $articleUpdate['where']);
|
||||
}
|
||||
|
||||
public function testSaveTranslationsInsertsForNewArticle(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$data = $this->getSampleData();
|
||||
|
||||
// 1 insert for pp_articles + 2 inserts for translations (pl, en) + 2 inserts for pages
|
||||
$insertCalls = [];
|
||||
$mockDb->method('insert')
|
||||
->willReturnCallback(function ($table, $row) use (&$insertCalls) {
|
||||
$insertCalls[] = ['table' => $table, 'row' => $row];
|
||||
return true;
|
||||
});
|
||||
|
||||
$mockDb->method('id')->willReturn(50);
|
||||
$mockDb->method('select')->willReturn([]);
|
||||
$mockDb->method('max')->willReturn(0);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$repository->save(0, $data, 1);
|
||||
|
||||
$langInserts = array_filter($insertCalls, function ($c) {
|
||||
return $c['table'] === 'pp_articles_langs';
|
||||
});
|
||||
|
||||
$this->assertCount(2, $langInserts);
|
||||
|
||||
$plInsert = array_values(array_filter($langInserts, function ($c) {
|
||||
return $c['row']['lang_id'] === 'pl';
|
||||
}))[0]['row'];
|
||||
|
||||
$this->assertEquals(50, $plInsert['article_id']);
|
||||
$this->assertEquals('Testowy artykul', $plInsert['title']);
|
||||
$this->assertEquals('/img/pl.jpg', $plInsert['main_image']);
|
||||
}
|
||||
|
||||
public function testSaveTranslationsUpsertsForExistingArticle(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$data = $this->getSampleData();
|
||||
|
||||
// get returns translation ID for 'pl', null for 'en'
|
||||
$mockDb->method('get')
|
||||
->willReturnOnConsecutiveCalls(100, null);
|
||||
|
||||
$updateCalls = [];
|
||||
$mockDb->method('update')
|
||||
->willReturnCallback(function ($table, $row, $where = null) use (&$updateCalls) {
|
||||
$updateCalls[] = ['table' => $table, 'row' => $row, 'where' => $where];
|
||||
return true;
|
||||
});
|
||||
|
||||
$insertCalls = [];
|
||||
$mockDb->method('insert')
|
||||
->willReturnCallback(function ($table, $row) use (&$insertCalls) {
|
||||
$insertCalls[] = ['table' => $table, 'row' => $row];
|
||||
return true;
|
||||
});
|
||||
|
||||
$mockDb->method('select')->willReturn([]);
|
||||
$mockDb->method('max')->willReturn(0);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$repository->save(10, $data, 1);
|
||||
|
||||
// pl should be updated (translation_id=100)
|
||||
$langUpdates = array_filter($updateCalls, function ($c) {
|
||||
return $c['table'] === 'pp_articles_langs';
|
||||
});
|
||||
$this->assertCount(1, $langUpdates);
|
||||
|
||||
// en should be inserted (no existing translation)
|
||||
$langInserts = array_filter($insertCalls, function ($c) {
|
||||
return $c['table'] === 'pp_articles_langs';
|
||||
});
|
||||
$this->assertCount(1, $langInserts);
|
||||
}
|
||||
|
||||
public function testSavePagesForNewArticle(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$data = $this->getSampleData();
|
||||
$data['pages'] = ['5', '8'];
|
||||
|
||||
$insertCalls = [];
|
||||
$mockDb->method('insert')
|
||||
->willReturnCallback(function ($table, $row) use (&$insertCalls) {
|
||||
$insertCalls[] = ['table' => $table, 'row' => $row];
|
||||
return true;
|
||||
});
|
||||
|
||||
$mockDb->method('id')->willReturn(60);
|
||||
$mockDb->method('select')->willReturn([]);
|
||||
$mockDb->method('max')->willReturn(10);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$repository->save(0, $data, 1);
|
||||
|
||||
$pageInserts = array_filter($insertCalls, function ($c) {
|
||||
return $c['table'] === 'pp_articles_pages';
|
||||
});
|
||||
|
||||
$this->assertCount(2, $pageInserts);
|
||||
|
||||
$pageIds = array_map(function ($c) {
|
||||
return $c['row']['page_id'];
|
||||
}, array_values($pageInserts));
|
||||
|
||||
$this->assertContains(5, $pageIds);
|
||||
$this->assertContains(8, $pageIds);
|
||||
}
|
||||
|
||||
public function testSaveDeletesMarkedImagesOnUpdate(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$data = $this->getSampleData();
|
||||
$data['pages'] = null;
|
||||
|
||||
$mockDb->method('update')->willReturn(true);
|
||||
$mockDb->method('get')->willReturn(null);
|
||||
$mockDb->method('max')->willReturn(0);
|
||||
|
||||
$selectCalls = 0;
|
||||
$mockDb->method('select')
|
||||
->willReturnCallback(function ($table, $columns, $where) use (&$selectCalls) {
|
||||
$selectCalls++;
|
||||
// Return marked images for deletion query
|
||||
if ($table === 'pp_articles_images' && isset($where['AND']['to_delete'])) {
|
||||
return [['id' => 1, 'src' => '/nonexistent/path/img.jpg']];
|
||||
}
|
||||
if ($table === 'pp_articles_files' && isset($where['AND']['to_delete'])) {
|
||||
return [['id' => 2, 'src' => '/nonexistent/path/file.pdf']];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
$deleteCalls = [];
|
||||
$mockDb->method('delete')
|
||||
->willReturnCallback(function ($table, $where) use (&$deleteCalls) {
|
||||
$deleteCalls[] = ['table' => $table, 'where' => $where];
|
||||
return true;
|
||||
});
|
||||
|
||||
$mockDb->method('insert')->willReturn(true);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$repository->save(15, $data, 1);
|
||||
|
||||
$imageDeletes = array_filter($deleteCalls, function ($c) {
|
||||
return $c['table'] === 'pp_articles_images';
|
||||
});
|
||||
$fileDeletes = array_filter($deleteCalls, function ($c) {
|
||||
return $c['table'] === 'pp_articles_files';
|
||||
});
|
||||
|
||||
$this->assertNotEmpty($imageDeletes);
|
||||
$this->assertNotEmpty($fileDeletes);
|
||||
}
|
||||
|
||||
public function testArchiveSetsStatusToMinusOne(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->with('pp_articles', ['status' => -1], ['id' => 25])
|
||||
->willReturn(true);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$result = $repository->archive(25);
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testArchiveReturnsFalseWhenUpdateFails(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('update')
|
||||
->with('pp_articles', ['status' => -1], ['id' => 999])
|
||||
->willReturn(false);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$result = $repository->archive(999);
|
||||
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ date_default_timezone_set('Europe/Warsaw');
|
||||
// Stuby klas systemowych (nie dostępnych w testach unit)
|
||||
if (!class_exists('S')) {
|
||||
class S {
|
||||
public static function seo($str) { return $str; }
|
||||
public static function delete_dir($path) {}
|
||||
public static function alert($msg) {}
|
||||
public static function htacces() {}
|
||||
|
||||
Reference in New Issue
Block a user