# Coding Conventions > Generated: 2026-04-26 ## File Naming | Layer | Convention | Example | |-------|-----------|---------| | Legacy (admin/front) | `class.{ClassName}.php` | `class.Articles.php` | | Domain repositories | `{ClassName}.php` (PSR-4) | `ArticlesRepository.php` | | Shared services | `{ClassName}.php` (PSR-4) | `CacheHandler.php` | | Templates | `{feature-name}.php` | `articles/list.php` | ## Naming Conventions | Element | Legacy code | New Domain code | |---------|------------|-----------------| | Methods | `snake_case` | `camelCase` | | Classes | `PascalCase` | `PascalCase` | | Properties | `$camelCase` | `$camelCase` | | Constants | `UPPER_CASE` | `UPPER_CASE` | | Namespaces | lowercase (`admin\`, `front\`) | PascalCase (`Domain\`, `Shared\`) | ## Class Patterns ### Controls (request handlers) — static methods only ```php namespace admin\controls; class Articles { public static function article_delete() { global $user; if (!admin\factory\Users::check_privileges('articles', $user['id'])) return \S::alert('Brak uprawnień'); admin\factory\Articles::article_delete(\S::get('article_id')); } } ``` ### Factories — @deprecated wrappers, static methods, delegate to repo ```php namespace admin\factory; /** @deprecated Wrapper — używaj \Domain\Articles\ArticlesRepository przez DI */ class Articles { private static function repo(): \Domain\Articles\ArticlesRepository { global $mdb; return new \Domain\Articles\ArticlesRepository($mdb); } public static function article_delete($id): bool { return self::repo()->deleteArticle((int)$id); } } ``` ### Domain Repositories — constructor DI, camelCase, typed returns ```php namespace Domain\Articles; class ArticlesRepository { private $db; public function __construct($db) { $this->db = $db; } // ------------------------------------------------------------------------- // Odczyt (Read) // ------------------------------------------------------------------------- public function find(int $id): ?array { return $this->db->get('pp_articles', '*', ['id' => $id]) ?: null; } // ------------------------------------------------------------------------- // Zapis / usuwanie (Write / Delete) // ------------------------------------------------------------------------- public function deleteArticle(int $id): bool { $this->db->delete('pp_articles', ['id' => $id]); return true; } } ``` ### View classes — static rendering ```php namespace admin\view; class Articles { public static function list($articles) { $tpl = new \Tpl; $tpl->articles = $articles; return $tpl->render('articles/list'); } } ``` ## PHPDoc Style Polish-language descriptions are standard in this project: ```php /** * Prosta lista autorów * @return array|bool */ public function authorsList() { ... } /** * Zapis autora (insert lub update) * @param int $authorId * @param string $author * @return object|bool */ public function authorSave(int $authorId, string $author) { ... } ``` Section separators in larger classes: ```php // ------------------------------------------------------------------------- // Odczyt (Read operations) // ------------------------------------------------------------------------- ``` ## Return Patterns | Pattern | Usage | |---------|-------| | `?array` | Single record lookup (null = not found) | | `array` (possibly `[]`) | List queries — `?: []` fallback | | `bool` | Write/delete operations | | `int` | Codes: `1 = OK`, `0 = bad credentials`, `-1 = blocked` | | `void` | Side-effect-only writes | | `['status' => 'ok'/'error', 'msg' => '...']` | AJAX JSON responses | ## Error Handling - Repositories return `null`/`false`/`[]` for "not found", don't throw - `ImageManipulator` uses typed exceptions (`\InvalidArgumentException`, `\RuntimeException`) - AJAX endpoints: `json_encode(['status' => 'ok/error', 'msg' => '...'])` - Error suppression with `@` is used in legacy code (avoid in new code) ## Database Access via Medoo Always use parameterized Medoo methods — never string concatenation with string values: ```php // Good $this->db->get('pp_articles', '*', ['id' => $id]); $this->db->select('pp_articles', '*', ['ORDER' => ['created' => 'DESC']]); $this->db->update('pp_articles', ['status' => 1], ['id' => $id]); $this->db->insert('pp_articles', ['title' => $title, 'slug' => $slug]); // Acceptable (integer cast only) $this->db->query("SELECT ... WHERE id = " . (int)$id)->fetchAll(); // Never $this->db->query("SELECT ... WHERE slug = '" . $slug . "'"); // SQL injection risk ``` ## Global Helper Facade (`\S::`) Legacy code uses `\S::method()` — new code should use `\Shared\Helpers\Helpers::method()` directly or inject the dependency. Migrate `\S::` calls opportunistically but don't block on it. ## Template Rendering ```php $tpl = new \Tpl; // or: new \Shared\Tpl\Tpl $tpl->variable = $value; // assign template variables return $tpl->render('module/template-name'); // checks templates_user/ first, then templates/ ```