# Coding Conventions **Analysis Date:** 2026-02-04 **Reference:** This document captures WinterCMS/Laravel PHP conventions that should guide the Scala rewrite. As SummerCMS is a greenfield Scala project, these patterns should be adapted to Scala idioms while maintaining architectural consistency. ## Naming Patterns **Files:** - **Classes:** PascalCase, one class per file (e.g., `User.php`, `AuthManager.php`, `FormController.php`) - **Models:** Singular PascalCase (e.g., `User`, `UserRole`, `UserGroup` in `modules/backend/models/`) - **Controllers:** Plural PascalCase with "Controller" suffix (e.g., `Users.php`, `AccessLogs.php` in `modules/backend/controllers/`) - **Namespaces:** Correspond to directory structure with backslash path separators **Functions/Methods:** - camelCase (e.g., `getFullNameAttribute()`, `sendInvitation()`, `getPersistCode()`) - Helper methods in models use verb prefixes: `get*`, `set*`, `is*`, `has*` (e.g., `getAvatarThumb()`, `isSuperUser()`) - Event hooks use specific naming: `afterCreate()`, `afterLogin()`, `afterUpdate()` (see `modules/backend/models/User.php` lines 129-158) - Private methods are lowercase camelCase **Variables:** - camelCase for all variable names (e.g., `$persist_code`, `$send_invite`, `$full_name`) - Snake_case for database column names mapped to model attributes - Configuration array keys use lowercase dot notation (e.g., `'cms.pluginsPath'`, `'database.default'`) **Types/Classes:** - Model classes: Base classes in `modules/*/models/` (e.g., `Backend\Models\User` extends `Winter\Storm\Auth\Models\User as UserBase`) - Controller classes: `Backend\Controllers\Users` implements behaviors - Use fully qualified namespaced class names in type declarations **Constants:** - UPPER_SNAKE_CASE for constants (convention follows Laravel) ## Code Style **Formatting:** - EditorConfig enforced via `.editorconfig` at repository root: - End of line: LF - Charset: UTF-8 - Indent: 4 spaces - Trim trailing whitespace: enabled - Insert final newline: enabled - Workflow files (`.github/workflows/`): 2-space indent **Spacing:** - Opening braces on same line (e.g., `public function getData() {`) - Closing braces on new line - Method declarations with full type hints and documentation (see `modules/backend/models/User.php` lines 78-98) **Linting:** - Tool: PHP CodeSniffer (squizlabs/php_codesniffer) via composer script - Command: `composer sniff` - Checks PSR-1, PSR-2, PSR-4 standards - Command: `composer lint` - Parallel lint checking with php-parallel-lint - Excludes: vendor/, storage/, specific test fixtures **Documentation:** - PSDoc style comments on all public methods with `@param`, `@return`, `@var` annotations - Class-level doc blocks include package and author info: ```php /** * Administrator user model * * @package winter\wn-backend-module * @author Alexey Bobkov, Samuel Georges */ ``` - Inline comments explain non-obvious logic (see `modules/backend/models/User.php` lines 89-95 option explanation) ## Import Organization **Order (per file):** 1. PHP namespace declaration (no blank line) 2. Use statements grouped: - Facades first (e.g., `use Backend\Facades\Backend;`) - Models next (e.g., `use Backend\Models\UserGroup;`) - Classes and utilities (e.g., `use Winter\Storm\Database\Traits\SoftDelete;`) 3. Blank line before class declaration **Example** (`modules/backend/models/User.php` lines 1-15): ```php 'required|between:6,255|email|unique:backend_users', 'login' => 'required|between:2,255|unique:backend_users', 'password' => 'required:create|min:4|confirmed', ]; ``` ## Logging **Framework:** Laravel native logging (via `Illuminate\Support\Facades\Log` or helpers) **Patterns:** - No explicit logging calls in examined source files - Framework routes all errors through Laravel's error handler - Debug mode toggled via `.env` `APP_DEBUG` setting (defaults to true in config but should be false in production) - Log configuration in `config/logging.php` **Observability:** - Model lifecycle events fired via `Event::fire()` for observation/extension: ```php Event::fire('backend.user.login', [$this]); ``` ## Comments **When to Comment:** - Explain "why", not "what" (code explains what it does) - Document non-obvious algorithms or workarounds - Mark uncertain logic with `@todo`, `@TODO` (seen throughout codebase) **Comment Styles:** - Single-line: `// Comment` - Multi-line: Block with `/** ... */` for docblocks only - Inline: After code with `// Comment` **JSDoc/TSDoc:** - PHP style with `@param`, `@return`, `@var`, `@throws` tags - Event documentation uses `@event` tag with example usage (see `modules/backend/models/User.php` lines 147-158) - Database column documentation via `@var` on property declarations ## Function Design **Size:** - Methods generally 10-40 lines (see examples in User model) - Extracted helper methods for reusable logic - Model lifecycle hooks are concise (afterCreate, afterLogin, etc.) **Parameters:** - Type-hinted where applicable - Favor explicit parameters over options arrays - Options arrays used for backward compatibility (e.g., `getAvatarThumb($size = 25, $options = null)`) **Return Values:** - Explicit return statements - Type hints on return values in docblocks (though PHP 7.4+ allows native return types) - Null returns used for "not found" cases ## Module Design **Exports:** - Classes explicitly imported via use statements - No wildcard imports (`use Namespace\*;`) - All public classes are explicitly declared **Barrel Files:** - No barrel/index files observed in WinterCMS - Direct class imports required **Class Properties:** - Public properties for model relations and validation rules: ```php public $belongsToMany = [...]; public $belongsTo = [...]; public $rules = [...]; public $implement = [...]; // In controllers ``` - Protected properties for internal state (e.g., `protected $table`, `protected $dates`) - Magic properties documented via `@var` doc comments **Traits:** - Used for cross-cutting concerns (e.g., `SoftDelete`, `UploadableWidget`) - Applied within class body via `use` statement - Traits encapsulate reusable behavior patterns ## Event System **Framework:** Laravel Event system with plugin extension points **Patterns:** - Events fired at significant lifecycle points (e.g., `backend.user.login`) - Listeners registered via `Event::listen()` in plugin service providers - Event documentation includes example listener code - Used for non-breaking extensibility across plugins ## Model Extension Pattern **Dynamic Extension:** - Models extended via `extend()` method in plugin registration: ```php User::extend(function ($model) { $model->hasMany['payments'] = [PaymentModel::class, 'key' => 'user_id']; }); ``` - Allows plugins to add relations, validation, behaviors without modifying core models ## Translation/Localization **Framework:** Winter's translation system **Pattern:** - Backend labels use plugin namespace: `'plugin.namespace::lang.section.key'` - Translation filter in views: `{{ 'String'|_ }}` - Used for all user-facing strings (labels, help text, messages) --- *Convention analysis: 2026-02-04* *Reference: WinterCMS PHP codebase patterns to inform Scala rewrite*