Files
aktualia.com.pl/.paul/codebase/architecture.md

5.5 KiB

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/RegAdmin/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