# Architecture **Analysis Date:** 2026-04-27 ## Pattern Overview **Overall:** Custom PHP MVC Monolith (dual frontend — public + admin) **Key Characteristics:** - Single shared `core/` layer powering both public and admin frontends - Front Controller routing via Apache rewrite → `index.php` → Router → Controller - All templating via Smarty (no JSON API, no SPA) - Session-based admin auth; anonymous public form with reCAPTCHA ## Layers **Router / Front Controller:** - Purpose: Parse URL, select controller and action - Contains: `Router.class.php`, `index.php` entry points - Location: `_rejestracja/index.php`, `_rejestracja/Admin/index.php` - Depends on: Core class loader - Used by: Nothing (entry point) **Controller Layer:** - Purpose: Handle request lifecycle — auth, business logic dispatch, template assignment - Contains: `*Controller.php` files; each has `preDispatch`, `{Name}Action`, `postDispatch` - Location: `_rejestracja/controller/` (public), `_rejestracja/Admin/controller/` - Depends on: DAL layer, Smarty, SessionProxy, Request - Used by: Router **DAL Layer (Data Access):** - Purpose: Typed database access; maps rows to model objects - Contains: `Mf{Entity}DAL.class.php` files, `DefaultDAL.class.php` base - Location: `_rejestracja/core/model/` - Depends on: MySQL connection, `DalData` query config objects, `DataObject` base model - Used by: Controllers **Model Layer:** - Purpose: Typed domain objects with getters/setters - Contains: `Mf{Entity}.class.php` with `$fields` array mapping DB columns to properties - Location: `_rejestracja/core/model/` - Depends on: `DataObject.class.php` base - Used by: DAL (hydration), Controllers, Templates (via Smarty assigns) **Template Layer:** - Purpose: HTML rendering via Smarty - Contains: `.tpl` files, Smarty plugins (`{translate}`, `{formField}`, `{url}`, `{dropDownContainer}`) - Location: `_rejestracja/template/`, `_rejestracja/Admin/template/` - Depends on: Variables assigned in controller (`$this->smarty->assign(...)`) - Used by: Nothing (output layer) ## Data Flow **Public Registration Request:** 1. Browser `POST /_rejestracja/index` → Apache rewrite → `_rejestracja/index.php` 2. `Router` parses URL → selects `IndexController` 3. `IndexController::preDispatch()` sets up shared context (Smarty, layout) 4. `IndexController::IndexAction()` runs: - Validates reCAPTCHA - Reads POST via `Request::GetPost()` - Hydrates `MfParticipant` model - Calls `MfParticipantDAL::Save($obj)` → INSERT/UPDATE - Sends confirmation email via PHPMailer - `$this->smarty->assign(...)` + Smarty renders confirmation template 5. HTML response returned to browser **Admin Registration List Request:** 1. Browser `GET /_rejestracja/Admin/Calc/Reg` → `Admin/index.php` → Router 2. `CalcController::preDispatch()` — calls `RunShared('Auth', $param)` (session check) 3. `CalcController::RegAction()`: - `MfParticipantDAL::GetResult($dalData)` with sort DESC - `$this->smarty->assign('arrayObj', $arrayObjReg)` 4. Smarty renders `Admin/template/partial/Calc/Reg.tpl` **State Management:** - PHP sessions via `SessionProxy` for admin auth and transient UI state - No in-memory cache; every request hits MySQL ## Key Abstractions **DataObject / Model:** - Purpose: Typed domain objects with `$fields` array auto-mapping DB↔PHP - Examples: `MfParticipant`, `MfParameters`, `MfDictionary` - Pattern: Active-record-lite; `$fields = ['db_col' => 'PropName']`, auto-generates getters/setters via `__get`/`__set` or explicit methods **DefaultDAL / DalData:** - Purpose: Generic CRUD over MySQL; `DalData` is a query config object (conditions, sort, limit) - Examples: `MfParticipantDAL`, `MfParametersDAL`, `MfDictionaryDAL` - Pattern: `GetDalDataObj()` → configure → `GetResult()` / `GetById()` / `Save()` / `Delete()` **Smarty Plugin Suite:** - Purpose: Template-level abstractions for common patterns - Key plugins: `{translate word='key'}` (dictionary lookup), `{formField name="" type=""}` (form inputs — text/hidden only), `{url label=X}` (router-aware URL generation), `{dropDownContainer}` (collapsible admin sections) - Pattern: Custom Smarty plugins registered in `_rejestracja/core/` ## Entry Points **Public Frontend:** - Location: `_rejestracja/index.php` - Triggers: HTTP request to `/_rejestracja/` - Responsibilities: Bootstrap core, invoke Router → Controller **Admin Frontend:** - Location: `_rejestracja/Admin/index.php` - Triggers: HTTP request to `/_rejestracja/Admin/` - Responsibilities: Same bootstrap + admin-specific auth via `RunShared('Auth')` ## Error Handling **Strategy:** Mostly unhandled — exceptions catch in isolated blocks, errors logged to PHP error_log **Patterns:** - `try/catch` in `RegDeleteAction` (DAL delete errors logged but swallowed) - `Validator` class collects field errors and returns them to template via `$out` array - No global exception handler observed ## Cross-Cutting Concerns **Logging:** - PHP `error_log` only; `Utils::ArrayDisplay()` for dev debug (should be removed pre-deploy) **Validation:** - `Validator` class at controller level for required-field checks - reCAPTCHA for bot protection on public form - No input sanitization layer beyond Smarty auto-escaping in templates **Authentication:** - Admin: `RunShared('Auth', $param)` in every admin controller `preDispatch` - Public: None (anonymous registration form) **Internationalization:** - `{translate word='key'}` Smarty plugin reads from `mf_dictionary` table - All visible strings for the registration form are dictionary-backed --- *Architecture analysis: 2026-04-27* *Update when major patterns change*