Files
cmsPRO/.paul/codebase/architecture.md
Jacek Pyziak a3caeb9a9a feat(06-admin-base): Admin\ base infrastructure — Form Edit System + Support layer (Phase 6)
Phase 6 zamknięta po 2 planach. Pełny fundament dla Phase 7-13 (migracja
17 admin controllers do Admin\ namespace).

06-01 (Forms infrastructure):
- Admin\ViewModels\Forms\* — 5 ViewModeli (687 L)
- Admin\Validation\FormValidator (196 L)
- composer.json: php >=7.4, PSR-4 paths cross-platform safe
  (Admin\ → autoload/admin/, Frontend\ → autoload/front/)

06-02 (Support layer):
- Admin\Support\TableListRequestFactory (99 L) — parser list z $_GET
- Admin\Support\Forms\FormRequestHandler (159 L) — POST + CSRF + walidacja + persist
- Admin\Support\Forms\FormFieldRenderer (494 L) — renderer HTML pól

Decyzje:
- Brak BaseController — Phase 7+ kontrolery jako POJOs z DI (jak shopPRO)
- PSR-4 filename fix: TableListRequestFactory.php (bez shopPRO 'class.' prefix)
- PascalCase namespace (Admin\Support) na lowercase folder admin/
  ze względu na Windows fs case-insensitivity vs legacy admin/controls/

Pliki: 8 nowych klas, 1635 L kodu PHP 7.4-kompatybilnego, zero regresji.
Smoke test: walidacja e-maila zwraca PL komunikat, factory parsuje
?page=&per_page=&sort=&filter=, Domain/Shared nadal ładują się.

PHPUnit: 37/37 OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 23:32:26 +02:00

6.9 KiB

Architecture

Generated: 2026-04-26

Overview

cmsPRO uses a 3-layer architecture with clean admin/frontend separation:

Request
  ↓
Controls (admin\controls\ or front\controls\)   ← request handling
  ↓
Factories (admin\factory\ or front\factory\)    ← DEPRECATED wrappers → will be removed
  ↓
Domain Repositories (Domain\*\*Repository)      ← data access (new pattern)
  ↓
Medoo ORM → MySQL

Views are rendered through admin\view\* / front\view\*Shared\Tpl\Tpl → Savant3 templates.

Directory Map

autoload/
├── autoloader.php                  Hybrid PSR-4 + legacy autoloader
├── class.S.php                     Global helper facade (deprecated wrapper)
├── class.Article.php               Legacy entity (ArrayAccess)
├── class.Page.php                  Legacy entity
├── class.Scontainer.php            Legacy entity
├── class.Cache.php / class.Cron.php / class.Image.php / class.Html.php
│
├── Domain/                         NEW — Repository pattern, DDD
│   ├── Articles/ArticlesRepository.php      (648 lines)
│   ├── Authors/AuthorsRepository.php        (156 lines)
│   ├── Banners/BannersRepository.php        (148 lines)
│   ├── Languages/LanguagesRepository.php    (213 lines)
│   ├── Layouts/LayoutsRepository.php        (123 lines)
│   ├── Newsletter/NewsletterRepository.php  (281 lines)
│   ├── Pages/PagesRepository.php            (451 lines)
│   ├── Scontainers/ScontainersRepository.php (110 lines)
│   ├── Settings/SettingsRepository.php      (73 lines)
│   └── User/UserRepository.php              (235 lines)
│
├── Shared/                         Cross-cutting services
│   ├── Helpers/Helpers.php         God class — 1220 lines (⚠ needs splitting)
│   ├── Tpl/Tpl.php                 Template renderer (checks templates_user/ first)
│   ├── Email/Email.php             Email service (wraps PHPMailer)
│   ├── Cache/CacheHandler.php      File-based cache (gzdeflate, TTL)
│   ├── Security/CsrfToken.php      CSRF token generation + validation
│   ├── Html/Html.php               HTML form element builder
│   └── Image/ImageManipulator.php  Image processing
│
├── admin/                          Mixed: legacy lowercase namespaces + new Admin\* PSR-4
│   │
│   │  NEW (Phase 6) — namespace Admin\* (PascalCase, PSR-4)
│   ├── ViewModels/Forms/           Admin\ViewModels\Forms\* — Form Edit System (5 VMs, 687 L)
│   ├── Validation/FormValidator.php
│   ├── Support/TableListRequestFactory.php   Admin\Support — list parser
│   ├── Support/Forms/FormRequestHandler.php  POST + CSRF + validate + persist
│   ├── Support/Forms/FormFieldRenderer.php   HTML renderer (delegates Shared\Html\Html)
│   │
│   │  LEGACY — namespace admin\* (lowercase, hybrid loader)
│   ├── class.Site.php              Admin routing + 2FA
│   ├── controls/class.*.php        18 request handler classes (static methods)
│   ├── factory/class.*.php         18 @deprecated wrappers
│   └── view/class.*.php            14 template renderer classes
│
└── front/
    ├── controls/class.Site.php     Main frontend router
    ├── controls/class.*.php        4 frontend controllers
    ├── factory/class.*.php         17 frontend factories
    └── view/class.*.php            View renderers

