Files
shopPRO/.paul/codebase/architecture.md
2026-03-12 13:36:06 +01:00

10 KiB

Architecture & Structure

Directory Layout

shopPRO/
├── autoload/                   # Core application code (custom autoloader)
│   ├── Domain/                 # Business logic — 29 modules
│   ├── Shared/                 # Cross-cutting utilities
│   │   ├── Cache/              # CacheHandler, RedisConnection
│   │   ├── Email/              # Email (PHPMailer wrapper)
│   │   ├── Helpers/            # Static utility methods
│   │   ├── Html/               # HTML escaping/generation
│   │   ├── Image/              # ImageManipulator
│   │   └── Tpl/                # Template engine
│   ├── admin/                  # Admin panel layer
│   │   ├── App.php             # Router & DI factory
│   │   ├── Controllers/        # 28 DI controllers
│   │   ├── Support/            # Forms, TableListRequestFactory
│   │   ├── Validation/         # FormValidator
│   │   └── ViewModels/         # Forms/, Common/
│   ├── front/                  # Frontend layer
│   │   ├── App.php             # Router & DI factory
│   │   ├── LayoutEngine.php    # Placeholder-based layout engine
│   │   ├── Controllers/        # 8 DI controllers
│   │   └── Views/              # 11 static view classes
│   └── api/                    # REST API layer
│       ├── ApiRouter.php       # Auth + routing
│       └── Controllers/        # 4 DI controllers
├── admin/
│   ├── index.php               # Admin entry point
│   ├── ajax.php                # Admin AJAX handler
│   ├── templates/              # Admin view templates
│   └── layout/                 # Admin CSS/JS/icons
├── templates/                  # Frontend view templates
├── libraries/                  # Third-party libraries
├── tests/                      # PHPUnit test suite
├── docs/                       # Technical documentation
├── index.php                   # Frontend entry point
├── ajax.php                    # Frontend AJAX handler
├── api.php                     # REST API entry point
├── cron.php                    # Background job processor
└── config.php                  # DB/Redis config (NOT in repo)

Autoloader

Custom autoloader in each entry point — tries two conventions:

  1. autoload/{namespace}/class.{ClassName}.php (legacy)
  2. autoload/{namespace}/{ClassName}.php (PSR-4 style, preferred)

Namespace → directory mapping (case-sensitive on Linux):

  • \Domain\autoload/Domain/
  • \admin\autoload/admin/ (lowercase a — never \Admin\)
  • \front\autoload/front/
  • \api\autoload/api/
  • \Shared\autoload/Shared/

Dependency Injection

Manual factory pattern in router classes. Each entry point wires dependencies once:

// Example from admin\App::getControllerFactories()
'ShopProduct' => function() {
    global $mdb;
    return new \admin\Controllers\ShopProductController(
        new \Domain\Product\ProductRepository($mdb),
        new \Domain\Integrations\IntegrationsRepository($mdb),
        new \Domain\Languages\LanguagesRepository($mdb)
    );
}

DI wiring locations:

  • Admin: autoload/admin/App.phpgetControllerFactories()
  • Frontend: autoload/front/App.phpgetControllerFactories()
  • API: autoload/api/ApiRouter.phpgetControllerFactories()

Routing

Admin (\admin\App)

  • URL: /admin/?module=shop_product&action=view_list
  • module → PascalCase (shop_productShopProduct) → controller lookup
  • action → method call on controller
  • Auth checked before routing; 2FA supported

Frontend (\front\App)

  • Routes stored in pp_routes table (regex patterns, cached in Redis as pp_routes:all)
  • Match URI → extract destination params → merge with $_GET
  • Special params: ?product=ID, ?category=ID, ?article=ID
  • Controller dispatch via getControllerFactories()
  • Unmatched → static page content

API (\api\ApiRouter)

  • URL: /api.php?endpoint=orders&action=getOrders
  • Stateless — auth via X-Api-Key header (hash_equals())
  • endpoint → controller, action → method

Request Lifecycle (Frontend)

HTTP GET /produkt/nazwa-produktu
  → index.php (autoload, init Medoo, session, language)
  → Fetch pp_routes from Redis (or DB)
  → Regex match → extract ?product=123
  → front\LayoutEngine::show()
    → Determine layout (pp_layouts)
    → Replace placeholders [MENU:ID], [BANER_STRONA_GLOWNA], etc.
    → Call view classes / repositories for each placeholder
  → Output HTML (with GTM, meta OG, WebP, lazy loading)

Request Lifecycle (Admin)

HTTP GET /admin/?module=shop_order&action=view_list
  → admin/index.php (IP check, session, auth cookie check)
  → admin\App::update() (run pending DB migrations)
  → admin\App::special_actions() (handle s-action=user-logon etc.)
  → admin\App::render()
    → Auth check → if not logged in, show login form
    → admin\App::route()
      → 'shop_order' → ShopOrder → factory()
      → new ShopOrderController(OrderAdminService, ProductRepository)
      → ShopOrderController::viewList()
      → Tpl::view('shop-order/orders-list', [...])
    → Tpl::render('site/main-layout', ['content' => $html])
  → Output admin HTML

