ver. 0.278: Settings + Languages frontend migration, bug fix get_single_settings_value

- Add cached frontend methods to existing Domain repositories (allSettings, getSingleValue, defaultLanguage, activeLanguages, translations)
- Convert front\factory\Settings and Languages to facades delegating to Domain repositories
- Fix get_single_settings_value() - was hardcoded to 'firm_name', now uses $param correctly
- Add CacheHandler stub methods (get/set/exists) to test bootstrap
- Establish architectural rule: Domain classes are shared between admin and frontend

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 13:50:27 +01:00
parent 7fcac87a58
commit 782dd35d5b
14 changed files with 483 additions and 164 deletions

View File

@@ -332,6 +332,85 @@ class LanguagesRepository
return $translationId;
}
/**
* Zwraca ID domyslnego jezyka (z flaga start=1) z cache Redis.
*/
public function defaultLanguage(): string
{
$cacheHandler = new \CacheHandler();
$cacheKey = 'Domain\Languages\LanguagesRepository::defaultLanguage';
$objectData = $cacheHandler->get($cacheKey);
if ($objectData) {
return unserialize($objectData);
}
$results = $this->db->query(
'SELECT id FROM pp_langs WHERE status = 1 ORDER BY start DESC, o ASC LIMIT 1'
)->fetchAll();
$defaultLanguage = $results[0][0] ?? 'pl';
$cacheHandler->set($cacheKey, $defaultLanguage);
return $defaultLanguage;
}
/**
* Zwraca liste aktywnych jezykow z cache Redis.
*/
public function activeLanguages(): array
{
$cacheHandler = new \CacheHandler();
$cacheKey = 'Domain\Languages\LanguagesRepository::activeLanguages';
$objectData = $cacheHandler->get($cacheKey);
if ($objectData) {
return unserialize($objectData);
}
$activeLanguages = $this->db->select(
'pp_langs',
['id', 'name'],
['status' => 1, 'ORDER' => ['o' => 'ASC']]
);
if (!is_array($activeLanguages)) {
$activeLanguages = [];
}
$cacheHandler->set($cacheKey, $activeLanguages);
return $activeLanguages;
}
/**
* Zwraca tlumaczenia dla danego jezyka z cache Redis.
*/
public function translations(string $language = 'pl'): array
{
$cacheHandler = new \CacheHandler();
$cacheKey = "Domain\Languages\LanguagesRepository::translations:$language";
$objectData = $cacheHandler->get($cacheKey);
if ($objectData) {
return unserialize($objectData);
}
$translations = ['0' => $language];
$results = $this->db->select('pp_langs_translations', ['text', $language]);
if (is_array($results)) {
foreach ($results as $row) {
$translations[$row['text']] = $row[$language];
}
}
$cacheHandler->set($cacheKey, $translations);
return $translations;
}
private function sanitizeLanguageId(string $languageId): ?string
{
$languageId = strtolower(trim($languageId));

View File

@@ -2,7 +2,7 @@
namespace Domain\Settings;
/**
* Repozytorium ustawien panelu administratora.
* Repozytorium ustawien — wspolne dla admin i frontendu.
*/
class SettingsRepository
{
@@ -141,6 +141,58 @@ class SettingsRepository
return $settings;
}
/**
* Pobranie wszystkich ustawien z cache Redis.
*
* @param bool $skipCache Pomija cache (np. przy generowaniu htaccess)
*/
public function allSettings(bool $skipCache = false): array
{
$cacheHandler = new \CacheHandler();
$cacheKey = 'Domain\Settings\SettingsRepository::allSettings';
if (!$skipCache) {
$objectData = $cacheHandler->get($cacheKey);
if ($objectData) {
return unserialize($objectData);
}
}
$results = $this->db->select('pp_settings', '*');
$settings = [];
if (is_array($results)) {
foreach ($results as $row) {
$settings[$row['param']] = $row['value'];
}
}
$cacheHandler->set($cacheKey, $settings);
return $settings;
}
/**
* Pobranie pojedynczej wartosci ustawienia po nazwie parametru.
*/
public function getSingleValue(string $param): string
{
$cacheHandler = new \CacheHandler();
$cacheKey = "Domain\Settings\SettingsRepository::getSingleValue:$param";
$objectData = $cacheHandler->get($cacheKey);
if ($objectData) {
return unserialize($objectData);
}
$value = $this->db->get('pp_settings', 'value', ['param' => $param]);
$value = (string)($value ?? '');
$cacheHandler->set($cacheKey, $value);
return $value;
}
private function isEnabled($value): bool
{
if (is_bool($value)) {

View File

@@ -1,78 +1,29 @@
<?php
namespace front\factory;
/**
* Fasada delegujaca do Domain\Languages\LanguagesRepository.
*/
class Languages
{
public static function default_language()
{
global $mdb;
$cacheHandler = new \CacheHandler();
$cacheKey = "\front\factory\Languages::default_language";
$objectData = $cacheHandler->get($cacheKey);
if ( !$objectData )
public static function default_language()
{
$results = $mdb -> query( 'SELECT id FROM pp_langs WHERE status = 1 ORDER BY start DESC, o ASC LIMIT 1' ) -> fetchAll();
$default_language = $results[0][0];
$cacheHandler -> set( $cacheKey, $default_language );
}
else
{
return unserialize($objectData);
}
return $default_language;
}
public static function active_languages()
{
global $mdb;
$cacheHandler = new \CacheHandler();
$cacheKey = "\front\factory\Languages::active_languages";
$objectData = $cacheHandler -> get( $cacheKey );
if ( !$objectData )
{
$active_languages = $mdb -> select( 'pp_langs', [ 'id', 'name' ], [ 'status' => 1, 'ORDER' => [ 'o' => 'ASC' ] ] );
$cacheHandler -> set( $cacheKey, $active_languages );
}
else
{
return unserialize( $objectData );
global $mdb;
$repo = new \Domain\Languages\LanguagesRepository($mdb);
return $repo->defaultLanguage();
}
return $active_languages;
}
public static function lang_translations( $language = 'pl' )
{
global $mdb;
$cacheHandler = new \CacheHandler();
$cacheKey = "\front\factory\Languages::lang_translations:$language";
$objectData = $cacheHandler -> get( $cacheKey );
if ( !$objectData )
public static function active_languages()
{
$translations[ '0' ] = $language;
$results = $mdb -> select( 'pp_langs_translations', [ 'text', $language ] );
if ( is_array( $results ) ) foreach ( $results as $row )
$translations[ $row['text'] ] = $row[ $language ];
$cacheHandler -> set( $cacheKey, $translations );
}
else
{
return unserialize( $objectData );
global $mdb;
$repo = new \Domain\Languages\LanguagesRepository($mdb);
return $repo->activeLanguages();
}
return $translations;
}
public static function lang_translations($language = 'pl')
{
global $mdb;
$repo = new \Domain\Languages\LanguagesRepository($mdb);
return $repo->translations($language);
}
}

View File

@@ -1,43 +1,22 @@
<?php
namespace front\factory;
/**
* Fasada delegujaca do Domain\Settings\SettingsRepository.
*/
class Settings
{
public static function settings_details( $admin = false )
{
global $mdb;
$cacheHandler = new \CacheHandler();
$cacheKey = "\front\factory\Settings::settings_details";
$objectData = $cacheHandler->get($cacheKey);
if ( !$objectData or $admin )
public static function settings_details($admin = false)
{
$results = $mdb -> select( 'pp_settings', '*' );
if ( is_array( $results ) ) foreach ( $results as $row )
$settings[ $row['param'] ] = $row['value'];
$cacheHandler -> set( $cacheKey, $settings );
global $mdb;
$repo = new \Domain\Settings\SettingsRepository($mdb);
return $repo->allSettings($admin);
}
else
public static function get_single_settings_value($param)
{
return unserialize( $objectData );
global $mdb;
$repo = new \Domain\Settings\SettingsRepository($mdb);
return $repo->getSingleValue($param);
}
return $settings;
}
static public function get_single_settings_value( $param ) {
global $mdb;
if ( !$value = \Cache::fetch( "get_single_settings_value:$param" ) ) {
$value = $mdb -> get( 'pp_settings', 'value', [ 'param' => 'firm_name' ] );
\Cache::store( "get_single_settings_value:$param", $value );
}
return $value;
}
}

View File

@@ -4,6 +4,21 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze.
---
## ver. 0.278 (2026-02-16) - Settings + Languages frontend migration
- **Settings + Languages (frontend)** — pierwszy etap refaktoringu frontendu
- NOWE METODY: `SettingsRepository::allSettings($skipCache)` — pobranie ustawien z cache Redis
- NOWE METODY: `SettingsRepository::getSingleValue($param)` — pobranie pojedynczej wartosci ustawienia
- NOWE METODY: `LanguagesRepository::defaultLanguage()` — domyslny jezyk z cache Redis
- NOWE METODY: `LanguagesRepository::activeLanguages()` — lista aktywnych jezykow z cache Redis
- NOWE METODY: `LanguagesRepository::translations($lang)` — tlumaczenia z cache Redis
- UPDATE: `front\factory\Settings` → fasada delegujaca do `SettingsRepository`
- UPDATE: `front\factory\Languages` → fasada delegujaca do `LanguagesRepository`
- FIX: `get_single_settings_value()` — parametr `$param` poprawnie uzywany (wczesniej hardcoded `'firm_name'`)
- Testy: 427 OK, 1378 asercji (+13 nowych)
---
## ver. 0.277 (2026-02-16) - ShopProduct factory, Dashboard, Update, legacy cleanup, admin\App
- **ShopProduct (factory)** - pelna migracja modulu #29 na Domain + DI

View File

@@ -153,26 +153,27 @@ Legacy Cleanup
---
## Plan wersjonowany
## Etapy migracji
### ver. 0.278 — Settings + Languages Frontend Services
### Etap: Settings + Languages — ZREALIZOWANY
**Cel:** Stworzyć serwisy domenowe dla Settings i Languages, naprawić buga Settings.
**Cel:** Dodac metody frontendowe (z cache Redis) do istniejacych repozytoriow Domain.
**NOWE:**
- `Domain/Settings/SettingsFrontendService.php``allSettings()`, `getSingleValue($param)` (FIX: używa poprawnie $param)
- `Domain/Languages/LanguagesFrontendService.php``defaultLanguage()`, `activeLanguages()`, `translations($lang)`
- Testy: `SettingsFrontendServiceTest`, `LanguagesFrontendServiceTest`
**DODANE METODY (do istniejacych klas):**
- `Domain/Settings/SettingsRepository``allSettings($skipCache)`, `getSingleValue($param)` (FIX: uzywa poprawnie $param)
- `Domain/Languages/LanguagesRepository``defaultLanguage()`, `activeLanguages()`, `translations($lang)`
- Testy: dopisane do `SettingsRepositoryTest` (6 testow), `LanguagesRepositoryTest` (7 testow)
**ZMIANA:**
- `front/factory/Settings` → fasada delegująca do `SettingsFrontendService`
- `front/factory/Languages` → fasada delegująca do `LanguagesFrontendService`
- `front/factory/Settings` → fasada delegujaca do `SettingsRepository`
- `front/factory/Languages` → fasada delegujaca do `LanguagesRepository`
- `tests/bootstrap.php` — uzupelniony stub CacheHandler o `get()`/`set()`/`exists()`
**BUG FIX:** `get_single_settings_value()` — zmiana `['param' => 'firm_name']` na `['param' => $param]`
---
### ver. 0.279 — Category Frontend Service
### Etap: Category Frontend Service
**Cel:** Migracja `front\factory\ShopCategory` do Domain.
@@ -186,7 +187,7 @@ Legacy Cleanup
---
### ver. 0.280 — Banners, Menu, Pages, Articles, Layouts Frontend Services
### Etap: Banners, Menu, Pages, Articles, Layouts Frontend Services
**Cel:** Migracja pozostałych fabryk "liściowych".
@@ -205,7 +206,7 @@ Legacy Cleanup
---
### ver. 0.281 — Promotion Engine (rozbicie circular dependency)
### Etap: Promotion Engine (rozbicie circular dependency)
**Cel:** Przeniesienie silnika promocji do Domain. Rozbicie cyklicznej zależności `shop\Promotion ↔ front\factory\ShopPromotion`.
@@ -231,7 +232,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.282 — Product Frontend Service
### Etap: Product Frontend Service
**Cel:** Migracja `front\factory\ShopProduct` i statycznych metod `shop\Product` do Domain.
@@ -245,11 +246,11 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
- `front/factory/ShopProduct` → fasada
- `shop/Product` statyczne metody → fasady do `ProductFrontendService`
**UWAGA:** Konstruktor `shop\Product`, `getFromCache()`, `calculate_basket_product_price()` — zostają na razie (instancyjne, używane w szablonach). Migracja w ver. 0.286.
**UWAGA:** Konstruktor `shop\Product`, `getFromCache()`, `calculate_basket_product_price()` — zostają na razie (instancyjne, używane w szablonach). Migracja w etapie "Product Instance + Cache".
---
### ver. 0.283 — Client Authentication (Security Fix)
### Etap: Client Authentication (Security Fix)
**Cel:** Migracja `front\factory\ShopClient` + NAPRAWIENIE hardcoded password bypass.
@@ -267,7 +268,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.284 — Transport, Payment, Coupon Frontend Services
### Etap: Transport, Payment, Coupon Frontend Services
**Cel:** Frontend serwisy dla transportu, płatności i kuponów.
@@ -285,7 +286,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.285 — Basket Service
### Etap: Basket Service
**Cel:** Migracja logiki koszyka do `Domain\Basket\BasketService`.
@@ -305,7 +306,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.286 — shop\Product Instance + Cache
### Etap: shop\Product Instance + Cache
**Cel:** Refaktoring konstruktora `shop\Product` i `getFromCache()`.
@@ -321,7 +322,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.287 — Order Creation Frontend Service
### Etap: Order Creation Frontend Service
**Cel:** Migracja `front\factory\ShopOrder::basket_save()` (~180 linii).
@@ -337,7 +338,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.288 — Payment Webhook Service
### Etap: Payment Webhook Service
**Cel:** Wyodrębnienie webhooków płatności z `front\controls\ShopOrder`.
@@ -356,7 +357,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.289 — shop\Order Instance + Apilo Service
### Etap: shop\Order Instance + Apilo Service
**Cel:** Refaktoring `shop\Order` instancyjnych metod + wyodrębnienie integracji Apilo.
@@ -374,7 +375,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.290 — Frontend App + Controllers (DI layer)
### Etap: Frontend App + Controllers (DI layer)
**Cel:** Stworzenie `front\App` (wzorowanego na `admin\App`) z mapą kontrolerów i DI.
@@ -390,7 +391,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.291 — Site Layout Engine
### Etap: Site Layout Engine
**Cel:** Refaktoring `front\view\Site::show()` (~600 linii) na testowalny `LayoutEngine`.
@@ -406,7 +407,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.292 — Entry Point Unification
### Etap: Entry Point Unification
**Cel:** Ujednolicenie bootstrapu `index.php` i `ajax.php`.
@@ -420,7 +421,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
---
### ver. 0.293 — Legacy Cleanup
### Etap: Legacy Cleanup
**Cel:** Finalne porządki.
@@ -440,26 +441,26 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
## Podsumowanie
| Wersja | Zakres | Priorytet | Nowe klasy Domain | Testy |
|--------|--------|-----------|-------------------|-------|
| 0.278 | Settings + Languages | FUNDAMENT | 2 serwisy | 2 |
| 0.279 | Category Frontend | WYSOKI | 1 serwis | 1 |
| 0.280 | Banners/Menu/Pages/Articles/Layouts | ŚREDNI | 5 serwisów | 5 |
| 0.281 | Promotion Engine | KRYTYCZNY | 1 serwis | 1 |
| 0.282 | Product Frontend | KRYTYCZNY | 1 serwis | 1 |
| 0.283 | Client/Auth (security fix) | KRYTYCZNY | 1 serwis | 1 |
| 0.284 | Transport/Payment/Coupon | WYSOKI | 3 serwisy | 3 |
| 0.285 | Basket Service | WYSOKI | 1 serwis | 1 |
| 0.286 | Product Instance + Cache | ŚREDNI | 1 loader | 1 |
| 0.287 | Order Creation | WYSOKI | 1 serwis | 1 |
| 0.288 | Payment Webhooks | WYSOKI | 1 serwis | 1 |
| 0.289 | Order Instance + Apilo | ŚREDNI | 2 serwisy | 2 |
| 0.290 | Frontend App + Controllers | WYSOKI | App + 3 kontrolery | 3 |
| 0.291 | Layout Engine | ŚREDNI | 1 engine | 1 |
| 0.292 | Entry Point Unification | ŚREDNI | Bootstrap + PostProcessor | 1 |
| 0.293 | Legacy Cleanup | NISKI | — | — |
| Etap | Zakres | Priorytet | Nowe klasy Domain | Testy |
|------|--------|-----------|-------------------|-------|
| Settings + Languages | Fundamenty | FUNDAMENT | 2 serwisy | 2 |
| Category Frontend | Kategorie | WYSOKI | 1 serwis | 1 |
| Banners/Menu/Pages/Articles/Layouts | Treści | ŚREDNI | 5 serwisów | 5 |
| Promotion Engine | Promocje | KRYTYCZNY | 1 serwis | 1 |
| Product Frontend | Produkty | KRYTYCZNY | 1 serwis | 1 |
| Client/Auth (security fix) | Klienci | KRYTYCZNY | 1 serwis | 1 |
| Transport/Payment/Coupon | Dostawa/Płatności | WYSOKI | 3 serwisy | 3 |
| Basket Service | Koszyk | WYSOKI | 1 serwis | 1 |
| Product Instance + Cache | Produkt cache | ŚREDNI | 1 loader | 1 |
| Order Creation | Zamówienia | WYSOKI | 1 serwis | 1 |
| Payment Webhooks | Webhooki | WYSOKI | 1 serwis | 1 |
| Order Instance + Apilo | Zamówienie + Apilo | ŚREDNI | 2 serwisy | 2 |
| Frontend App + Controllers | DI layer | WYSOKI | App + 3 kontrolery | 3 |
| Layout Engine | Silnik layoutu | ŚREDNI | 1 engine | 1 |
| Entry Point Unification | Entry points | ŚREDNI | Bootstrap + PostProcessor | 1 |
| Legacy Cleanup | Porządki | NISKI | — | — |
**Łącznie:** 16 wersji, ~24 nowe klasy Domain, ~25 plików testowych
**Łącznie:** 16 etapów, ~24 nowe klasy Domain, ~25 plików testowych
### Wzorce do przestrzegania (z migracji admin)
- Konstruktor DI z `$db` (medoo)
@@ -468,8 +469,9 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on
- Testy PHPUnit z mockami medoo
- Namespace `\Domain\*``autoload/Domain/*/`
- Namespace `\front\Controllers\``autoload/front/Controllers/`
- **Klasy Domain sa wspolne dla admin i frontendu** — NIE tworzymy osobnych FrontendService/AdminService. Metody frontendowe (z cache Redis) dodajemy do istniejacych repozytoriow/serwisow Domain. Klasy sa ladowane lazy (instancja tworzona dopiero przy wywolaniu), wiec nie wplywaja na wydajnosc.
### Weryfikacja po każdej wersji
### Weryfikacja po każdym etapie
1. `composer test` (pełny suite PHPUnit)
2. Manualne sprawdzenie frontendu: strona główna, kategoria, produkt, koszyk, zamówienie
3. Sprawdzenie AJAX: dodawanie do koszyka, zmiana transportu, kupon

View File

@@ -36,7 +36,14 @@ Alternatywnie (Git Bash):
Ostatnio zweryfikowano: 2026-02-16
```text
OK (414 tests, 1335 assertions)
OK (427 tests, 1378 assertions)
```
Aktualizacja po migracji Settings + Languages frontend (2026-02-16, ver. 0.278):
```text
Pelny suite: OK (427 tests, 1378 assertions)
Nowe testy: SettingsRepositoryTest (+6: allSettings, getSingleValue, bugfix param), LanguagesRepositoryTest (+7: defaultLanguage, activeLanguages, translations)
Zaktualizowane: tests/bootstrap.php (stub CacheHandler: get/set/exists)
```
Aktualizacja po migracji Dashboard + Update + legacy cleanup (2026-02-16, ver. 0.277):

View File

@@ -18,20 +18,19 @@ Aktualizacje znajdują się w folderze `updates/0.XX/` gdzie XX oznacza dziesią
## Procedura tworzenia nowej aktualizacji
## Status biezacej aktualizacji (ver. 0.277)
## Status biezacej aktualizacji (ver. 0.278)
- Wersja udostepniona: `0.277` (data: 2026-02-16).
- Wersja udostepniona: `0.278` (data: 2026-02-16).
- Pliki publikacyjne:
- `updates/0.20/ver_0.277.zip`
- `updates/0.20/ver_0.277_files.txt`
- `updates/0.20/ver_0.278.zip`
- Pliki metadanych aktualizacji:
- `updates/changelog.php` (dodany wpis `ver. 0.277`)
- `updates/versions.php` (`$current_ver = 277`)
- `updates/changelog.php` (dodany wpis `ver. 0.278`)
- `updates/versions.php` (`$current_ver = 278`)
- Weryfikacja testow przed publikacja:
- `OK (414 tests, 1335 assertions)`
- `OK (427 tests, 1378 assertions)`
### 1. Określ numer wersji
Sprawdź ostatnią wersję w `temp/` i zwiększ o 1.
Sprawdź ostatnią wersję w `updates/` i zwiększ o 1.
### 2. Utwórz folder tymczasowy ze strukturą w katalogu temp
```bash

View File

@@ -145,4 +145,140 @@ class LanguagesRepositoryTest extends TestCase
$this->assertSame('en', $repository->defaultLanguageId());
$this->assertSame('pl', $repository->defaultLanguageId());
}
// --- Metody frontendowe (z cache Redis) ---
public function testDefaultLanguageReturnsId(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockStmt = $this->createMock(\PDOStatement::class);
$mockStmt->expects($this->once())
->method('fetchAll')
->willReturn([['pl']]);
$mockDb->expects($this->once())
->method('query')
->with('SELECT id FROM pp_langs WHERE status = 1 ORDER BY start DESC, o ASC LIMIT 1')
->willReturn($mockStmt);
$repository = new LanguagesRepository($mockDb);
$langId = $repository->defaultLanguage();
$this->assertEquals('pl', $langId);
}
public function testDefaultLanguageReturnsFallbackWhenEmpty(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockStmt = $this->createMock(\PDOStatement::class);
$mockStmt->expects($this->once())
->method('fetchAll')
->willReturn([]);
$mockDb->expects($this->once())
->method('query')
->willReturn($mockStmt);
$repository = new LanguagesRepository($mockDb);
$langId = $repository->defaultLanguage();
$this->assertEquals('pl', $langId);
}
public function testActiveLanguagesReturnsList(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->with(
'pp_langs',
['id', 'name'],
['status' => 1, 'ORDER' => ['o' => 'ASC']]
)
->willReturn([
['id' => 'pl', 'name' => 'Polski'],
['id' => 'en', 'name' => 'English'],
]);
$repository = new LanguagesRepository($mockDb);
$languages = $repository->activeLanguages();
$this->assertIsArray($languages);
$this->assertCount(2, $languages);
$this->assertEquals('pl', $languages[0]['id']);
$this->assertEquals('English', $languages[1]['name']);
}
public function testActiveLanguagesReturnsEmptyArrayWhenNone(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->willReturn(null);
$repository = new LanguagesRepository($mockDb);
$languages = $repository->activeLanguages();
$this->assertIsArray($languages);
$this->assertEmpty($languages);
}
public function testTranslationsReturnsArray(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->with('pp_langs_translations', ['text', 'pl'])
->willReturn([
['text' => 'basket', 'pl' => 'Koszyk'],
['text' => 'order', 'pl' => 'Zamowienie'],
]);
$repository = new LanguagesRepository($mockDb);
$translations = $repository->translations('pl');
$this->assertIsArray($translations);
$this->assertEquals('pl', $translations['0']);
$this->assertEquals('Koszyk', $translations['basket']);
$this->assertEquals('Zamowienie', $translations['order']);
}
public function testTranslationsDefaultsToPl(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->with('pp_langs_translations', ['text', 'pl'])
->willReturn([]);
$repository = new LanguagesRepository($mockDb);
$translations = $repository->translations();
$this->assertIsArray($translations);
$this->assertEquals('pl', $translations['0']);
}
public function testTranslationsForDifferentLanguage(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->with('pp_langs_translations', ['text', 'en'])
->willReturn([
['text' => 'basket', 'en' => 'Cart'],
]);
$repository = new LanguagesRepository($mockDb);
$translations = $repository->translations('en');
$this->assertEquals('en', $translations['0']);
$this->assertEquals('Cart', $translations['basket']);
}
}

View File

@@ -4,15 +4,6 @@ namespace Tests\Unit\Domain\Settings;
use PHPUnit\Framework\TestCase;
use Domain\Settings\SettingsRepository;
/**
* Testy dla SettingsRepository
*
* UWAGA: SettingsRepository jest krokiem pośrednim migracji - deleguje do
* statycznych metod admin\factory\Settings. Pełne testy jednostkowe z mockami
* będą możliwe po migracji do DI (jak ProductRepository/BannerRepository).
*
* Na razie testujemy tylko to, co da się zweryfikować bez bazy danych.
*/
class SettingsRepositoryTest extends TestCase
{
public function testCanBeInstantiated(): void
@@ -30,4 +21,105 @@ class SettingsRepositoryTest extends TestCase
{
$this->assertTrue(method_exists(SettingsRepository::class, 'getSettings'));
}
public function testAllSettingsReturnsAssociativeArray(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->with('pp_settings', '*')
->willReturn([
['param' => 'firm_name', 'value' => 'Test Shop'],
['param' => 'contact_email', 'value' => 'test@example.com'],
['param' => 'ssl', 'value' => '1'],
]);
$service = new SettingsRepository($mockDb);
$settings = $service->allSettings(true);
$this->assertIsArray($settings);
$this->assertEquals('Test Shop', $settings['firm_name']);
$this->assertEquals('test@example.com', $settings['contact_email']);
$this->assertEquals('1', $settings['ssl']);
$this->assertCount(3, $settings);
}
public function testAllSettingsReturnsEmptyArrayWhenNoSettings(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->with('pp_settings', '*')
->willReturn([]);
$service = new SettingsRepository($mockDb);
$settings = $service->allSettings(true);
$this->assertIsArray($settings);
$this->assertEmpty($settings);
}
public function testAllSettingsHandlesNullFromDb(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('select')
->with('pp_settings', '*')
->willReturn(null);
$service = new SettingsRepository($mockDb);
$settings = $service->allSettings(true);
$this->assertIsArray($settings);
$this->assertEmpty($settings);
}
public function testGetSingleValueReturnsCorrectParam(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('get')
->with('pp_settings', 'value', ['param' => 'contact_email'])
->willReturn('test@example.com');
$service = new SettingsRepository($mockDb);
$value = $service->getSingleValue('contact_email');
$this->assertEquals('test@example.com', $value);
}
public function testGetSingleValueUsesParamNotHardcoded(): void
{
$mockDb = $this->createMock(\medoo::class);
// Kluczowy test: sprawdza ze param NIE jest hardcoded na 'firm_name'
$mockDb->expects($this->once())
->method('get')
->with('pp_settings', 'value', ['param' => 'ssl'])
->willReturn('1');
$service = new SettingsRepository($mockDb);
$value = $service->getSingleValue('ssl');
$this->assertEquals('1', $value);
}
public function testGetSingleValueReturnsEmptyStringWhenNotFound(): void
{
$mockDb = $this->createMock(\medoo::class);
$mockDb->expects($this->once())
->method('get')
->with('pp_settings', 'value', ['param' => 'nonexistent'])
->willReturn(null);
$service = new SettingsRepository($mockDb);
$value = $service->getSingleValue('nonexistent');
$this->assertEquals('', $value);
}
}

View File

@@ -78,6 +78,9 @@ if (!class_exists('Redis')) {
if (!class_exists('CacheHandler')) {
class CacheHandler {
public function get($key) { return null; }
public function set($key, $value, $ttl = 86400) {}
public function exists($key) { return false; }
public function delete($key) {}
public function deletePattern($pattern) {}
}

BIN
updates/0.20/ver_0.278.zip Normal file

Binary file not shown.

View File

@@ -1,3 +1,7 @@
<b>ver. 0.278 - 16.02.2026</b><br />
- UPDATE - migracja Settings + Languages do wspolnych klas Domain (z cache Redis)
- FIX - `get_single_settings_value()` parametr `$param` poprawnie uzywany (wczesniej hardcoded `firm_name`)
<hr>
<b>ver. 0.277 - 16.02.2026</b><br />
- NEW - migracja modulu `ShopProduct` (factory) pelna migracja ~40 metod do `ProductRepository` + ~30 akcji w `ShopProductController`
- NEW - migracja modulu `Dashboard` do Domain + DI (`DashboardRepository`, `DashboardController`)

View File

@@ -1,5 +1,5 @@
<?
$current_ver = 276;
$current_ver = 278;
for ($i = 1; $i <= $current_ver; $i++)
{