# 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) ```php class ArticlesRepository { public function __construct($db) { $this->db = $db; } public function find(int $id): ?array { ... } public function save(...): int { ... } } ``` ### Factory Wrapper (deprecated bridge) ```php /** @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) ```php 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 ```php // 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_list` → `admin\controls\Articles::view_list()` Routing in `admin/index.php`: reads `$_GET['a']` → dynamically loads control class → calls action method. ## Frontend Routing `index.php` → `front\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