Files
drmaterac.pl/.paul/codebase/conventions.md
2026-05-10 21:32:38 +02:00

151 lines
5.6 KiB
Markdown

# Coding Conventions
**Analysis Date:** 2026-05-10
## Naming Patterns
**Files:**
- PHP class files: PascalCase matching class — `classes/Product.php`, `classes/Cart.php`
- Module entry file: lowercase, matches directory — `modules/crosssellpro/crosssellpro.php`
- Smarty templates: camelCase per module — `cartCrossSell.tpl`, `checkoutCrossSell.tpl`
- Asset files: camelCase — `cartCrossSell.css`, `cartCrossSell.js`
**Functions / Methods:**
- camelCase — `buildCrossSellProducts()`, `collectAccessoryIds()`, `getCombinationFlags()`, `presentProducts()` (`modules/crosssellpro/crosssellpro.php`)
- Hook handlers: literal prefix `hook` + PascalCase hook name — `hookDisplayShoppingCartFooter()`, `hookActionFrontControllerSetMedia()`
**Variables:**
- New custom code: `$camelCase``$cartProducts`, `$inCartProductIds`, `$productId`
- Legacy / DB-driven code: `$snake_case``$id_product`, `$id_cart`, `$id_shop` (mirrors PrestaShop column names; expected when interacting with ObjectModel data)
**Classes:**
- PascalCase, suffixed `Core` for PrestaShop core — `class ProductCore extends ObjectModel` (`classes/Product.php`)
- Module classes: PascalCase matching folder — `class Crosssellpro extends Module`
**Hook names (string identifiers):**
- camelCase, registered as strings — `displayShoppingCartFooter`, `displayHeader`, `actionFrontControllerSetMedia`
## Code Style
**PHP Formatting:**
- 4-space indentation (no tabs)
- PSR-12-compatible style for new custom code
- Opening braces on same line: `class Crosssellpro extends Module {`
- Single quotes preferred for strings
- Escape filter pattern in templates: `{$product.name|escape:'htmlall':'UTF-8'}`
**JavaScript Formatting:**
- 2-space indentation
- Legacy ES5 in custom module JS (`var` declarations) — `modules/crosssellpro/views/js/cartCrossSell.js`
- camelCase for functions/variables
- Data-attribute targeting: `[data-crosssellpro-block="1"]`
**Smarty:**
- `{$variable|filter:'arg':'arg'}` for output with escaping
- `{if}…{/if}`, `{foreach}…{/foreach}`, `{assign}` block syntax
**Linting:**
- No root-level `.php-cs-fixer.php` or `phpstan.neon`
- Per-module PHPStan/PHP-CS-Fixer config available in some PrestaShop modules (`modules/<m>/tests/phpstan/phpstan.neon`)
## Import Organization
**PHP:**
- `<?php` opener with no namespace declared in custom modules (PrestaShop legacy autoloader convention)
- `use` statements for Symfony / vendor classes when needed
- No enforced ordering — follow existing file's pattern
**JS:**
- Vanilla DOM manipulation in custom module JS — no module bundler
- Theme JS bundled in `themes/leo_gstore/assets/cache/`
## Error Handling
**Patterns:**
- PrestaShop convention: input via `Tools::getValue('key')` (sanitizes; preferred over raw `$_GET`/`$_POST`)
- DB queries via `Db::getInstance()` with `pSQL()` for sanitization (legacy pattern; not parameterized)
- `try/catch` rare — exceptions surfaced via `Tools::displayError()` or logged
- Hook methods generally return rendered output; failure typically silent (returns empty string)
**Custom-code observations:**
- `import-product.php` has minimal error handling, no transaction wrapping
- `buy-by-phone.php` accesses `$_POST` directly without `Tools::getValue()` — see `concerns.md`
## Logging
**Framework:**
- Symfony Monolog (admin layer) via `app/AppKernel.php`
- File logs at `errors.log` (root) and `iadmin/errors.log`
- No structured/contextual logging in custom code
**Patterns:**
- PrestaShop core `PrestaShopLogger::addLog()` — used in some modules
- Custom code prefers `error_log()` or no logging
## Comments
**When to Comment:**
- PHPDoc blocks above public methods (recommended)
- Inline `//` for non-obvious business logic
**PHPDoc style (used in custom module):**
```php
/**
* Builds presented products list from accessories of products currently in cart.
*
* @return array
*/
protected function buildCrossSellProducts()
```
Parameter form:
```php
/**
* @param int[] $productIds
* @return array<int, bool>
*/
protected function getCombinationFlags(array $productIds)
```
Property form:
```php
/** @var int Manufacturer identifier */
public $id_manufacturer;
```
**TODO Comments:**
- Format varies (`// TODO`, `// FIXME`, `// HACK`) — found in core, rare in custom code
## Function Design
**Size:**
- Module hook methods kept short; logic delegated to private helpers (e.g. `buildCrossSellProducts()`, `presentProducts()`)
- Long legacy scripts exist (`import-product.php` 813 lines) — anti-pattern
**Parameters:**
- Hook method signatures match PrestaShop dispatcher: `hookXxx(array $params)` where `$params` carries context
## Module Design (PrestaShop-specific)
**Module class skeleton:**
- Constructor sets `$this->name`, `$this->tab`, `$this->version`, `$this->author`, `$this->bootstrap`, then `parent::__construct()`
- `install()` calls `parent::install()` and chains `$this->registerHook(...)` calls
- `uninstall()` calls `parent::uninstall()` (cleans hook table)
- Hook handlers named `hook<HookName>()`
**Template overrides:**
- Module ships defaults in `modules/<m>/views/templates/hook/`
- Theme overrides resolved at `themes/<theme>/modules/<m>/views/templates/hook/`
**Assets:**
- Registered in `hookActionFrontControllerSetMedia()` via `$this->context->controller->registerStylesheet()` / `registerJavascript()`
## Override Design
- Place in `override/classes/<ClassName>.php` or `override/classes/controller/<Name>.php`
- Extend the core class verbatim and add/override methods only
- Document the *why* of each override (currently undocumented in this project — see `concerns.md`)
---
*Convention analysis: 2026-05-10*
*Update when patterns change*