Domain Modules (29)

All in autoload/Domain/{Module}/{Module}Repository.php:

Module Repository Notes
Article ArticleRepository Blog/news
Attribute AttributeRepository Product attributes (color, size)
Banner BannerRepository Promo banners
Basket (static) Cart calculations
Cache (utilities) Cache key constants
Category CategoryRepository Category tree
Client ClientRepository Customer accounts
Coupon CouponRepository Discount codes
CronJob CronJobRepository, CronJobProcessor Job queue
Dashboard DashboardRepository Admin stats
Dictionaries DictionariesRepository Units, enums
Integrations IntegrationsRepository Apilo, Ekomi (875 lines — too large)
Languages LanguagesRepository i18n translations
Layouts LayoutsRepository Page templates
Newsletter NewsletterRepository, NewsletterPreviewRenderer Email campaigns
Order OrderRepository, OrderAdminService Orders, status
Pages PagesRepository Static pages
PaymentMethod PaymentMethodRepository Payment gateways
Producer ProducerRepository Brands
Product ProductRepository Core catalog (3583 lines — too large)
ProductSet ProductSetRepository Bundles
Promotion PromotionRepository Special offers
Scontainers ScontainersRepository Content blocks
Settings SettingsRepository Shop config
ShopStatus ShopStatusRepository Order statuses
Transport TransportRepository Shipping
Update UpdateRepository DB migrations
User UserRepository Admin users, 2FA

Admin Controllers (28)

All in autoload/admin/Controllers/: ArticlesController, ArticlesArchiveController, BannerController, DashboardController, DictionariesController, FilemanagerController, IntegrationsController, LanguagesController, LayoutsController, NewsletterController, PagesController, ProductArchiveController, ScontainersController, SettingsController, ShopAttributeController, ShopCategoryController, ShopClientsController, ShopCouponController, ShopOrderController, ShopPaymentMethodController, ShopProducerController, ShopProductController (1199 lines), ShopProductSetsController, ShopPromotionController, ShopStatusesController, ShopTransportController, UpdateController, UsersController

Frontend Controllers (8)

autoload/front/Controllers/: NewsletterController, SearchController, ShopBasketController, ShopClientController, ShopCouponController, ShopOrderController, ShopProducerController, ShopProductController

Frontend Views (11, static)

autoload/front/Views/: Articles, Banners, Languages, Menu, Newsletter, Scontainers, ShopCategory, ShopClient, ShopPaymentMethod, ShopProduct, ShopSearch

API Controllers (4)

autoload/api/Controllers/: OrdersApiController, ProductsApiController, CategoriesApiController, DictionariesApiController

Template System

Tpl Engine (\Shared\Tpl\Tpl)

// Controller
return \Shared\Tpl\Tpl::view('shop-category/category-edit', [
    'category' => $data,
    'languages' => $langs,
]);

// Template (templates/shop-category/category-edit.php)
<h1><?= $this->category['name'] ?></h1>

Search order: templates_user/, templates/, ../templates_user/, ../templates/

Frontend Layout Engine (\front\LayoutEngine)

Replaces placeholders in layout HTML loaded from pp_layouts.html:

  • [MENU:ID], [KONTENER:ID], [LANG:key]
  • [PROMOWANE_PRODUKTY:limit], [PRODUKTY_TOP:limit], [PRODUKTY_NEW:limit]
  • [BANER_STRONA_GLOWNA], [BANERY], [COPYRIGHT]
  • [AKTUALNOSCI:layout_id:limit], [PRODUKTY_KATEGORIA:cat_id:limit]

Admin Form System

Universal form system for CRUD views. Full docs: docs/FORM_EDIT_SYSTEM.md.

Component Class Location
View model FormEditViewModel autoload/admin/ViewModels/Forms/
Field definition FormField same
Field type enum FormFieldType same
Tab FormTab same
Action FormAction same
Validation FormValidator autoload/admin/Validation/
POST parsing FormRequestHandler autoload/admin/Support/Forms/
Rendering FormFieldRenderer autoload/admin/Support/Forms/
Template form-edit.php admin/templates/components/

Authentication

Admin

  • Session: $_SESSION['user'] after successful login
  • 2FA: 6-digit code sent by email; twofa_pending in session during verification
  • Remember Me: 14-day HMAC-SHA256 signed cookie

API

  • Stateless; X-Api-Key header vs pp_settings.api_key via hash_equals()

Frontend

  • Customer session in $_SESSION['client']
  • IP validation on every request ($_SESSION['ip'] vs REMOTE_ADDR)