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

5.6 KiB

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):

/**
 * Builds presented products list from accessories of products currently in cart.
 *
 * @return array
 */
protected function buildCrossSellProducts()

Parameter form:

/**
 * @param int[] $productIds
 * @return array<int, bool>
 */
protected function getCombinationFlags(array $productIds)

Property form:

/** @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