feat: Refactor article handling and introduce ArticleRepository
- Introduced Domain\Article\ArticleRepository for better data access. - Migrated article_edit functionality to admin\Controllers\ArticlesController. - Updated admin\factory\Articles::article_details() to use the new repository. - Marked legacy methods in admin\controls as @deprecated for clarity. - Updated changelog and versioning to reflect changes in version 0.242.
This commit is contained in:
@@ -1 +1 @@
|
||||
{"version":1,"defects":[],"times":{"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetQuantityReturnsCorrectValue":0.001,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetQuantityReturnsNullWhenProductNotFound":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testFindReturnsProductData":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testUpdateQuantitySuccess":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetPriceReturnsRegularPrice":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetPriceReturnsPromoPrice":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetPriceReturnsRegularWhenPromoIsHigher":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetPriceReturnsNullWhenNotFound":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetNameReturnsProductName":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetNameReturnsNullWhenNotFound":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetQuantityReturnsInteger":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testUnarchiveUpdatesProductAndChildren":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testArchiveUpdatesProductAndChildren":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testUnarchiveReturnsBool":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testArchiveReturnsBool":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testConstructorAcceptsRepository":0.001,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testHasListMethod":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testHasUnarchiveMethod":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testListMethodReturnType":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testUnarchiveMethodReturnType":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testConstructorRequiresProductRepository":0,"Tests\\Unit\\Domain\\Banner\\BannerRepositoryTest::testFindReturnsBannerWithTranslations":0.004,"Tests\\Unit\\Domain\\Banner\\BannerRepositoryTest::testFindReturnsNullWhenNotFound":0,"Tests\\Unit\\Domain\\Banner\\BannerRepositoryTest::testDeleteReturnsTrue":0.002,"Tests\\Unit\\Domain\\Banner\\BannerRepositoryTest::testSaveInsertsNewBanner":0,"Tests\\Unit\\Domain\\Cache\\CacheRepositoryTest::testClearCacheWithRedis":0.001,"Tests\\Unit\\Domain\\Cache\\CacheRepositoryTest::testClearCacheRedisUnavailable":0,"Tests\\Unit\\Domain\\Cache\\CacheRepositoryTest::testClearCacheWithoutRedis":0,"Tests\\Unit\\Domain\\Cache\\CacheRepositoryTest::testClearCacheReturnStructure":0,"Tests\\Unit\\Domain\\Settings\\SettingsRepositoryTest::testCanBeInstantiated":0.001,"Tests\\Unit\\Domain\\Settings\\SettingsRepositoryTest::testHasSaveSettingsMethod":0,"Tests\\Unit\\Domain\\Settings\\SettingsRepositoryTest::testHasGetSettingsMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testConstructorAcceptsRepository":0.001,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testHasClearCacheMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testHasClearCacheAjaxMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testHasSaveMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testHasViewMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testIsNotAbstract":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testActionMethodReturnTypes":0}}
|
||||
{"version":1,"defects":[],"times":{"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetQuantityReturnsCorrectValue":0.001,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetQuantityReturnsNullWhenProductNotFound":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testFindReturnsProductData":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testUpdateQuantitySuccess":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetPriceReturnsRegularPrice":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetPriceReturnsPromoPrice":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetPriceReturnsRegularWhenPromoIsHigher":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetPriceReturnsNullWhenNotFound":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetNameReturnsProductName":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetNameReturnsNullWhenNotFound":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testGetQuantityReturnsInteger":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testUnarchiveUpdatesProductAndChildren":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testArchiveUpdatesProductAndChildren":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testUnarchiveReturnsBool":0,"Tests\\Unit\\Domain\\Product\\ProductRepositoryTest::testArchiveReturnsBool":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testConstructorAcceptsRepository":0.001,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testHasListMethod":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testHasUnarchiveMethod":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testListMethodReturnType":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testUnarchiveMethodReturnType":0,"Tests\\Unit\\admin\\Controllers\\ProductArchiveControllerTest::testConstructorRequiresProductRepository":0,"Tests\\Unit\\Domain\\Banner\\BannerRepositoryTest::testFindReturnsBannerWithTranslations":0.001,"Tests\\Unit\\Domain\\Banner\\BannerRepositoryTest::testFindReturnsNullWhenNotFound":0,"Tests\\Unit\\Domain\\Banner\\BannerRepositoryTest::testDeleteReturnsTrue":0.002,"Tests\\Unit\\Domain\\Banner\\BannerRepositoryTest::testSaveInsertsNewBanner":0,"Tests\\Unit\\Domain\\Cache\\CacheRepositoryTest::testClearCacheWithRedis":0.001,"Tests\\Unit\\Domain\\Cache\\CacheRepositoryTest::testClearCacheRedisUnavailable":0,"Tests\\Unit\\Domain\\Cache\\CacheRepositoryTest::testClearCacheWithoutRedis":0,"Tests\\Unit\\Domain\\Cache\\CacheRepositoryTest::testClearCacheReturnStructure":0,"Tests\\Unit\\Domain\\Settings\\SettingsRepositoryTest::testCanBeInstantiated":0.001,"Tests\\Unit\\Domain\\Settings\\SettingsRepositoryTest::testHasSaveSettingsMethod":0,"Tests\\Unit\\Domain\\Settings\\SettingsRepositoryTest::testHasGetSettingsMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testConstructorAcceptsRepository":0.001,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testHasClearCacheMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testHasClearCacheAjaxMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testHasSaveMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testHasViewMethod":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testIsNotAbstract":0,"Tests\\Unit\\admin\\Controllers\\SettingsControllerTest::testActionMethodReturnTypes":0,"Tests\\Unit\\admin\\Controllers\\ArticlesControllerTest::testCanCreateController":0.001,"Tests\\Unit\\admin\\Controllers\\ArticlesControllerTest::testHasListMethod":0,"Tests\\Unit\\admin\\Controllers\\ArticlesControllerTest::testListMethodReturnType":0,"Tests\\Unit\\admin\\Controllers\\ArticlesControllerTest::testHasEditMethod":0,"Tests\\Unit\\admin\\Controllers\\ArticlesControllerTest::testEditMethodReturnType":0,"Tests\\Unit\\admin\\Controllers\\ArticlesControllerTest::testConstructorAcceptsRepository":0,"Tests\\Unit\\admin\\Controllers\\ArticlesControllerTest::testConstructorRequiresArticleRepository":0,"Tests\\Unit\\Domain\\Article\\ArticleRepositoryTest::testFindReturnsArticleWithRelations":0.003,"Tests\\Unit\\Domain\\Article\\ArticleRepositoryTest::testFindReturnsNullWhenArticleDoesNotExist":0}}
|
||||
@@ -92,16 +92,49 @@ Artykuły.
|
||||
| id | PK |
|
||||
| status | -1 = archiwum, 0 = nieaktywny, 1 = aktywny |
|
||||
|
||||
**Używane w:** `admin\controls\ArticlesArchive`
|
||||
**Używane w:** `admin\controls\ArticlesArchive`, `Domain\Article\ArticleRepository::find()`
|
||||
|
||||
## pp_articles_pages
|
||||
Strony artykułów.
|
||||
|
||||
| Kolumna | Opis |
|
||||
|---------|------|
|
||||
| article_id | FK do pp_articles |
|
||||
| page_id | FK do strony (pp_pages) |
|
||||
| o | Kolejność |
|
||||
|
||||
**Używane w:** `Domain\Article\ArticleRepository::find()`
|
||||
|
||||
## pp_articles_langs
|
||||
Tłumaczenia artykułów.
|
||||
|
||||
| Kolumna | Opis |
|
||||
|---------|------|
|
||||
| article_id | FK do pp_articles |
|
||||
| lang_id | ID języka (np. 'pl') |
|
||||
| title | Tytuł artykułu |
|
||||
| seo_link | Link SEO artykułu |
|
||||
|
||||
**Używane w:** `Domain\Article\ArticleRepository::find()`
|
||||
|
||||
## pp_articles_images
|
||||
Zdjęcia artykułów.
|
||||
|
||||
| Kolumna | Opis |
|
||||
|---------|------|
|
||||
| article_id | FK do pp_articles |
|
||||
| src | Ścieżka do pliku |
|
||||
| o | Kolejność |
|
||||
| id | PK (używane też do sortowania DESC) |
|
||||
|
||||
**Używane w:** `Domain\Article\ArticleRepository::find()`
|
||||
|
||||
## pp_articles_files
|
||||
Pliki artykułów.
|
||||
|
||||
| Kolumna | Opis |
|
||||
|---------|------|
|
||||
| article_id | FK do pp_articles |
|
||||
| src | Ścieżka do pliku |
|
||||
|
||||
**Używane w:** `Domain\Article\ArticleRepository::find()`
|
||||
|
||||
@@ -246,10 +246,18 @@ tests/
|
||||
│ └── ProductArchiveControllerTest.php # 6 testów
|
||||
└── Integration/
|
||||
```
|
||||
**Łącznie: 39 testów, 73 asercji**
|
||||
**Ĺ<EFBFBD>Ä…cznie: 48 testów, 91 asercji**
|
||||
|
||||
## Ostatnie modyfikacje
|
||||
|
||||
### 2026-02-06: Migracja Articles::article_edit do DI (ver. 0.242)
|
||||
- **NOWE:** `Domain\Article\ArticleRepository` - repozytorium artykułów (`find()`)
|
||||
- **UPDATE:** `admin\Controllers\ArticlesController` - konstruktor DI + `edit()` uĹĽywa repozytorium
|
||||
- **UPDATE:** Router `admin\Site` - factory dla `ArticlesController` z `ArticleRepository`
|
||||
- **UPDATE:** `admin\factory\Articles::article_details()` deleguje do `Domain\Article\ArticleRepository`
|
||||
- **UPDATE:** Stare kontrolery `admin\controls\Articles|Banners|Settings` - metody przejęte przez nowe kontrolery oznaczone `@deprecated`
|
||||
- Testy: 48 testĂłw, 91 asercji
|
||||
|
||||
### 2026-02-06: Migracja ProductArchive (ver. 0.241)
|
||||
- **NOWE:** `admin\Controllers\ProductArchiveController` - kontroler archiwum produktĂłw z DI
|
||||
- **NOWE:** `ProductRepository::archive()`, `unarchive()` - operacje archiwizacji w repozytorium
|
||||
@@ -258,7 +266,7 @@ tests/
|
||||
- **FIX:** BrakujÄ…cy `archive = 1` w branchu bez wyszukiwania
|
||||
- **CLEANUP:** Usunięto zbędny JS z szablonu archiwum (apilo, baselinker, duplikowanie, edycja cen)
|
||||
- Stary kontroler `admin\controls\Archive` zachowany jako fallback
|
||||
- Testy: 39 testów, 73 asercji (+10 nowych)
|
||||
- Testy: 48 testów, 91 asercji (+10 nowych)
|
||||
|
||||
### 2026-02-05: Migracja Settings + Cache (ver. 0.240)
|
||||
- **NOWE:** `Domain\Settings\SettingsRepository` - repozytorium ustawień (fasada → factory)
|
||||
@@ -293,4 +301,5 @@ tests/
|
||||
- Metoda `clear_product_cache()` w klasie S
|
||||
|
||||
---
|
||||
*Dokument aktualizowany: 2026-02-05*
|
||||
*Dokument aktualizowany: 2026-02-06*
|
||||
|
||||
|
||||
@@ -174,6 +174,16 @@ grep -r "Product::getQuantity" .
|
||||
- Stara factory `admin\factory\Banners` zachowana bez zmian (fallback)
|
||||
- Aktualizacja: ver. 0.239
|
||||
|
||||
- **Articles** (migracja kontrolera - etap edit/details)
|
||||
- ✅ ArticleRepository::find() - **ZMIGROWANE** (2026-02-06) 🎉
|
||||
- Nowa klasa: `Domain\Article\ArticleRepository` (find: artykul + relacje)
|
||||
- Nowy kontroler: `admin\Controllers\ArticlesController` (DI, instancyjny)
|
||||
- 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: `tests/Unit/Domain/Article/ArticleRepositoryTest.php`, `tests/Unit/admin/Controllers/ArticlesControllerTest.php`
|
||||
- Aktualizacja: ver. 0.242
|
||||
|
||||
- **Settings** (migracja kontrolera - krok pośredni)
|
||||
- ✅ SettingsRepository - **ZMIGROWANE** (2026-02-05) 🎉
|
||||
- Nowa klasa: `Domain\Settings\SettingsRepository` (saveSettings, getSettings)
|
||||
@@ -217,7 +227,7 @@ tests/
|
||||
│ └── ProductArchiveControllerTest.php # 6 testów
|
||||
└── Integration/
|
||||
```
|
||||
**Łącznie: 39 testów, 73 asercji**
|
||||
**Łącznie: 48 testów, 91 asercji**
|
||||
|
||||
### Przykład testu
|
||||
```php
|
||||
@@ -305,4 +315,4 @@ vendor/bin/phpstan analyse autoload/Domain
|
||||
|
||||
---
|
||||
*Rozpoczęto: 2025-02-05*
|
||||
*Ostatnia aktualizacja: 2026-02-05*
|
||||
*Ostatnia aktualizacja: 2026-02-06*
|
||||
|
||||
@@ -11,6 +11,9 @@ Aktualizacje znajdują się w folderze `updates/0.XX/` gdzie XX oznacza dziesią
|
||||
- `changelog.php` - historia zmian
|
||||
- `versions.php` - konfiguracja wersji (zmienna `$current_ver`)
|
||||
|
||||
### Zasada pakowania plików
|
||||
- Do paczek aktualizacji **nie dodajemy plików `*.md`** (dokumentacja jest tylko wewnętrzna/deweloperska).
|
||||
|
||||
## Procedura tworzenia nowej aktualizacji
|
||||
|
||||
### 1. Określ numer wersji
|
||||
|
||||
43
autoload/Domain/Article/ArticleRepository.php
Normal file
43
autoload/Domain/Article/ArticleRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace Domain\Article;
|
||||
|
||||
/**
|
||||
* Repository odpowiedzialny za dostep do danych artykulow
|
||||
*/
|
||||
class ArticleRepository
|
||||
{
|
||||
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']
|
||||
]);
|
||||
$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;
|
||||
}
|
||||
}
|
||||
46
autoload/admin/Controllers/ArticlesController.php
Normal file
46
autoload/admin/Controllers/ArticlesController.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace admin\Controllers;
|
||||
|
||||
use Domain\Article\ArticleRepository;
|
||||
|
||||
class ArticlesController
|
||||
{
|
||||
private ArticleRepository $repository;
|
||||
|
||||
public function __construct(ArticleRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lista artykulow
|
||||
*/
|
||||
public function list(): string
|
||||
{
|
||||
return \admin\view\Articles::articles_list();
|
||||
}
|
||||
|
||||
/**
|
||||
* Edycja artykulu
|
||||
*/
|
||||
public function edit(): string
|
||||
{
|
||||
global $user;
|
||||
|
||||
if (!$user) {
|
||||
header('Location: /admin/');
|
||||
exit;
|
||||
}
|
||||
|
||||
\admin\factory\Articles::delete_nonassigned_images();
|
||||
\admin\factory\Articles::delete_nonassigned_files();
|
||||
|
||||
return \Tpl::view('articles/article-edit', [
|
||||
'article' => $this->repository->find((int)\S::get('id')),
|
||||
'menus' => \admin\factory\Pages::menus_list(),
|
||||
'languages' => \admin\factory\Languages::languages_list(),
|
||||
'layouts' => \admin\factory\Layouts::layouts_list(),
|
||||
'user' => $user
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -199,6 +199,13 @@ class Site
|
||||
return self::$newControllers;
|
||||
|
||||
self::$newControllers = [
|
||||
'Articles' => function() {
|
||||
global $mdb;
|
||||
|
||||
return new \admin\Controllers\ArticlesController(
|
||||
new \Domain\Article\ArticleRepository( $mdb )
|
||||
);
|
||||
},
|
||||
'Banners' => function() {
|
||||
global $mdb;
|
||||
|
||||
@@ -247,6 +254,7 @@ class Site
|
||||
*/
|
||||
private static $actionMap = [
|
||||
'view_list' => 'list',
|
||||
'article_edit' => 'edit',
|
||||
'banner_edit' => 'edit',
|
||||
'banner_save' => 'save',
|
||||
'banner_delete' => 'delete',
|
||||
|
||||
@@ -39,6 +39,10 @@ class Articles
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\ArticlesController::edit().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function article_edit() {
|
||||
global $user;
|
||||
|
||||
@@ -59,9 +63,13 @@ class Articles
|
||||
] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\ArticlesController::list().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function view_list()
|
||||
{
|
||||
return \admin\view\Articles::articles_list();
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -9,6 +9,10 @@ namespace admin\controls;
|
||||
*/
|
||||
class Banners
|
||||
{
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\BannerController::delete().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function banner_delete()
|
||||
{
|
||||
if ( \admin\factory\Banners::banner_delete( \S::get( 'id' ) ) )
|
||||
@@ -17,6 +21,10 @@ class Banners
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\BannerController::save().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function banner_save()
|
||||
{
|
||||
$response = [ 'status' => 'error', 'msg' => 'Podczas zapisywania baneru wystąpił błąd. Proszę spróbować ponownie.' ];
|
||||
@@ -30,6 +38,10 @@ class Banners
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\BannerController::edit().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function banner_edit()
|
||||
{
|
||||
return \admin\view\Banners::banner_edit(
|
||||
@@ -40,6 +52,10 @@ class Banners
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\BannerController::list().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function view_list()
|
||||
{
|
||||
return \admin\view\Banners::banners_list();
|
||||
|
||||
@@ -3,6 +3,10 @@ namespace admin\controls;
|
||||
|
||||
class Settings
|
||||
{
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\SettingsController::clearCache().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
static public function clear_cache()
|
||||
{
|
||||
\S::delete_dir( '../temp/' );
|
||||
@@ -17,6 +21,10 @@ class Settings
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\SettingsController::clearCacheAjax().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
static public function clear_cache_ajax()
|
||||
{
|
||||
try
|
||||
@@ -41,6 +49,10 @@ class Settings
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\SettingsController::save().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function settings_save()
|
||||
{
|
||||
$values = json_decode( \S::get( 'values' ), true );
|
||||
@@ -88,6 +100,10 @@ class Settings
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Routing kieruje do admin\Controllers\SettingsController::view().
|
||||
* Ta metoda pozostaje tylko jako fallback dla starej architektury.
|
||||
*/
|
||||
public static function view()
|
||||
{
|
||||
return \Tpl::view( 'settings/settings', [
|
||||
@@ -96,4 +112,4 @@ class Settings
|
||||
] );
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -123,19 +123,8 @@ class Articles
|
||||
public static function article_details( $article_id )
|
||||
{
|
||||
global $mdb;
|
||||
|
||||
if ( $article = $mdb -> get( 'pp_articles', '*', [ 'id' => (int)$article_id ] ) )
|
||||
{
|
||||
$results = $mdb -> select( 'pp_articles_langs', '*', [ 'article_id' => (int)$article_id ] );
|
||||
if ( is_array( $results ) ) foreach ( $results as $row )
|
||||
$article['languages'][ $row['lang_id'] ] = $row;
|
||||
|
||||
$article['images'] = $mdb -> select( 'pp_articles_images', '*', [ 'article_id' => (int)$article_id, 'ORDER' => [ 'o' => 'ASC', 'id' => 'DESC' ] ] );
|
||||
$article['files'] = $mdb -> select( 'pp_articles_files', '*', [ 'article_id' => (int)$article_id ] );
|
||||
$article['pages'] = $mdb -> select( 'pp_articles_pages', 'page_id', [ 'article_id' => (int)$article_id ] );
|
||||
}
|
||||
|
||||
return $article;
|
||||
$repository = new \Domain\Article\ArticleRepository( $mdb );
|
||||
return $repository->find( (int)$article_id );
|
||||
}
|
||||
|
||||
public static function max_order()
|
||||
@@ -469,4 +458,4 @@ class Articles
|
||||
$mdb -> delete( 'pp_articles_images', [ 'article_id' => null ] );
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
60
tests/Unit/Domain/Article/ArticleRepositoryTest.php
Normal file
60
tests/Unit/Domain/Article/ArticleRepositoryTest.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
namespace Tests\Unit\Domain\Article;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Domain\Article\ArticleRepository;
|
||||
|
||||
class ArticleRepositoryTest extends TestCase
|
||||
{
|
||||
public function testFindReturnsArticleWithRelations(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_articles', '*', ['id' => 7])
|
||||
->willReturn(['id' => 7, 'status' => 1]);
|
||||
|
||||
$mockDb->expects($this->exactly(4))
|
||||
->method('select')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[
|
||||
['lang_id' => 'pl', 'title' => 'Artykul'],
|
||||
['lang_id' => 'en', 'title' => 'Article'],
|
||||
],
|
||||
[
|
||||
['id' => 10, 'src' => '/img/a.jpg']
|
||||
],
|
||||
[
|
||||
['id' => 20, 'src' => '/files/a.pdf']
|
||||
],
|
||||
[1, 2]
|
||||
);
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$article = $repository->find(7);
|
||||
|
||||
$this->assertIsArray($article);
|
||||
$this->assertEquals(7, $article['id']);
|
||||
$this->assertArrayHasKey('languages', $article);
|
||||
$this->assertEquals('Artykul', $article['languages']['pl']['title']);
|
||||
$this->assertCount(1, $article['images']);
|
||||
$this->assertCount(1, $article['files']);
|
||||
$this->assertEquals([1, 2], $article['pages']);
|
||||
}
|
||||
|
||||
public function testFindReturnsNullWhenArticleDoesNotExist(): void
|
||||
{
|
||||
$mockDb = $this->createMock(\medoo::class);
|
||||
$mockDb->expects($this->once())
|
||||
->method('get')
|
||||
->with('pp_articles', '*', ['id' => 999])
|
||||
->willReturn(false);
|
||||
$mockDb->expects($this->never())->method('select');
|
||||
|
||||
$repository = new ArticleRepository($mockDb);
|
||||
$article = $repository->find(999);
|
||||
|
||||
$this->assertNull($article);
|
||||
}
|
||||
}
|
||||
61
tests/Unit/admin/Controllers/ArticlesControllerTest.php
Normal file
61
tests/Unit/admin/Controllers/ArticlesControllerTest.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace Tests\Unit\admin\Controllers;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use admin\Controllers\ArticlesController;
|
||||
use Domain\Article\ArticleRepository;
|
||||
|
||||
class ArticlesControllerTest extends TestCase
|
||||
{
|
||||
private $mockRepository;
|
||||
private $controller;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->mockRepository = $this->createMock(ArticleRepository::class);
|
||||
$this->controller = new ArticlesController($this->mockRepository);
|
||||
}
|
||||
|
||||
public function testCanCreateController(): void
|
||||
{
|
||||
$this->assertInstanceOf(ArticlesController::class, $this->controller);
|
||||
}
|
||||
|
||||
public function testConstructorAcceptsRepository(): void
|
||||
{
|
||||
$controller = new ArticlesController($this->mockRepository);
|
||||
$this->assertInstanceOf(ArticlesController::class, $controller);
|
||||
}
|
||||
|
||||
public function testHasListMethod(): void
|
||||
{
|
||||
$this->assertTrue(method_exists($this->controller, 'list'));
|
||||
}
|
||||
|
||||
public function testHasEditMethod(): void
|
||||
{
|
||||
$this->assertTrue(method_exists($this->controller, 'edit'));
|
||||
}
|
||||
|
||||
public function testListMethodReturnType(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->controller);
|
||||
$this->assertEquals('string', (string)$reflection->getMethod('list')->getReturnType());
|
||||
}
|
||||
|
||||
public function testEditMethodReturnType(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass($this->controller);
|
||||
$this->assertEquals('string', (string)$reflection->getMethod('edit')->getReturnType());
|
||||
}
|
||||
|
||||
public function testConstructorRequiresArticleRepository(): void
|
||||
{
|
||||
$reflection = new \ReflectionClass(ArticlesController::class);
|
||||
$constructor = $reflection->getConstructor();
|
||||
$params = $constructor->getParameters();
|
||||
|
||||
$this->assertCount(1, $params);
|
||||
$this->assertEquals('Domain\Article\ArticleRepository', $params[0]->getType()->getName());
|
||||
}
|
||||
}
|
||||
BIN
updates/0.20/ver_0.242.zip
Normal file
BIN
updates/0.20/ver_0.242.zip
Normal file
Binary file not shown.
@@ -1,4 +1,8 @@
|
||||
<b>ver. 0.241</b><br />
|
||||
<b>ver. 0.242</b><br />
|
||||
- NEW - refaktoryzacja: Domain\Article\ArticleRepository + migracja article_edit do admin\Controllers\ArticlesController (DI)
|
||||
- UPDATE - admin\factory\Articles::article_details() deleguje do nowego repozytorium (kompatybilność zachowana)
|
||||
- UPDATE - metody przejęte przez nowe kontrolery oznaczone jako @deprecated w legacy kontrolerach admin\controls
|
||||
<hr><b>ver. 0.241</b><br />
|
||||
- NEW - refaktoryzacja: admin\Controllers\ProductArchiveController - archiwum produktĂłw z DI
|
||||
- NEW - ProductRepository::archive(), unarchive() - operacje archiwizacji w repozytorium
|
||||
- FIX - naprawiono SQL w liście archiwum (puste wyszukiwanie filtrowało wszystkie wyniki)
|
||||
@@ -298,4 +302,4 @@
|
||||
- FIX - poprawa generowania plikĂłw WEBP
|
||||
<hr>
|
||||
<b>ver. 0.142</b><br />
|
||||
- FIX - poprawa adresu strony głównej
|
||||
- FIX - poprawa adresu strony głównej
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?
|
||||
$current_ver = 241;
|
||||
$current_ver = 242;
|
||||
|
||||
for ($i = 1; $i <= $current_ver; $i++)
|
||||
{
|
||||
@@ -43,4 +43,4 @@ else
|
||||
{
|
||||
foreach ($versions as $ver)
|
||||
echo $ver . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user