admin/
├── index.php                       Admin entry point (IP check, session, routing)
├── ajax.php                        Admin AJAX dispatcher → admin/ajax/*.php
└── templates/                      Admin Savant3 templates (per module)

templates/                          Frontend Savant3 templates
templates_user/                     User-overridable template overrides
plugins/
├── special-actions.php             Hook: pre-routing
├── special-actions-middle.php      Hook: mid-request
└── special-actions-end.php         Hook: post-rendering

Namespace Convention

Namespace Path Convention
admin\controls\ autoload/admin/controls/class.*.php Legacy lowercase
admin\factory\ autoload/admin/factory/class.*.php Legacy, @deprecated
admin\view\ autoload/admin/view/class.*.php Legacy lowercase
front\controls\ autoload/front/controls/class.*.php Legacy lowercase
front\factory\ autoload/front/factory/class.*.php Legacy lowercase
Domain\*\ autoload/Domain/*/ClassName.php PSR-4 PascalCase
Shared\*\ autoload/Shared/*/ClassName.php PSR-4 PascalCase
Admin\*\ autoload/admin/*/ClassName.php PSR-4 PascalCase namespace, lowercase folder (Win fs collision with legacy)

Key Patterns

Repository Pattern (Domain layer)

class ArticlesRepository {
    public function __construct($db) { $this->db = $db; }
    public function find(int $id): ?array { ... }
    public function save(...): int { ... }
}

Factory Wrapper (deprecated bridge)

/** @deprecated Używaj Domain\Articles\ArticlesRepository przez DI */
class Articles {
    private static function repo(): ArticlesRepository {
        global $mdb;
        return new ArticlesRepository($mdb);
    }
    public static function article_delete($id): bool {
        return self::repo()->deleteArticle($id);
    }
}

Controls (request handler)

class Articles {
    public static function article_delete() {
        global $user;
        if (!admin\factory\Users::check_privileges('articles', $user['id']))
            return \S::alert('Brak uprawnień');
        // delegate to factory → repository
    }
}

Global Helper Facade

// class.S.php — calls Shared\Helpers\Helpers via __callStatic
\S::get('param')          // → Helpers::get()
\S::delete_cache()        // → Helpers::delete_cache()

Admin Routing

GET /admin/?a=articles&action=view_listadmin\controls\Articles::view_list()

Routing in admin/index.php: reads $_GET['a'] → dynamically loads control class → calls action method.

Frontend Routing

index.phpfront\controls\Site::route() — checks \S::get('search'), \S::get('tag'), \S::get('article'), then falls through to page rendering by page_type.

Caching Strategy

Cache Type Location Engine
Page cache cache/ Full HTML output
Object cache temp/md5[0]/md5[1]/ gzdeflate + serialize, TTL
WebP images cache/ Filesystem
Language strings $_SESSION PHP session

Plugin System

3 hook points in frontend lifecycle (files in plugins/ directory, included if they exist):

  1. special-actions.php — after language init, before routing
  2. special-actions-middle.php — before cache check
  3. special-actions-end.php — before final output