189 lines
7.9 KiB
Markdown
189 lines
7.9 KiB
Markdown
# Coding Conventions
|
|
|
|
**Analysis Date:** 2026-05-20
|
|
|
|
## Naming Conventions
|
|
|
|
**Files:**
|
|
- Controllers: PascalCase (e.g., `SirenController.php`, `AdminController.php`, `MapController.php`)
|
|
- **Exception:** `cctvController.php` uses lowercase — inconsistent with project convention
|
|
- Models: PascalCase singular (e.g., `User.php`)
|
|
- Exports: PascalCase (e.g., `WaterLevelExport.php`, `HourlyRainfallExport.php`)
|
|
- Notifications: PascalCase (e.g., `ResetPasswordNotification.php`)
|
|
- Services: PascalCase (e.g., `FcmService.php`)
|
|
- Middleware: PascalCase (e.g., `AdminMiddleware.php`, `LocalizationMiddleware.php`)
|
|
- Form Requests: PascalCase (e.g., `ProfileUpdateRequest.php`, `LoginRequest.php`)
|
|
- Migrations: `YYYY_MM_DD_HHMMSS_description_snake_case.php`
|
|
- Blade views: `snake_case` directories + `kebab-case` or `snake_case` files (e.g., `layout/notification/rainfall.blade.php`)
|
|
- JavaScript: `camelCase.js` (e.g., `homemap.js`, `graph.js`, `rfhistory.js`)
|
|
|
|
**Classes:**
|
|
- PascalCase for all classes, following PSR-4 autoloading
|
|
- Controllers suffixed with `Controller` (e.g., `RainfallController`)
|
|
- Exports suffixed with `Export` (e.g., `HourlyRainfallExport`)
|
|
|
|
**Methods:**
|
|
- camelCase (e.g., `stationDisplay()`, `rainfallSum()`, `exportHistoricalWl()`)
|
|
- **Exception:** `SirenHistory()` uses PascalCase — inconsistent
|
|
- Public methods in controllers follow action naming: `index()`, `store()`, `update()`, `destroy()`, `edit()`
|
|
|
|
**Variables:**
|
|
- camelCase for local variables (e.g., `$stationFilter`, `$rainfallData`, `$displayDate`)
|
|
- camelCase for class properties (e.g., `$stationid`, `$startDate` in Export classes)
|
|
- `$stationid` used as one word (not `$stationId`) — project-specific convention
|
|
|
|
**Database Tables:**
|
|
- snake_case lowercase singular (e.g., `station`, `rainfall`, `waterlevel`, `siren`, `notification`, `users`)
|
|
- `users` is the only plural table name
|
|
|
|
**Columns:**
|
|
- snake_case lowercase (e.g., `stationid`, `active_time`, `access_level`, `login_attempts`, `is_blocked`, `cctv_link`)
|
|
- No consistent convention: some use compound words without underscore (e.g., `stationid`, `waterlevel`)
|
|
|
|
## Code Style
|
|
|
|
**Formatting:**
|
|
- `.editorconfig` present at both project root and `src/`
|
|
- Indent: 4 spaces (no tabs, except Makefiles)
|
|
- Charset: UTF-8
|
|
- End of line: LF
|
|
- Trailing whitespace trimmed (except `.md` files)
|
|
- YAML files: 2-space indent
|
|
- No ESLint or Prettier configured for JavaScript
|
|
|
|
**Linting:**
|
|
- `laravel/pint` installed as dev dependency (PHP code style fixer)
|
|
- No evidence of a `pint.json` configuration file — using defaults
|
|
- No frontend linting tools configured
|
|
|
|
**Bracket Style:**
|
|
- Opening braces on same line for classes and methods
|
|
- Control structures: opening brace on same line (K&R style)
|
|
- Multi-line function calls and arrays: trailing comma not consistently used
|
|
|
|
**Import/Use Statement Organization:**
|
|
- Laravel framework imports first
|
|
- Then third-party packages (e.g., `Carbon`, `Maatwebsite\Excel`, `DomPDF`)
|
|
- Then application imports (e.g., `App\Models\User`, `App\Services\FcmService`)
|
|
- Blank line between groups is not consistently applied
|
|
- Example from `WaterLevelController.php`:
|
|
```php
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Carbon\Carbon;
|
|
// Add this for Export data to excel
|
|
use App\Exports\WaterLevelExport;
|
|
use Maatwebsite\Excel\Facades\Excel;
|
|
```
|
|
|
|
**Docblock Usage:**
|
|
- PHPDoc blocks present on model properties (`$fillable`, `$hidden`, `casts()`)
|
|
- Docblocks on factory methods and notification methods (Breeze scaffolded)
|
|
- Custom controllers use inline `//` comments extensively rather than docblocks
|
|
- Comment style in controllers follows a pattern:
|
|
```php
|
|
// Function Retrieve Current Water Level Data
|
|
public function index(Request $request)
|
|
```
|
|
- Each SQL query is annotated with block comments:
|
|
```php
|
|
// TABLE : STATION JOIN TABLE WATERLEVEL
|
|
// COLUMN : name,datetime,waterlevel
|
|
// INPUT : $stationCondition from resources/views/...
|
|
// OUTPUT : resources/views/layout/waterlevel.blade.php
|
|
```
|
|
|
|
## File Organization
|
|
|
|
**How files are grouped:**
|
|
- Controllers grouped by domain in flat structure under `app/Http/Controllers/`
|
|
- API controllers in `app/Http/Controllers/Api/` subdirectory
|
|
- Auth controllers in `app/Http/Controllers/Auth/` subdirectory (Breeze scaffolded)
|
|
- Exports in `app/Exports/`
|
|
- Services in `app/Services/`
|
|
- Notifications in `app/Notifications/`
|
|
- Views follow a `layout.{domain}` naming pattern (e.g., `layout.rainfall`, `layout.admin.stationmgmt`)
|
|
|
|
**One class per file:**
|
|
- Adhered to throughout — one class per file
|
|
|
|
**Directory naming:**
|
|
- All lowercase directories (e.g., `Controllers/`, `Models/`, `Services/`, `Exports/`)
|
|
- Views use nested lowercase directories (e.g., `layout/notification/history/`)
|
|
|
|
## Git Conventions
|
|
|
|
**Branch naming:**
|
|
- Only 2 commits in the repository — no discernible branch naming convention
|
|
|
|
**Commit message patterns:**
|
|
- Observed messages:
|
|
- `first commit`
|
|
- `fix: configuration docker-compose.yml`
|
|
- The second commit suggests a possible `type: description` convention (fix:, feat:, etc.)
|
|
|
|
## Laravel-Specific Patterns
|
|
|
|
**Eloquent Model Patterns:**
|
|
- Only `User.php` exists as an Eloquent model (`app/Models/User.php`)
|
|
- `HasFactory` and `Notifiable` traits used on User
|
|
- `$fillable` array for mass assignment (not `$guarded`)
|
|
- `casts()` method (Laravel 12 style) instead of `$casts` property
|
|
- Custom notification override: `sendPasswordResetNotification()`
|
|
|
|
**Controller Patterns:**
|
|
- **Not resource controllers** — methods are custom-named (e.g., `stationDisplay()`, `userDisplay()`, `storeStation()`)
|
|
- Heavy use of raw SQL via `DB::select()` and `DB::table()` instead of Eloquent ORM
|
|
- `collect(DB::select(...))` pattern to wrap raw SQL results into collections
|
|
- Controller validation done inline with `$request->validate()` — not consistently using Form Requests
|
|
- Redirect pattern: `redirect()->back()->with('success', __('toast.key'))`
|
|
- View compact pattern: `return view('blade.path', compact('var1', 'var2'))`
|
|
|
|
**Form Request Usage:**
|
|
- `ProfileUpdateRequest` for profile updates (`app/Http/Requests/ProfileUpdateRequest.php`)
|
|
- `LoginRequest` for authentication (`app/Http/Requests/Auth/LoginRequest.php`)
|
|
- Admin controller does inline `$request->validate()` instead of Form Requests
|
|
- **Inconsistent:** Form Requests exist but most validation is inline
|
|
|
|
**Resource/API Resource Usage:**
|
|
- Not used — API responses use `response()->json($data)` directly
|
|
- No API Resource classes defined
|
|
|
|
**Policy Usage:**
|
|
- Not used — authorization handled via custom `AdminMiddleware` checking `access_level`
|
|
- `app/Http/Middleware/AdminMiddleware.php` checks `Auth::user()->access_level !== 1`
|
|
|
|
**Event/Listener Patterns:**
|
|
- Not used — no events or listeners defined
|
|
- Notification push (FCM) is called directly from API controller
|
|
|
|
**Route Patterns:**
|
|
- Named routes used consistently: `->name('rainfall')`, `->name('stationmanagement.store')`
|
|
- Route grouping by middleware: `Route::middleware('auth')`, `Route::middleware(['admin'])`
|
|
- Admin routes use POST for updates (not PUT/PATCH) — non-RESTful
|
|
- API routes in `routes/api.php` with no auth middleware
|
|
|
|
**Localization:**
|
|
- Bilingual: English (`en`) and Bahasa Malaysia (`bm`) in `resources/lang/`
|
|
- `LocalizationMiddleware` sets locale via session
|
|
- `__('key')` helper used for translations in views and controllers
|
|
|
|
**Middleware:**
|
|
- Custom middleware registered in `bootstrap/app.php`
|
|
- `AdminMiddleware` for admin-only routes
|
|
- `LocalizationMiddleware` for language switching
|
|
|
|
**Export Pattern (Maatwebsite Excel):**
|
|
- Export classes implement `FromCollection`, `WithHeadings`, `ShouldAutoSize`
|
|
- Constructor injection for filter parameters
|
|
- Raw SQL queries in `collection()` method
|
|
- `headings()` method returns array of column names
|
|
|
|
**PDF Export Pattern (DomPDF):**
|
|
- `Pdf::loadView('blade.path', compact('data'))->setPaper('a4','potrait')`
|
|
- Note: `'potrait'` is a typo — should be `'portrait'` (present in multiple files)
|
|
|
|
---
|
|
|
|
*Convention analysis: 2026-05-20*
|