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:
autoload/{namespace}/class.{ClassName}.php(legacy)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.php→getControllerFactories() - Frontend:
autoload/front/App.php→getControllerFactories() - API:
autoload/api/ApiRouter.php→getControllerFactories()
Routing
Admin (\admin\App)
- URL:
/admin/?module=shop_product&action=view_list module→ PascalCase (shop_product→ShopProduct) → controller lookupaction→ method call on controller- Auth checked before routing; 2FA supported
Frontend (\front\App)
- Routes stored in
pp_routestable (regex patterns, cached in Redis aspp_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-Keyheader (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_pendingin session during verification - Remember Me: 14-day HMAC-SHA256 signed cookie
API
- Stateless;
X-Api-Keyheader vspp_settings.api_keyviahash_equals()
Frontend
- Customer session in
$_SESSION['client'] - IP validation on every request (
$_SESSION['ip']vsREMOTE_ADDR)