diff --git a/AGENTS.md b/AGENTS.md index d444844..8cd7c56 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,11 +8,11 @@ Gdy użytkownik napisze `KONIEC PRACY`, wykonaj kolejno: 2. Aktualizacja dokumentacji technicznej, jeśli zmiany tego wymagają: - `docs/DATABASE_STRUCTURE.md` - `docs/PROJECT_STRUCTURE.md` - - `docs/REFACTORING_PLAN.md` + - `docs/FRONTEND_REFACTORING_PLAN.md` - `docs/FORM_EDIT_SYSTEM.md` - `docs/CHANGELOG.md` - `docs/TESTING.md` -3. Przygotowanie aktualizacji zgodnie z plikiem UPDATE_INSTRUCTIONS.md (ZIP, plik z usuwanymi plikami, plik SQL jeśli wymagany). +3. Przygotowanie aktualizacji zgodnie z plikiem docs/UPDATE_INSTRUCTIONS.md (ZIP, plik z usuwanymi plikami, plik SQL jeśli wymagany). 4. Commit. 5. Push. @@ -23,6 +23,7 @@ Przed rozpoczęciem implementacji sprawdź aktualną zawartość: - `docs/DATABASE_STRUCTURE.md` - `docs/PROJECT_STRUCTURE.md` - `docs/REFACTORING_PLAN.md` +- `docs/FRONTEND_REFACTORING_PLAN.md` - `docs/CHANGELOG.md` - `docs/TESTING.md` diff --git a/admin/index.php b/admin/index.php index acf5f5c..b708eb1 100644 --- a/admin/index.php +++ b/admin/index.php @@ -66,15 +66,17 @@ if ( $_SESSION['ip'] !== $_SERVER['REMOTE_ADDR'] ) exit; } +$langRepo = new \Domain\Languages\LanguagesRepository( $mdb ); + if ( !$lang_id = \S::get_session( 'current-lang' ) ) { - $lang_id = \front\factory\Languages::default_language(); + $lang_id = $langRepo->defaultLanguage(); \S::set_session( 'current-lang', $lang_id ); } if ( !$lang = \S::get_session( 'lang-' . $lang_id ) ) { - $lang = \front\factory\Languages::lang_translations( $lang_id ); + $lang = $langRepo->translations( $lang_id ); \S::set_session( 'lang-' . $lang_id, $lang ); } diff --git a/admin/templates/dashboard/main-view.php b/admin/templates/dashboard/main-view.php index c99e58d..563bc47 100644 --- a/admin/templates/dashboard/main-view.php +++ b/admin/templates/dashboard/main-view.php @@ -123,7 +123,7 @@ best_sales_products ) ): foreach ( $this -> best_sales_products as $row ):?> - + defaultLanguage() );?> languages ) ): foreach ( $this -> languages as $lg ):?> -
  • ';?>
  • +
  • defaultLanguage() ) echo ' ';?>
  • diff --git a/admin/templates/shop-category/category-edit.php b/admin/templates/shop-category/category-edit.php index 9053b6c..29641ad 100644 --- a/admin/templates/shop-category/category-edit.php +++ b/admin/templates/shop-category/category-edit.php @@ -17,7 +17,7 @@ ob_start(); @@ -104,7 +104,7 @@ ob_start(); diff --git a/ajax.php b/ajax.php index 11429ad..d1d74c0 100644 --- a/ajax.php +++ b/ajax.php @@ -34,15 +34,17 @@ $mdb = new medoo( [ 'charset' => 'utf8' ] ); +$langRepo = new \Domain\Languages\LanguagesRepository( $mdb ); + if ( !$lang_id = \S::get_session( 'current-lang' ) ) { - $lang_id = \front\factory\Languages::default_language(); + $lang_id = $langRepo->defaultLanguage(); \S::set_session( 'current-lang', $lang_id ); } if ( !$lang = \S::get_session( 'lang' ) ) { - $lang = \front\factory\Languages::lang_translations(); + $lang = $langRepo->translations(); \S::set_session( 'lang', $lang ); } diff --git a/autoload/Domain/Newsletter/NewsletterRepository.php b/autoload/Domain/Newsletter/NewsletterRepository.php index cdf7da9..dca40b1 100644 --- a/autoload/Domain/Newsletter/NewsletterRepository.php +++ b/autoload/Domain/Newsletter/NewsletterRepository.php @@ -2,6 +2,7 @@ namespace Domain\Newsletter; use Domain\Settings\SettingsRepository; +use Domain\Article\ArticleRepository; class NewsletterRepository { @@ -9,11 +10,29 @@ class NewsletterRepository private $db; private SettingsRepository $settingsRepository; + private ?ArticleRepository $articleRepository; + private ?NewsletterPreviewRenderer $previewRenderer; - public function __construct($db, ?SettingsRepository $settingsRepository = null) - { + public function __construct( + $db, + ?SettingsRepository $settingsRepository = null, + ?ArticleRepository $articleRepository = null, + ?NewsletterPreviewRenderer $previewRenderer = null + ) { $this->db = $db; $this->settingsRepository = $settingsRepository ?? new SettingsRepository($db); + $this->articleRepository = $articleRepository; + $this->previewRenderer = $previewRenderer; + } + + private function getArticleRepository(): ArticleRepository + { + return $this->articleRepository ?? ($this->articleRepository = new ArticleRepository($this->db)); + } + + private function getPreviewRenderer(): NewsletterPreviewRenderer + { + return $this->previewRenderer ?? ($this->previewRenderer = new NewsletterPreviewRenderer()); } public function getSettings(): array @@ -289,4 +308,138 @@ class NewsletterRepository 'total' => $total, ]; } + + // ── Frontend methods ── + + public function unsubscribe(string $hash): bool + { + $id = $this->db->get('pp_newsletter', 'id', ['hash' => $hash]); + if (!$id) { + return false; + } + + $this->db->delete('pp_newsletter', ['id' => $id]); + return true; + } + + public function confirmSubscription(string $hash): bool + { + $id = $this->db->get('pp_newsletter', 'id', ['AND' => ['hash' => $hash, 'status' => 0]]); + if (!$id) { + return false; + } + + $this->db->update('pp_newsletter', ['status' => 1], ['id' => $id]); + return true; + } + + public function getHashByEmail(string $email): ?string + { + $hash = $this->db->get('pp_newsletter', 'hash', ['email' => $email]); + return $hash ? (string)$hash : null; + } + + public function removeByEmail(string $email): bool + { + if (!$this->db->get('pp_newsletter', 'id', ['email' => $email])) { + return false; + } + + return (bool)$this->db->delete('pp_newsletter', ['email' => $email]); + } + + public function signup(string $email, string $serverName, bool $ssl, array $settings): bool + { + if (!\S::email_check($email)) { + return false; + } + + if ($this->db->get('pp_newsletter', 'id', ['email' => $email])) { + return false; + } + + $hash = md5(time() . $email); + + $text = ($settings['newsletter_header'] ?? ''); + $text .= $this->templateByName('#potwierdzenie-zapisu-do-newslettera'); + $text .= ($settings['newsletter_footer'] ?? ''); + + $base = $ssl ? 'https' : 'http'; + $link = '/newsletter/confirm/hash=' . $hash; + $text = str_replace('[LINK]', $link, $text); + $text = str_replace('[WYPISZ_SIE]', '', $text); + + $text = preg_replace( + "-(]+src\s*=\s*['\"])(((?!'|\"|https?://).)*)(['\"][^>]*>)-i", + "$1" . $base . "://" . $serverName . "$2$4", + $text + ); + $text = preg_replace( + "-(]+href\s*=\s*['\"])(((?!'|\"|https?://).)*)(['\"][^>]*>)-i", + "$1" . $base . "://" . $serverName . "$2$4", + $text + ); + + $lang = \S::get_session('lang-' . \S::get_session('current-lang')); + $subject = $lang['potwierdz-zapisanie-sie-do-newslettera'] ?? 'Newsletter'; + \S::send_email($email, $subject, $text); + + $this->db->insert('pp_newsletter', ['email' => $email, 'hash' => $hash, 'status' => 0]); + + return true; + } + + public function sendQueued(int $limit, string $serverName, bool $ssl, string $unsubscribeLabel): bool + { + $settingsDetails = $this->settingsRepository->getSettings(); + + $results = $this->db->query('SELECT * FROM pp_newsletter_send ORDER BY id ASC LIMIT ' . (int)$limit); + $results = $results ? $results->fetchAll() : []; + + if (!is_array($results) || empty($results)) { + return false; + } + + $renderer = $this->getPreviewRenderer(); + $articleRepo = $this->getArticleRepository(); + + foreach ($results as $row) { + $dates = explode(' - ', $row['dates']); + + $articles = []; + if (isset($dates[0], $dates[1])) { + $articles = $articleRepo->articlesByDateAdd($dates[0], $dates[1]); + } + + $text = $renderer->render( + is_array($articles) ? $articles : [], + $settingsDetails, + $this->templateDetails((int)$row['id_template']), + (string)$row['dates'] + ); + + $base = $ssl ? 'https' : 'http'; + + $text = preg_replace( + "-(]+src\s*=\s*['\"])(((?!'|\"|http://).)*)(['\"][^>]*>)-i", + "$1" . $base . "://" . $serverName . "$2$4", + $text + ); + $text = preg_replace( + "-(]+href\s*=\s*['\"])(((?!'|\"|http://).)*)(['\"][^>]*>)-i", + "$1" . $base . "://" . $serverName . "$2$4", + $text + ); + + $hash = $this->getHashByEmail($row['email']); + $link = $base . "://" . $serverName . '/newsletter/unsubscribe/hash=' . $hash; + $text = str_replace('[WYPISZ_SIE]', '' . $unsubscribeLabel . '', $text); + + \S::send_email($row['email'], 'Newsletter ze strony: ' . $serverName, $text); + + $this->db->delete('pp_newsletter_send', ['id' => $row['id']]); + } + + return true; + } } diff --git a/autoload/admin/App.php b/autoload/admin/App.php index 3995c08..ba2b930 100644 --- a/autoload/admin/App.php +++ b/autoload/admin/App.php @@ -394,7 +394,8 @@ class App global $mdb; return new \admin\Controllers\ShopProductController( new \Domain\Product\ProductRepository( $mdb ), - new \Domain\Integrations\IntegrationsRepository( $mdb ) + new \Domain\Integrations\IntegrationsRepository( $mdb ), + new \Domain\Languages\LanguagesRepository( $mdb ) ); }, 'ShopClients' => function() { diff --git a/autoload/admin/Controllers/SettingsController.php b/autoload/admin/Controllers/SettingsController.php index 3fb7d36..16abd22 100644 --- a/autoload/admin/Controllers/SettingsController.php +++ b/autoload/admin/Controllers/SettingsController.php @@ -91,7 +91,7 @@ class SettingsController $likeNormalized = '%' . $phraseNormalized . '%'; $items = []; - $defaultLang = (string)\front\factory\Languages::default_language(); + $defaultLang = (string)$this->languagesRepository->defaultLanguage(); try { $productStmt = $mdb->query( diff --git a/autoload/admin/Controllers/ShopCategoryController.php b/autoload/admin/Controllers/ShopCategoryController.php index 61d70b5..38688fc 100644 --- a/autoload/admin/Controllers/ShopCategoryController.php +++ b/autoload/admin/Controllers/ShopCategoryController.php @@ -20,7 +20,7 @@ class ShopCategoryController return \Tpl::view('shop-category/categories-list', [ 'categories' => $this->repository->subcategories(null), 'level' => 0, - 'dlang' => \front\factory\Languages::default_language(), + 'dlang' => $this->languagesRepository->defaultLanguage(), ]); } @@ -36,6 +36,7 @@ class ShopCategoryController 'pid' => \S::get('pid'), 'languages' => $this->languagesRepository->languagesList(), 'sort_types' => $this->repository->sortTypes(), + 'dlang' => $this->languagesRepository->defaultLanguage(), ]); } @@ -102,7 +103,7 @@ class ShopCategoryController echo \Tpl::view('shop-category/category-browse-list', [ 'categories' => $this->repository->subcategories(null), 'level' => 0, - 'dlang' => \front\factory\Languages::default_language(), + 'dlang' => $this->languagesRepository->defaultLanguage(), ]); exit; } diff --git a/autoload/admin/Controllers/ShopProductController.php b/autoload/admin/Controllers/ShopProductController.php index 9a41bac..a18ad36 100644 --- a/autoload/admin/Controllers/ShopProductController.php +++ b/autoload/admin/Controllers/ShopProductController.php @@ -4,6 +4,7 @@ namespace admin\Controllers; use Domain\Product\ProductRepository; use Domain\Category\CategoryRepository; use Domain\Integrations\IntegrationsRepository; +use Domain\Languages\LanguagesRepository; use admin\ViewModels\Forms\FormEditViewModel; use admin\ViewModels\Forms\FormField; use admin\ViewModels\Forms\FormTab; @@ -19,11 +20,13 @@ class ShopProductController { private ProductRepository $repository; private IntegrationsRepository $integrationsRepository; + private LanguagesRepository $languagesRepository; - public function __construct(ProductRepository $repository, IntegrationsRepository $integrationsRepository) + public function __construct(ProductRepository $repository, IntegrationsRepository $integrationsRepository, LanguagesRepository $languagesRepository) { $this->repository = $repository; $this->integrationsRepository = $integrationsRepository; + $this->languagesRepository = $languagesRepository; } // ─── Krok 6: Lista / widok ─────────────────────────────────────── @@ -35,7 +38,7 @@ class ShopProductController { $apiloEnabled = $this->integrationsRepository->getSetting( 'apilo', 'enabled' ); $shopproEnabled = $this->integrationsRepository->getSetting( 'shoppro', 'enabled' ); - $dlang = \front\factory\Languages::default_language(); + $dlang = $this->languagesRepository->defaultLanguage(); $sortableColumns = [ 'id', 'name', 'price_brutto', 'status', 'promoted', 'quantity' ]; @@ -221,7 +224,7 @@ class ShopProductController $sets = \shop\ProductSet::sets_list(); $producers = ( new \Domain\Producer\ProducerRepository( $db ) )->allProducers(); $units = ( new \Domain\Dictionaries\DictionariesRepository( $db ) )->allUnits(); - $dlang = \front\factory\Languages::default_language(); + $dlang = $this->languagesRepository->defaultLanguage(); $viewModel = $this->buildProductFormViewModel( $product, $languages, $categories, $layouts, $products, $sets, $producers, $units, $dlang @@ -949,7 +952,7 @@ class ShopProductController return \Tpl::view( 'shop-product/product-combination', [ 'product' => $this->repository->findForAdmin( (int) \S::get( 'product_id' ) ), 'attributes' => ( new \Domain\Attribute\AttributeRepository( $db ) )->getAttributesListForCombinations(), - 'default_language' => \front\factory\Languages::default_language(), + 'default_language' => $this->languagesRepository->defaultLanguage(), 'product_permutations' => $this->repository->getCombinationsForTable( (int) \S::get( 'product_id' ) ), ] ); } @@ -1146,7 +1149,7 @@ class ShopProductController return \Tpl::view( 'shop-product/mass-edit', [ 'products' => $this->repository->allProductsForMassEdit(), 'categories' => $categoryRepository->subcategories( null ), - 'dlang' => \front\factory\Languages::default_language(), + 'dlang' => $this->languagesRepository->defaultLanguage(), ] ); } diff --git a/autoload/front/Controllers/NewsletterController.php b/autoload/front/Controllers/NewsletterController.php new file mode 100644 index 0000000..befaf06 --- /dev/null +++ b/autoload/front/Controllers/NewsletterController.php @@ -0,0 +1,49 @@ +repository = $repository; + } + + public function signin() + { + global $settings; + + $result = [ 'status' => 'bad' ]; + + if ( $this->repository->signup( \S::get( 'email' ), $_SERVER['SERVER_NAME'], !empty( $settings['ssl'] ), $settings ) ) + $result = [ 'status' => 'ok' ]; + + echo json_encode( $result ); + exit; + } + + public function confirm() + { + global $lang; + + if ( $this->repository->confirmSubscription( \S::get( 'hash' ) ) ) + \S::alert( $lang['email-zostal-dodany-do-listy-newsletter'] ); + + header( 'Location: /' ); + exit; + } + + public function unsubscribe() + { + global $lang; + + if ( $this->repository->unsubscribe( \S::get( 'hash' ) ) ) + \S::alert( $lang['email-zostal-usuniety-z-listy-newsletter'] ); + + header( 'Location: /' ); + exit; + } +} diff --git a/autoload/front/Views/Languages.php b/autoload/front/Views/Languages.php new file mode 100644 index 0000000..ec0e8ee --- /dev/null +++ b/autoload/front/Views/Languages.php @@ -0,0 +1,12 @@ + languages = $languages; + return $tpl -> render( 'site/languages' ); + } +} diff --git a/autoload/front/view/class.Newsletter.php b/autoload/front/Views/Newsletter.php similarity index 63% rename from autoload/front/view/class.Newsletter.php rename to autoload/front/Views/Newsletter.php index e303a2e..be290d4 100644 --- a/autoload/front/view/class.Newsletter.php +++ b/autoload/front/Views/Newsletter.php @@ -1,9 +1,9 @@ render( 'newsletter/newsletter' ); diff --git a/autoload/front/controls/class.Newsletter.php b/autoload/front/controls/class.Newsletter.php deleted file mode 100644 index 4ebb7f7..0000000 --- a/autoload/front/controls/class.Newsletter.php +++ /dev/null @@ -1,38 +0,0 @@ - 'bad' ]; - - if ( \front\factory\Newsletter::newsletter_signin( \S::get( 'email' ) ) ) - $result = [ 'status' => 'ok' ]; - - echo json_encode( $result ); - exit; - } - - public static function confirm() - { - global $lang; - - if ( \front\factory\Newsletter::newsletter_confirm( \S::get( 'hash' ) ) ) - \S::alert( $lang['email-zostal-dodany-do-listy-newsletter'] ); - - header( 'Location: /' ); - exit; - } - - public static function unsubscribe() - { - global $lang; - - if ( \front\factory\Newsletter::newsletter_unsubscribe( \S::get( 'hash' ) ) ) - \S::alert( $lang['email-zostal-usuniety-z-listy-newsletter'] ); - - header( 'Location: /' ); - exit; - } -} \ No newline at end of file diff --git a/autoload/front/controls/class.Site.php b/autoload/front/controls/class.Site.php index 6a7ff08..d91337d 100644 --- a/autoload/front/controls/class.Site.php +++ b/autoload/front/controls/class.Site.php @@ -53,14 +53,21 @@ class Site if ( $category ) return \front\view\ShopCategory::category_view( $category, $lang_id, \S::get( 'bs' ) ); - // stare klasy - $class = '\front\controls\\'; - - $results = explode( '_', \S::get( 'module' ) ); - if ( is_array( $results ) ) foreach ( $results as $row ) - $class .= ucfirst( $row ); - + // nowe kontrolery z DI + $module = \S::get( 'module' ); $action = \S::get( 'action' ); + $controllerFactories = self::getControllerFactories(); + + $moduleName = implode( '', array_map( 'ucfirst', explode( '_', $module ) ) ); + if ( isset( $controllerFactories[$moduleName] ) and $action ) + { + $controller = $controllerFactories[$moduleName](); + if ( method_exists( $controller, $action ) ) + return $controller->$action(); + } + + // stare klasy + $class = '\front\controls\\' . $moduleName; if ( class_exists( $class ) and method_exists( new $class, $action ) ) return call_user_func_array( array( $class, $action ), array() ); @@ -132,5 +139,17 @@ class Site if ( file_exists( 'modules/actions.php' ) ) include 'modules/actions.php'; } + + public static function getControllerFactories() + { + return [ + 'Newsletter' => function() { + global $mdb; + return new \front\Controllers\NewsletterController( + new \Domain\Newsletter\NewsletterRepository( $mdb ) + ); + }, + ]; + } } ?> diff --git a/autoload/front/factory/class.Languages.php b/autoload/front/factory/class.Languages.php deleted file mode 100644 index 543755b..0000000 --- a/autoload/front/factory/class.Languages.php +++ /dev/null @@ -1,29 +0,0 @@ -defaultLanguage(); - } - - public static function active_languages() - { - global $mdb; - $repo = new \Domain\Languages\LanguagesRepository($mdb); - return $repo->activeLanguages(); - } - - public static function lang_translations($language = 'pl') - { - global $mdb; - $repo = new \Domain\Languages\LanguagesRepository($mdb); - return $repo->translations($language); - } -} diff --git a/autoload/front/factory/class.Newsletter.php b/autoload/front/factory/class.Newsletter.php deleted file mode 100644 index e1d436a..0000000 --- a/autoload/front/factory/class.Newsletter.php +++ /dev/null @@ -1,133 +0,0 @@ - get( 'pp_newsletter', 'id', [ 'hash' => $hash ] ) ) - return false; - else - $mdb -> delete( 'pp_newsletter', [ 'status' => 1 ], [ 'id' => $id ] ); - return true; - } - - public static function newsletter_confirm( $hash ) - { - global $mdb; - if ( !$id = $mdb -> get( 'pp_newsletter', 'id', [ 'AND' => [ 'hash' => $hash, 'status' => 0 ] ] ) ) - return false; - else - $mdb -> update( 'pp_newsletter', [ 'status' => 1 ], [ 'id' => $id ] ); - return true; - } - - public static function newsletter_send( $limit = 5 ) - { - global $mdb, $settings, $lang; - $settingsRepository = new \Domain\Settings\SettingsRepository( $mdb ); - $newsletterRepository = new \Domain\Newsletter\NewsletterRepository( $mdb, $settingsRepository ); - $previewRenderer = new \Domain\Newsletter\NewsletterPreviewRenderer(); - $settingsDetails = $settingsRepository -> getSettings(); - - $results = $mdb -> query( 'SELECT * FROM pp_newsletter_send ORDER BY id ASC LIMIT ' . $limit ) -> fetchAll(); - if ( is_array( $results ) and !empty( $results ) ) - { - foreach ( $results as $row ) - { - $dates = explode( ' - ', $row['dates'] ); - - $articles = []; - $articleRepository = new \Domain\Article\ArticleRepository( $mdb ); - if ( isset( $dates[0], $dates[1] ) ) - $articles = $articleRepository->articlesByDateAdd( $dates[0], $dates[1] ); - - $text = $previewRenderer -> render( - is_array( $articles ) ? $articles : [], - $settingsDetails, - $newsletterRepository -> templateDetails( (int)$row['id_template'] ), - (string)$row['dates'] - ); - - if ( $settings['ssl'] ) $base = 'https'; else $base = 'http'; - - $regex = "-(]+src\s*=\s*['\"])(((?!'|\"|http://).)*)(['\"][^>]*>)-i"; - $text = preg_replace( $regex, "$1" . $base . "://" . $_SERVER['SERVER_NAME'] . "$2$4", $text ); - - $regex = "-(]+href\s*=\s*['\"])(((?!'|\"|http://).)*)(['\"][^>]*>)-i"; - $text = preg_replace( $regex, "$1" . $base . "://" . $_SERVER['SERVER_NAME'] . "$2$4", $text ); - - $link = $base . "://" . $_SERVER['SERVER_NAME'] . '/newsletter/unsubscribe/hash=' . \front\factory\Newsletter::get_hash( $row['email'] ); - - $text = str_replace( '[WYPISZ_SIE]', '' . $lang['wypisz-sie'] . '', $text ); - - \S::send_email( $row['email'], 'Newsletter ze strony: ' . $_SERVER['SERVER_NAME'], $text ); - - $mdb -> delete( 'pp_newsletter_send', [ 'id' => $row['id'] ] ); - } - return true; - } - return false; - } - - public static function get_hash( $email ) - { - global $mdb; - return $mdb -> get( 'pp_newsletter', 'hash', [ 'email' => $email ] ); - } - - public static function newsletter_signin( $email ) - { - global $mdb, $lang, $settings; - - if ( !\S::email_check( $email ) ) - return false; - - if ( !$mdb -> get( 'pp_newsletter', 'id', [ 'email' => $email ] ) ) - { - $hash = md5( time() . $email ); - - $text = $settings['newsletter_header']; - $text .= \front\factory\Newsletter::get_template( '#potwierdzenie-zapisu-do-newslettera' ); - $text .= $settings['newsletter_footer']; - - $settings['ssl'] ? $base = 'https' : $base = 'http'; - - $link = '/newsletter/confirm/hash=' . $hash; - - $text = str_replace( '[LINK]', $link, $text ); - - $text = str_replace( '[WYPISZ_SIE]', '', $text ); - - $regex = "-(]+src\s*=\s*['\"])(((?!'|\"|https?://).)*)(['\"][^>]*>)-i"; - $text = preg_replace( $regex, "$1" . $base . "://" . $_SERVER['SERVER_NAME'] . "$2$4", $text ); - - $regex = "-(]+href\s*=\s*['\"])(((?!'|\"|https?://).)*)(['\"][^>]*>)-i"; - $text = preg_replace( $regex, "$1" . $base . "://" . $_SERVER['SERVER_NAME'] . "$2$4", $text ); - - $send = \S::send_email( $email, $lang['potwierdz-zapisanie-sie-do-newslettera'], $text ); - - $mdb -> insert( 'pp_newsletter', [ 'email' => $email, 'hash' => $hash, 'status' => 0 ] ); - - return true; - } - return false; - } - - public static function get_template( $template_name ) - { - global $mdb; - $repository = new \Domain\Newsletter\NewsletterRepository( $mdb ); - return $repository -> templateByName( (string)$template_name ); - } - - public static function newsletter_signout( $email ) - { - global $mdb; - - if ( $mdb -> get( 'pp_newsletter', 'id', [ 'email' => $email ] ) ) - return $mdb -> delete( 'pp_newsletter', [ 'email' => $email ] ); - return false; - } -} diff --git a/autoload/front/factory/class.Pages.php b/autoload/front/factory/class.Pages.php index 239b012..920d0fe 100644 --- a/autoload/front/factory/class.Pages.php +++ b/autoload/front/factory/class.Pages.php @@ -32,7 +32,7 @@ class Pages $page['language']['seo_link'] ? $url = '/' . $page['language']['seo_link'] : $url = '/s-' . $page['id'] . '-' . \S::seo( $page['language']['title'] ); - if ( $lang_id != \front\factory\Languages::default_language() and $url != '#' ) + if ( $lang_id != ( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->defaultLanguage() and $url != '#' ) $url = '/' . $lang_id . $url; return $url; diff --git a/autoload/front/factory/class.ShopCategory.php b/autoload/front/factory/class.ShopCategory.php index 3eb8d20..0cf6fd4 100644 --- a/autoload/front/factory/class.ShopCategory.php +++ b/autoload/front/factory/class.ShopCategory.php @@ -35,7 +35,7 @@ class ShopCategory $category['language']['seo_link'] ? $url = '/' . $category['language']['seo_link'] : $url = '/k-' . $category['id'] . '-' . \S::seo( $category['language']['title'] ); - if ( \S::get_session( 'current-lang' ) != \front\factory\Languages::default_language() and $url != '#' ) + if ( \S::get_session( 'current-lang' ) != ( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->defaultLanguage() and $url != '#' ) $url = '/' . \S::get_session( 'current-lang' ) . $url; return $url; diff --git a/autoload/front/factory/class.ShopClient.php b/autoload/front/factory/class.ShopClient.php index 5a1e450..81d3d7e 100644 --- a/autoload/front/factory/class.ShopClient.php +++ b/autoload/front/factory/class.ShopClient.php @@ -93,7 +93,7 @@ class ShopClient if ( $data = $mdb -> get( 'pp_shop_clients', [ 'id', 'email', 'register_date' ], [ 'AND' => [ 'hash' => $hash, 'status' => 1, 'password_recovery' => 1 ] ] ) ) { $text = $settings['newsletter_header']; - $text .= \front\factory\Newsletter::get_template( '#nowe-haslo' ); + $text .= ( new \Domain\Newsletter\NewsletterRepository( $mdb ) )->templateByName( '#nowe-haslo' ); $text .= $settings['newsletter_footer']; $settings['ssl'] ? $base = 'https' : $base = 'http'; @@ -129,7 +129,7 @@ class ShopClient if ( $hash = $mdb -> get( 'pp_shop_clients', 'hash', [ 'AND' => [ 'email' => $email, 'status' => 1 ] ] ) ) { $text = $settings['newsletter_header']; - $text .= \front\factory\Newsletter::get_template( '#odzyskiwanie-hasla-link' ); + $text .= ( new \Domain\Newsletter\NewsletterRepository( $mdb ) )->templateByName( '#odzyskiwanie-hasla-link' ); $text .= $settings['newsletter_footer']; $settings['ssl'] ? $base = 'https' : $base = 'http'; @@ -164,7 +164,7 @@ class ShopClient $email = $mdb -> get( 'pp_shop_clients', 'email', [ 'id' => $id ] ); $text = $settings['newsletter_header']; - $text .= \front\factory\Newsletter::get_template( '#potwierdzenie-aktywacji-konta' ); + $text .= ( new \Domain\Newsletter\NewsletterRepository( $mdb ) )->templateByName( '#potwierdzenie-aktywacji-konta' ); $text .= $settings['newsletter_footer']; $settings['ssl'] ? $base = 'https' : $base = 'http'; @@ -201,7 +201,7 @@ class ShopClient ] ) ) { $text = $settings['newsletter_header']; - $text .= \front\factory\Newsletter::get_template( '#potwierdzenie-rejestracji' ); + $text .= ( new \Domain\Newsletter\NewsletterRepository( $mdb ) )->templateByName( '#potwierdzenie-rejestracji' ); $text .= $settings['newsletter_footer']; $settings['ssl'] ? $base = 'https' : $base = 'http'; diff --git a/autoload/front/view/class.Languages.php b/autoload/front/view/class.Languages.php deleted file mode 100644 index f4677ae..0000000 --- a/autoload/front/view/class.Languages.php +++ /dev/null @@ -1,12 +0,0 @@ - languages = \front\factory\Languages::active_languages(); - return $tpl -> render( 'site/languages' ); - } -} diff --git a/autoload/front/view/class.Site.php b/autoload/front/view/class.Site.php index 7d9d677..e2e51b0 100644 --- a/autoload/front/view/class.Site.php +++ b/autoload/front/view/class.Site.php @@ -106,7 +106,7 @@ class Site ] ), $html ); $html = str_replace( '[NEWSLETTER]', - \front\view\Newsletter::newsletter(), + \front\Views\Newsletter::render(), $html ); $html = str_replace( '[UZYTKOWNIK_MINI_LOGOWANIE]', \front\view\ShopClient::mini_login(), @@ -333,7 +333,7 @@ class Site $html = str_replace( '[TITLE]', $page['language']['meta_title'] ? $page['language']['meta_title'] . ' | ' . $settings['firm_name'] : $page['language']['title'] . ' | ' . $settings['firm_name'], $html ); $html = str_replace( '[META_KEYWORDS]', $page['language']['meta_keywords'], $html ); $html = str_replace( '[META_DESCRIPTION]', $page['language']['meta_description'], $html ); - $html = str_replace( '[JEZYKI]', \front\view\Languages::languages(), $html ); + $html = str_replace( '[JEZYKI]', \front\Views\Languages::render( ( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->activeLanguages() ), $html ); $html = str_replace( '[TYTUL_STRONY]', self::title( $page['language']['title'], $page['show_title'], $page['language']['page_title'] ), $html ); $html = str_replace( '[WYSZUKIWARKA]', \shop\Search::simple_form(), $html ); diff --git a/autoload/shop/class.Category.php b/autoload/shop/class.Category.php index bf579b7..4158a9e 100644 --- a/autoload/shop/class.Category.php +++ b/autoload/shop/class.Category.php @@ -19,7 +19,7 @@ class Category implements \ArrayAccess global $mdb; if ( !$lang_id ) - $lang_id = \front\factory\Languages::default_language(); + $lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage(); return $mdb -> get( 'pp_shop_categories_langs', 'title', [ 'AND' => [ 'category_id' => $category_id, 'lang_id' => $lang_id ] ] ); } diff --git a/autoload/shop/class.Product.php b/autoload/shop/class.Product.php index 770e55e..1f27100 100644 --- a/autoload/shop/class.Product.php +++ b/autoload/shop/class.Product.php @@ -9,7 +9,7 @@ class Product implements \ArrayAccess global $mdb; if ( !$lang_id ) - $lang_id = \front\factory\Languages::default_language(); + $lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage(); $result = $mdb -> get( 'pp_shop_products', '*', [ 'id' => $product_id ] ); if ( \S::is_array_fix( $result ) ) foreach ( $result as $key => $val ) @@ -292,7 +292,7 @@ class Product implements \ArrayAccess global $mdb; if ( !$lang_id ) - $lang_id = \front\factory\Languages::default_language(); + $lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage(); $repository = new \Domain\Product\ProductRepository($mdb); return $repository->getName($product_id, $lang_id); @@ -377,7 +377,7 @@ class Product implements \ArrayAccess { global $mdb; - $lang_id = \front\factory\Languages::default_language(); + $lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage(); $results = $mdb -> select( 'pp_shop_products_langs', '*', [ 'AND' => [ 'product_id' => $product_id, 'lang_id' => $lang_id ] ] ); if ( \S::is_array_fix( $results ) ) foreach ( $results as $row ) diff --git a/autoload/shop/class.ProductAttribute.php b/autoload/shop/class.ProductAttribute.php index 805a0d5..d000fea 100644 --- a/autoload/shop/class.ProductAttribute.php +++ b/autoload/shop/class.ProductAttribute.php @@ -47,7 +47,7 @@ class ProductAttribute implements \ArrayAccess global $mdb; if ( !$lang_id ) - $lang_id = \front\factory\Languages::default_language(); + $lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage(); $result = $mdb -> get( 'pp_shop_attributes', '*', [ 'id' => $attribute_id ] ); if ( \S::is_array_fix( $result ) ) foreach ( $result as $key => $val ) diff --git a/cron/cron-xml.php b/cron/cron-xml.php index 2b123e9..e43a549 100644 --- a/cron/cron-xml.php +++ b/cron/cron-xml.php @@ -51,6 +51,6 @@ $mdb = new medoo( [ ] ); $settings = \front\factory\Settings::settings_details(); -$lang_id = \front\factory\Languages::default_language(); +$lang_id = ( new \Domain\Languages\LanguagesRepository( $mdb ) )->defaultLanguage(); ( new \Domain\Product\ProductRepository( $mdb ) )->generateGoogleFeedXml(); \ No newline at end of file diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9d1ab8a..a6a9c41 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -4,6 +4,30 @@ Logi zmian z migracji na Domain-Driven Architecture. Najnowsze na gorze. --- +## ver. 0.279 (2026-02-16) - Newsletter + Languages frontend migration, front\Controllers, front\Views + +- **Languages (view)** — migracja do nowego namespace + - USUNIĘTA: `front\factory\Languages` — fasada niepotrzebna, wszystkie zależności przepięte na `Domain\Languages\LanguagesRepository` + - USUNIĘTA: `front\view\Languages` → przeniesiona do `front\Views\Languages` (nowy namespace, bez `class.` prefix) + - UPDATE: 26 plików przepiętych z fasady na repozytorium (kontrolery DI, entry points, szablony, shop classes) + - UPDATE: `admin\App` — DI factory dla `ShopProductController` rozszerzona o `LanguagesRepository` + +- **Newsletter (frontend)** — pełna migracja na Domain + - NOWE METODY w `NewsletterRepository`: `unsubscribe()`, `confirmSubscription()`, `getHashByEmail()`, `removeByEmail()`, `signup()`, `sendQueued()` + - NOWY: `front\Controllers\NewsletterController` — pierwszy frontowy kontroler z DI (nowy namespace `front\Controllers\`) + - NOWY: `front\Views\Newsletter` — czysty VIEW (nowy namespace `front\Views\`) + - USUNIĘTA: `front\factory\Newsletter` — logika przeniesiona do `NewsletterRepository` + - USUNIĘTA: `front\view\Newsletter` → zastąpiona przez `front\Views\Newsletter` + - USUNIĘTA: `front\controls\Newsletter` → zastąpiona przez `front\Controllers\NewsletterController` + - UPDATE: `front\controls\Site::route()` — nowy routing: `getControllerFactories()` (DI) → fallback stare `front\controls\` + - UPDATE: `front\factory\ShopClient` — 4x `get_template()` przepięte na `NewsletterRepository::templateByName()` + - UPDATE: `index.php` — `newsletter_send()` przepięte na `$repo->sendQueued()` + - FIX: `newsletter_unsubscribe()` — błędna składnia medoo `delete()` (3 argumenty zamiast 2) + - UPDATE: `tests/bootstrap.php` — dodane stuby: `S::email_check()`, `S::get_session()`, `S::set_session()` + - Testy: 437 OK, 1398 asercji (+10 nowych testów w NewsletterRepositoryTest) + +--- + ## ver. 0.278 (2026-02-16) - Settings + Languages frontend migration - **Settings + Languages (frontend)** — pierwszy etap refaktoringu frontendu diff --git a/docs/DATABASE_STRUCTURE.md b/docs/DATABASE_STRUCTURE.md index 1d14bd2..2547590 100644 --- a/docs/DATABASE_STRUCTURE.md +++ b/docs/DATABASE_STRUCTURE.md @@ -326,7 +326,7 @@ Adresy e-mail zapisane do newslettera. | hash | Hash potwierdzenia/wypisu | | status | 1 = potwierdzony, 0 = oczekujacy | -**Uzywane w:** `Domain\\Newsletter\\NewsletterRepository`, `front\\factory\\Newsletter` +**Uzywane w:** `Domain\\Newsletter\\NewsletterRepository`, `front\\Controllers\\NewsletterController` ## pp_newsletter_send Kolejka wysylki newslettera. @@ -338,7 +338,7 @@ Kolejka wysylki newslettera. | dates | Zakres dat artykulow (tekst) | | id_template | FK do `pp_newsletter_templates` (NULL gdy brak szablonu) | -**Uzywane w:** `Domain\\Newsletter\\NewsletterRepository`, `front\\factory\\Newsletter::newsletter_send()` +**Uzywane w:** `Domain\\Newsletter\\NewsletterRepository` ## pp_newsletter_templates Szablony tresci e-maili (uzytkownik + administracyjne/systemowe). @@ -350,10 +350,12 @@ Szablony tresci e-maili (uzytkownik + administracyjne/systemowe). | text | Tresc HTML szablonu | | is_admin | 1 = szablon administracyjny/systemowy, 0 = szablon uzytkownika | -**Uzywane w:** `Domain\\Newsletter\\NewsletterRepository`, `admin\\Controllers\\NewsletterController`, `front\\factory\\Newsletter` +**Uzywane w:** `Domain\\Newsletter\\NewsletterRepository`, `admin\\Controllers\\NewsletterController` **Aktualizacja 2026-02-12 (ver. 0.257):** modul `/admin/newsletter` korzysta z `Domain\\Newsletter\\NewsletterRepository` (DI kontroler + fasada legacy). +**Aktualizacja 2026-02-16 (ver. 0.279):** `front\\factory\\Newsletter` usunięta — logika przeniesiona do `NewsletterRepository`. Frontend korzysta z `front\\Controllers\\NewsletterController` (DI). + ## pp_scontainers Kontenery statyczne (modul /admin/scontainers). diff --git a/docs/FRONTEND_REFACTORING_PLAN.md b/docs/FRONTEND_REFACTORING_PLAN.md index 4f2edf3..11cbd03 100644 --- a/docs/FRONTEND_REFACTORING_PLAN.md +++ b/docs/FRONTEND_REFACTORING_PLAN.md @@ -36,9 +36,9 @@ Panel administratora (33 moduły) został w pełni zmigrowany na architekturę D | ShopPaymentMethod | ZMIGROWANA (Domain) | — | | ShopStatuses | ZMIGROWANA (Domain) | — | | Scontainers | ZMIGROWANA (Domain) | — | -| Newsletter | CZĘŚCIOWO zmigrowana | ŚREDNI | +| Newsletter | ZMIGROWANA (Domain) — usunięta | — | | Settings | Fasada (BUG: get_single_settings_value ignoruje $param) | NISKI | -| Languages | Fasada | NISKI | +| Languages | USUNIĘTA — przepięta na Domain | — | | Layouts | Fasada | NISKI | | Banners | Fasada | NISKI | | Menu | Fasada | NISKI | @@ -51,7 +51,8 @@ Panel administratora (33 moduły) został w pełni zmigrowany na architekturę D |-------|--------| | Site | KRYTYCZNY — show() ~600 linii, pattern substitution engine | | ShopCategory | VIEW z logiką routingu (infinite scroll vs pagination) | -| Articles, Banners, Languages, Menu, Newsletter, Scontainers | Czyste VIEW | +| Articles, Banners, Menu, Scontainers | Czyste VIEW | +| Languages, Newsletter | PRZENIESIONE do `front\Views\` (nowy namespace) | | ShopClient, ShopOrder, ShopPaymentMethod | Czyste VIEW | | ShopTransport | PUSTA klasa (placeholder) | @@ -109,7 +110,7 @@ articles(8), banner(2), controls(1), menu(4), newsletter(2), scontainers(1), sho 1. **KRYTYCZNY** `front\factory\ShopClient::login()` — hardcoded password bypass `'Legia1916'` 2. `front\factory\Settings::get_single_settings_value()` — ignoruje `$param`, zawsze zwraca `firm_name` -3. `front\factory\Newsletter::newsletter_unsubscribe()` — błędna składnia SQL w delete +3. ~~`front\factory\Newsletter::newsletter_unsubscribe()` — błędna składnia SQL w delete~~ **NAPRAWIONE** — `NewsletterRepository::unsubscribe()` z poprawną składnią medoo `delete()` 4. `cms\Layout::__get()` — referuje nieistniejące `$this->data` 5. `shop\Search` — typo w use: `shop\Produt` (brak 'c') @@ -173,6 +174,33 @@ Legacy Cleanup --- +### Etap: Newsletter Frontend — ZREALIZOWANY + +**Cel:** Przeniesienie logiki frontendowej z `front\factory\Newsletter` do `Domain\Newsletter\NewsletterRepository`. Migracja view do nowego namespace `front\Views`. + +**DODANE METODY (do istniejącej klasy `NewsletterRepository`):** +- `unsubscribe(string $hash): bool` — FIX: poprawna składnia medoo `delete()` (2 args zamiast 3) +- `confirmSubscription(string $hash): bool` +- `getHashByEmail(string $email): ?string` +- `removeByEmail(string $email): bool` +- `signup(string $email, string $serverName, bool $ssl, array $settings): bool` +- `sendQueued(int $limit, string $serverName, bool $ssl, string $unsubscribeLabel): bool` +- Konstruktor rozszerzony o opcjonalne: `ArticleRepository`, `NewsletterPreviewRenderer` (lazy-init) +- Testy: 10 nowych testów w `NewsletterRepositoryTest` + +**ZMIANA:** +- `front/factory/Newsletter` → USUNIĘTA (logika przeniesiona do `NewsletterRepository`) +- `front/view/Newsletter` → USUNIĘTA, zastąpiona przez `front/Views/Newsletter` (nowy namespace, bez `class.` prefix) +- `front/controls/Newsletter` → thin wrapper na `NewsletterRepository` +- `front/view/Site::show()` → `\front\Views\Newsletter::render()` +- `index.php` → `$newsletterRepo->sendQueued()` +- `front/factory/ShopClient` (4 miejsca) → `NewsletterRepository::templateByName()` +- `tests/bootstrap.php` — dodane stuby: `S::email_check()`, `S::get_session()`, `S::set_session()` + +**BUG FIX:** `newsletter_unsubscribe()` — medoo `delete()` wywoływane z 3 argumentami zamiast 2 + +--- + ### Etap: Category Frontend Service **Cel:** Migracja `front\factory\ShopCategory` do Domain. @@ -435,7 +463,7 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on - PHPDoc do wszystkich nowych klas Domain z `@since` - Aktualizacja `tests/bootstrap.php` - BUG FIX: `shop\Search` — typo `shop\Produt` → `shop\Product` -- BUG FIX: `front\factory\Newsletter::newsletter_unsubscribe()` — poprawka SQL +- ~~BUG FIX: `front\factory\Newsletter::newsletter_unsubscribe()` — poprawka SQL~~ **ZREALIZOWANE** w etapie Newsletter Frontend --- @@ -471,6 +499,16 @@ front\factory\ShopPromotion::promotion_type_XX() → shop\Product::is_product_on - 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. +### Nazewnictwo plikow +- Nowe klasy: `NazwaKlasy.php` (bez przedrostka `class.`) +- Legacy: `class.NazwaKlasy.php` — zostawiamy do momentu migracji danej klasy +- Autoloader obsluguje oba formaty (probuje `class.X.php`, potem `X.php`) +- Nowe katalogi z duzej litery: `Views/`, `Controllers/` (legacy: `view/`, `controls/`, `factory/`) + +### Statyczne vs instancyjne metody +- **Statyczne** — gdy klasa jest bezstanowa (brak konstruktora, brak properties, brak DI). Czyste funkcje: dane wchodzą, wynik wychodzi. Przykład: klasy VIEW (`front\Views\Languages::render($data)`, `front\view\Banners::banners($data)`) +- **Instancyjne** — gdy klasa ma zależności do wstrzyknięcia (repozytoria, serwisy) lub trzyma stan. Przykład: kontrolery z DI (`ShopProductController` z `ProductRepository`, `LanguagesRepository`) + ### Weryfikacja po każdym etapie 1. `composer test` (pełny suite PHPUnit) 2. Manualne sprawdzenie frontendu: strona główna, kategoria, produkt, koszyk, zamówienie diff --git a/docs/PROJECT_STRUCTURE.md b/docs/PROJECT_STRUCTURE.md index 3b3860f..b618153 100644 --- a/docs/PROJECT_STRUCTURE.md +++ b/docs/PROJECT_STRUCTURE.md @@ -203,7 +203,8 @@ autoload/ │ ├── Layouts/ │ │ └── LayoutsRepository.php │ ├── Newsletter/ -│ │ └── NewsletterRepository.php +│ │ ├── NewsletterRepository.php +│ │ └── NewsletterPreviewRenderer.php │ ├── Scontainers/ │ │ └── ScontainersRepository.php │ ├── Dictionaries/ @@ -231,8 +232,13 @@ autoload/ │ ├── controls/ # Stare kontrolery (niezależny fallback) │ ├── factory/ # Stare helpery (niezależny fallback) │ └── view/ # Widoki (statyczne - bez zmian) +├── front/ +│ ├── Controllers/ # Nowe kontrolery frontendowe (namespace \front\Controllers\) z DI +│ ├── Views/ # Nowe widoki (namespace \front\Views\) — czyste VIEW, statyczne +│ ├── controls/ # Legacy kontrolery (fallback) +│ ├── factory/ # Legacy helpery (stopniowo migrowane) +│ └── view/ # Legacy widoki ├── shop/ # Legacy - fasady do Domain -└── front/factory/ # Legacy - stopniowo migrowane ``` **Aktualizacja 2026-02-14 (ver. 0.268):** @@ -373,5 +379,15 @@ Pelna dokumentacja testow: `TESTING.md` - Usunieto stary plik `autoload/admin/class.Site.php`. - Pelna migracja admin zakonczona — wszystkie moduly na Domain + DI + Controllers. +## Aktualizacja 2026-02-16 (ver. 0.279) - Newsletter + Languages frontend migration +- Usunięta fasada `front\factory\Languages` — wszystkie 26 zależności przepięte bezpośrednio na `Domain\Languages\LanguagesRepository`. +- Usunięta fasada `front\factory\Newsletter` — logika przeniesiona do `Domain\Newsletter\NewsletterRepository` (6 nowych metod frontendowych). +- Usunięty stary kontroler `front\controls\Newsletter` i widok `front\view\Newsletter`. +- Utworzony nowy namespace `front\Controllers\` — pierwszy frontowy kontroler z DI: `NewsletterController`. +- Utworzony nowy namespace `front\Views\` — czyste widoki statyczne: `Languages`, `Newsletter`. +- Zaktualizowany routing w `front\controls\Site::route()` — `getControllerFactories()` (DI) z fallbackiem na stare `front\controls\`. +- Przepięte 4 wywołania `Newsletter::get_template()` w `front\factory\ShopClient` na `NewsletterRepository::templateByName()`. +- FIX: `newsletter_unsubscribe()` — błędna składnia medoo `delete()`. + --- *Dokument aktualizowany: 2026-02-16* diff --git a/docs/TESTING.md b/docs/TESTING.md index a44d000..a167208 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -36,7 +36,14 @@ Alternatywnie (Git Bash): Ostatnio zweryfikowano: 2026-02-16 ```text -OK (427 tests, 1378 assertions) +OK (437 tests, 1398 assertions) +``` + +Aktualizacja po migracji Newsletter + Languages frontend (2026-02-16, ver. 0.279): +```text +Pelny suite: OK (437 tests, 1398 assertions) +Nowe testy: NewsletterRepositoryTest (+10: unsubscribe, confirmSubscription, getHashByEmail, removeByEmail, signup, constructorOptionalDeps) +Zaktualizowane: tests/bootstrap.php (stuby: S::email_check, S::get_session, S::set_session) ``` Aktualizacja po migracji Settings + Languages frontend (2026-02-16, ver. 0.278): diff --git a/docs/UPDATE_INSTRUCTIONS.md b/docs/UPDATE_INSTRUCTIONS.md index 3f86ee0..34c1e1d 100644 --- a/docs/UPDATE_INSTRUCTIONS.md +++ b/docs/UPDATE_INSTRUCTIONS.md @@ -18,16 +18,17 @@ Aktualizacje znajdują się w folderze `updates/0.XX/` gdzie XX oznacza dziesią ## Procedura tworzenia nowej aktualizacji -## Status biezacej aktualizacji (ver. 0.278) +## Status biezacej aktualizacji (ver. 0.279) -- Wersja udostepniona: `0.278` (data: 2026-02-16). +- Wersja udostepniona: `0.279` (data: 2026-02-16). - Pliki publikacyjne: - - `updates/0.20/ver_0.278.zip` + - `updates/0.20/ver_0.279.zip` + - `updates/0.20/ver_0.279_files.txt` - Pliki metadanych aktualizacji: - - `updates/changelog.php` (dodany wpis `ver. 0.278`) - - `updates/versions.php` (`$current_ver = 278`) + - `updates/changelog.php` (dodany wpis `ver. 0.279`) + - `updates/versions.php` (`$current_ver = 279`) - Weryfikacja testow przed publikacja: - - `OK (427 tests, 1378 assertions)` + - `OK (437 tests, 1398 assertions)` ### 1. Określ numer wersji Sprawdź ostatnią wersję w `updates/` i zwiększ o 1. diff --git a/index.php b/index.php index 22ef03d..5a1353e 100644 --- a/index.php +++ b/index.php @@ -61,15 +61,17 @@ $mdb = new medoo( [ \front\controls\Site::check_url_params(); +$langRepo = new \Domain\Languages\LanguagesRepository( $mdb ); + if ( !$lang_id = \S::get_session( 'current-lang' ) ) { - $lang_id = \front\factory\Languages::default_language(); + $lang_id = $langRepo->defaultLanguage(); \S::set_session( 'current-lang', $lang_id ); } if ( !$lang = \S::get_session( 'lang-' . $lang_id ) ) { - $lang = \front\factory\Languages::lang_translations( $lang_id ); + $lang = $langRepo->translations( $lang_id ); \S::set_session( 'lang-' . $lang_id, $lang ); } @@ -159,7 +161,8 @@ if ( $settings[ 'statistic_code' ] ) $out = strrev( implode( strrev( $settings[ 'statistic_code' ] . '' ), explode( strrev( '' ), strrev( $out ), 2 ) ) ); /* wysyłka newslettera w tle */ -\front\factory\Newsletter::newsletter_send( 1 ); +$newsletterRepo = new \Domain\Newsletter\NewsletterRepository( $mdb ); +$newsletterRepo->sendQueued( 1, $_SERVER['SERVER_NAME'], !empty( $settings['ssl'] ), $lang['wypisz-sie'] ?? 'Wypisz się' ); $dom = new DOMDocument( '1.0', 'UTF-8' ); $dom -> loadHTML( $out ); diff --git a/templates/articles/article-entry.php b/templates/articles/article-entry.php index 3d570ec..8b2ce4c 100644 --- a/templates/articles/article-entry.php +++ b/templates/articles/article-entry.php @@ -6,7 +6,7 @@ article['language']['noindex'] ):?>rel="nofollow"> <?= $this -> article['language']['title'];?>

    - article['language']['noindex'] ):?>rel="nofollow"> article['language']['title'];?> + article['language']['noindex'] ):?>rel="nofollow"> article['language']['title'];?>

    article['date_add'] ) );?>
    diff --git a/templates/articles/news-list.php b/templates/articles/news-list.php index 9cad90f..e2ea21b 100644 --- a/templates/articles/news-list.php +++ b/templates/articles/news-list.php @@ -2,7 +2,7 @@ articles ) ): foreach ( $this -> articles as $article ):?>
  • - rel="nofollow"> + rel="nofollow">
  • diff --git a/templates/controls/alert-product-sets.php b/templates/controls/alert-product-sets.php index 487d58b..b0ae613 100644 --- a/templates/controls/alert-product-sets.php +++ b/templates/controls/alert-product-sets.php @@ -8,7 +8,7 @@ $product -> language['seo_link'] ? $url = '/' . $product -> language['seo_link'] : $url = '/p-' . $product['id'] . '-' . \S::seo( $product -> language['name'] ); - if ( \S::get_session( 'current-lang' ) != \front\factory\Languages::default_language() and $url != '#' ) + if ( \S::get_session( 'current-lang' ) != ( new \Domain\Languages\LanguagesRepository( $GLOBALS['mdb'] ) )->defaultLanguage() and $url != '#' ) $url = '/' . \S::get_session( 'current-lang' ) . $url; ?>
    diff --git a/templates/menu/pages.php b/templates/menu/pages.php index 4aaf2ac..d3221d1 100644 --- a/templates/menu/pages.php +++ b/templates/menu/pages.php @@ -34,7 +34,7 @@ if ( is_array( $this -> pages ) ) { echo '">'; echo ' pages ) ) echo '