8.2 KiB
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,UserGroupinmodules/backend/models/) - Controllers: Plural PascalCase with "Controller" suffix (e.g.,
Users.php,AccessLogs.phpinmodules/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()(seemodules/backend/models/User.phplines 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\UserextendsWinter\Storm\Auth\Models\User as UserBase) - Controller classes:
Backend\Controllers\Usersimplements 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
.editorconfigat 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.phplines 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,@varannotations - Class-level doc blocks include package and author info:
/** * Administrator user model * * @package winter\wn-backend-module * @author Alexey Bobkov, Samuel Georges */ - Inline comments explain non-obvious logic (see
modules/backend/models/User.phplines 89-95 option explanation)
Import Organization
Order (per file):
- PHP namespace declaration (no blank line)
- 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;)
- Facades first (e.g.,
- Blank line before class declaration
Example (modules/backend/models/User.php lines 1-15):
<?php namespace Backend\Models;
use Backend\Facades\Backend;
use Backend\Facades\BackendAuth;
use Illuminate\Support\Facades\Event;
use Winter\Storm\Auth\Models\User as UserBase;
use Winter\Storm\Support\Facades\Mail;
/**
* Administrator user model
* ...
*/
class User extends UserBase
Path Aliases:
- No import aliases in WinterCMS codebase - full namespace paths are used
- Traits are explicitly used via
usekeyword within class body (e.g.,use \Winter\Storm\Database\Traits\SoftDelete;)
Error Handling
Patterns:
- No explicit try-catch in models/controllers; exceptions bubble to framework handlers
- Validation errors handled via model
$rulesproperty (e.g.,modules/backend/models/User.phplines 27-32) - Framework handles model validation failures and redirects with flash messages
- Exception types:
Winter\Storm\Exception\SystemExceptionused for framework-level errors (seen in tests)
Validation:
- Model rules defined in
public $rulesarray with pipe-separated validators:public $rules = [ 'email' => '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
.envAPP_DEBUGsetting (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: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,@throwstags - Event documentation uses
@eventtag with example usage (seemodules/backend/models/User.phplines 147-158) - Database column documentation via
@varon 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:
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
@vardoc comments
Traits:
- Used for cross-cutting concerns (e.g.,
SoftDelete,UploadableWidget) - Applied within class body via
usestatement - 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: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