update
This commit is contained in:
158
.paul/codebase/architecture.md
Normal file
158
.paul/codebase/architecture.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Architecture
|
||||
|
||||
**Analysis Date:** 2026-05-10
|
||||
|
||||
## Pattern Overview
|
||||
|
||||
**Overall:** PrestaShop 1.7.8.x MVC e-commerce monolith with hook-based module extensibility and a Symfony admin layer.
|
||||
|
||||
**Key Characteristics:**
|
||||
- Front-office: legacy PrestaShop dispatcher + Smarty templates
|
||||
- Back-office (admin): Symfony 4-style kernel (`app/AppKernel.php`) at non-standard path `iadmin/`
|
||||
- Hook-based publish/subscribe extension model — modules attach to named hooks
|
||||
- Core class overrides via `override/classes/` (monkey-patch layer)
|
||||
- Multi-domain (`drmaterac.pl` + `lulandia.pl`) served from a single install via `.htaccess` rules
|
||||
|
||||
## Layers
|
||||
|
||||
**Entry / Routing Layer:**
|
||||
- Purpose: Route HTTP requests via mod_rewrite to dispatcher / Symfony kernel
|
||||
- Contains: `.htaccess` (429 lines), `index.php` (front), `iadmin/index.php` (back-office)
|
||||
- Used by: All HTTP requests
|
||||
- Key class: `classes/Dispatcher.php` (overridden in `override/classes/Dispatcher.php`)
|
||||
|
||||
**Controller Layer:**
|
||||
- Purpose: Handle request-specific logic (cart, product, checkout, search)
|
||||
- Contains: `controllers/front/*.php` (CartController, OrderController, ProductController…)
|
||||
- Base classes: `classes/controller/FrontController.php`, `ModuleFrontController.php`, `AdminController.php`, `ProductListingFrontController.php`
|
||||
- Overrides: `override/classes/controller/FrontController.php`, `override/classes/controller/ProductListingFrontController.php`
|
||||
|
||||
**Model / Domain Layer (ObjectModel):**
|
||||
- Purpose: ORM-style domain entities (Product, Cart, Order, Customer, Category…)
|
||||
- Contains: `classes/Product.php`, `classes/Cart.php`, `classes/Order.php`, `classes/Customer.php`, etc.
|
||||
- Base: `classes/ObjectModel.php`
|
||||
- Overrides: 31 files in `override/classes/` (e.g. `override/classes/Product.php` adds Google Shopping fields; `override/classes/Cart.php` extends `getOrderTotal()` for ets_promotion pricing)
|
||||
|
||||
**Module Layer (extensibility):**
|
||||
- Purpose: Optional features attached via hooks; first-class extension mechanism
|
||||
- Contains: `modules/*/` (50+ installed modules, ~138 entries on disk)
|
||||
- Custom in this project: `modules/crosssellpro/` (Cross Sell PRO carousel), `modules/caraty/`
|
||||
- Active third-party: `modules/paynow/`, `modules/santandercredit/`, `modules/empikmarketplace/`, `modules/dpdpoland/`, `modules/pdgoogleanalytycs4pro/`, `modules/fbpixel/`, `modules/ekomiratingsandreviews/`, `modules/ceneo_trustedreviews/`, etc.
|
||||
|
||||
**Theme / Presentation Layer:**
|
||||
- Purpose: Page templates and visual assets
|
||||
- Contains: `themes/leo_gstore/` (active child theme, Leo Gstore v1.4)
|
||||
- Templates: `themes/leo_gstore/templates/*.tpl` (layout, cart, checkout, product…)
|
||||
- Per-module overrides: `themes/leo_gstore/modules/<module>/views/templates/hook/*.tpl`
|
||||
- Assets: `themes/leo_gstore/assets/cache/` (bundled JS/CSS)
|
||||
|
||||
**Cross-cutting / Hook System:**
|
||||
- `classes/Hook.php` + `override/classes/Hook.php` (PageCache module integration)
|
||||
- Hooks dispatch from controllers/templates → fire each registered module's `hook<Name>()` method
|
||||
- Registration table: `ps_hook_module`
|
||||
|
||||
## Data Flow
|
||||
|
||||
**HTTP Request lifecycle (front-office):**
|
||||
|
||||
1. Apache receives request → `.htaccess` rewrite rule (line ~353) routes non-physical URLs to `index.php`
|
||||
2. `Dispatcher::getInstance()->dispatch()` resolves URL to a controller (e.g. `CartController`)
|
||||
3. Controller `init()` / `initContent()` runs; sets up `Context` (cart, customer, shop, language)
|
||||
4. Controller dispatches display hooks (`displayHeader`, `displayShoppingCartFooter`, `actionFrontControllerSetMedia`, etc.)
|
||||
5. Each subscribing module's `hook<Name>()` method runs and may render Smarty partials
|
||||
6. Smarty renders the theme template (`themes/leo_gstore/templates/cart.tpl`) injecting hook output
|
||||
7. Response (HTML + CSS + JS) returned to client
|
||||
|
||||
**Admin lifecycle:**
|
||||
- `iadmin/index.php` boots `app/AppKernel.php` (Symfony) — `iadmin/` is the renamed admin folder (security-by-obscurity)
|
||||
- Symfony routes to controllers; falls back to legacy `Dispatcher` if Symfony routing fails (`iadmin/index.php` line ~93)
|
||||
|
||||
**API:**
|
||||
- `webservice/dispatcher.php` — REST endpoint reached via `.htaccess` line ~323
|
||||
|
||||
**State Management:**
|
||||
- Per-request state held in `classes/Context.php` singleton (`$context->cart`, `$context->customer`, `$context->shop`, `$context->controller`, `$context->language`)
|
||||
- Persistent state in MySQL (`materac_*` tables)
|
||||
- Caching configured but disabled (Memcached driver inactive)
|
||||
|
||||
## Key Abstractions
|
||||
|
||||
**Module:**
|
||||
- Purpose: Attachable feature unit registering hook callbacks
|
||||
- Examples: `modules/crosssellpro/crosssellpro.php`, `modules/paynow/paynow.php`, `modules/fbpixel/fbpixel.php`
|
||||
- Pattern: subclasses `Module` (`classes/Module.php`); `install()` registers hooks; `hook<Name>()` methods are invoked dynamically
|
||||
|
||||
**ObjectModel:**
|
||||
- Purpose: ORM base for domain entities — handles `add()`, `update()`, `delete()`, hydration, validation
|
||||
- Examples: `classes/Product.php`, `classes/Cart.php`, `classes/Order.php`
|
||||
- Pattern: declarative `$definition` array describes table + fields
|
||||
|
||||
**Hook (publish/subscribe):**
|
||||
- Purpose: Decouple core from extensions
|
||||
- Examples: `displayShoppingCartFooter`, `displayCheckoutSummaryTop`, `displayHeader`, `actionFrontControllerSetMedia`
|
||||
- Pattern: `Hook::exec('hookName', ...)` dispatches; `$module->hookHookName(...)` receives
|
||||
|
||||
**Context:**
|
||||
- Purpose: Per-request global container (cart, customer, shop, language, controller)
|
||||
- Pattern: Singleton — `Context::getContext()`
|
||||
|
||||
**Override:**
|
||||
- Purpose: Patch core class behavior without editing core
|
||||
- Examples: `override/classes/Cart.php` (custom totals), `override/classes/Hook.php` (PageCache hooks)
|
||||
- Pattern: Files in `override/classes/<X>.php` override `classes/<X>.php` via PrestaShop autoloader
|
||||
|
||||
## Entry Points
|
||||
|
||||
**Front-office:**
|
||||
- Location: `index.php` (root) — invoked implicitly via `.htaccess`
|
||||
- Triggers: Any non-physical URL on the public domains
|
||||
- Responsibilities: Bootstrap → Dispatcher → controller dispatch
|
||||
|
||||
**Back-office:**
|
||||
- Location: `iadmin/index.php` (custom-named admin folder)
|
||||
- Triggers: Admin URL access
|
||||
- Responsibilities: Boot `AppKernel`, fall back to legacy dispatcher when needed
|
||||
|
||||
**Web service:**
|
||||
- Location: `webservice/dispatcher.php`
|
||||
- Triggers: REST API calls
|
||||
|
||||
**Custom Cross-Sell module:**
|
||||
- Location: `modules/crosssellpro/crosssellpro.php`
|
||||
- Hooks registered (in `install()`): `displayShoppingCartFooter`, `displayCheckoutSummaryTop`, `displayHeader`, `actionFrontControllerSetMedia`
|
||||
- Key methods: `hookDisplayShoppingCartFooter()`, `hookDisplayCheckoutSummaryTop()`, `buildCrossSellProducts()`, `collectAccessoryIds()`, `getCombinationFlags()`, `presentProducts()`
|
||||
- Templates: `modules/crosssellpro/views/templates/hook/cartCrossSell.tpl`, `…/checkoutCrossSell.tpl`
|
||||
- Front assets: `modules/crosssellpro/views/css/cartCrossSell.css`, `modules/crosssellpro/views/js/cartCrossSell.js`
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Strategy:** PrestaShop legacy approach — `Tools::displayError()`, exceptions logged to `iadmin/errors.log` and `errors.log` (root). Exceptions in hooks may silently degrade module output.
|
||||
|
||||
**Patterns:**
|
||||
- `try/catch` rare in custom code; `import-product.php` lacks transaction wrapping/rollback
|
||||
- Mail send paths in `buy-by-phone.php` minimally handle PHPMailer failures
|
||||
- `errors.log` at repo root + `iadmin/errors.log` (5 MB historical) — both inside webroot (concern, see `concerns.md`)
|
||||
|
||||
## Cross-Cutting Concerns
|
||||
|
||||
**Logging:**
|
||||
- File-based: `errors.log` (root), `iadmin/errors.log`
|
||||
- Symfony Monolog wired in admin via `MonologBundle`
|
||||
|
||||
**Caching:**
|
||||
- `pagecache` module
|
||||
- Memcached configured but disabled (`app/config/parameters.php`)
|
||||
- Smarty compiled templates: `themes/leo_gstore/cache/`
|
||||
|
||||
**Authentication:**
|
||||
- Customer auth: PrestaShop core (cookies + DB)
|
||||
- Admin auth: Symfony Security via `iadmin/`
|
||||
|
||||
**Image handling:**
|
||||
- WebP delivery via `.htaccess` content negotiation + `modules/x13webp/`
|
||||
- Lazy-loading image override (`pshowlazyimg` override)
|
||||
|
||||
---
|
||||
|
||||
*Architecture analysis: 2026-05-10*
|
||||
*Update when major patterns change*
|
||||
Reference in New Issue
Block a user