Architecture

Naming Conventions

Laravel

What How Good Bad
Blade kebab-case partials.top-header @include('top_header')
Collections Plural, camelCase activeUsers active_users
Commands kebab-case send-email SendEmail
Config snake_case google_calendar.php google-calendar.php
Controllers Singular UserController UsersController
Functions snake_case get_user getUser
Methods camelCase getUsers get_users
Models Singular User Users
Route Names dot notation tickets.show tickets-show
Routes Plural articles/1 article/1
Tables Plural users user
URLs kebab-case /about-us /about_us
Variables camelCase userName $user_name
Views kebab-case show-user.blade.php show_user.blade.php

Classes

Models

  • PascalCase, singular form
  • Prefix related models with parent name
// Good
class User extends Model
class Ticket extends Model
class MashCategory extends Model
class MashItem extends Model
class ExerciseVideo extends Model

// Bad
class Users extends Model          // Plural
class mash_category extends Model  // snake_case

Actions

  • PascalCase, verb-first naming
  • Describe the action being performed
// Good
class CreateTicket
class UpdateItem
class DeleteUser
class ConvertKilogramsToPounds
class GetAllActiveRepeatingReminders
class BuildUserSettingDefaults

// Bad
class TicketCreator        // Noun instead of verb
class HandleTicket         // Too vague

Data Transfer Objects (DTOs)

  • PascalCase, suffixed with Data
// Good
class TicketData extends Data
class StoreData extends Data
class PlanData extends Data

// Bad
class TicketDTO extends Data       // Use Data suffix
class Ticket extends Data          // Conflicts with model

Enums

  • PascalCase, singular
  • Values in PascalCase or UPPER_SNAKE_CASE
// Good
enum Status: int
{
    case Pending = 0;
    case Active = 1;
    case Completed = 2;
}

enum WeightTypes: string
{
    case Kilograms = 'kg';
    case Pounds = 'lbs';
}

Traits

  • PascalCase, prefixed with Has or descriptive verb
// Good
trait HasHashIds
trait HasActiveInactive
trait HasSlug
trait HasTags

// Bad
trait HashIdsTrait         // Suffix instead of prefix
trait Active               // Not descriptive

Livewire Components

  • PascalCase, descriptive of the view/feature
// Good
class Dashboard extends Component
class Login extends Component
class TicketList extends Component
class LoginForm extends Form

// Bad
class DashboardComponent   // Redundant suffix

Methods

General Methods

  • camelCase
  • Verb-first for actions
// Good
public function execute(TicketData $data): Ticket
public function authenticate(): void
public function generateSlug(): string

// Bad
public function Execute()          // PascalCase
public function ticket_create()    // snake_case

Query Scopes

  • camelCase, prefixed with scope
  • Descriptive of the filter
// Good
public function scopeActive(Builder $query): Builder
public function scopeDueThisWeek(Builder $query): Builder
public function scopeForUser(Builder $query, User $user): Builder

// Bad
public function scopeGetActive()   // Redundant "Get"
public function active()           // Missing scope prefix

Relationship Methods

  • camelCase
  • Singular for belongsTo/hasOne, plural for hasMany
// Good
public function user(): BelongsTo
public function category(): BelongsTo
public function items(): HasMany
public function tickets(): HasMany

// Bad
public function getUser()          // Redundant prefix
public function item(): HasMany    // Singular for hasMany

Protected/Private Helpers

  • camelCase, descriptive names
// Good
protected function ensureIsNotRateLimited(): void
protected function throttleKey(): string
private function calculateTotal(): float

// Bad
protected function helper()        // Not descriptive
private function _doSomething()    // Underscore prefix

Properties

Class Properties

  • camelCase for PHP properties
  • Type hints always present
// Good
public string $email = '';
public bool $rememberMe = false;
private int $maxAttempts = 5;

// Bad
public $email;                     // Missing type hint
public string $Email;              // PascalCase

Database Properties

  • snake_case for database-related
// Good
protected $guarded = ['id'];
protected $casts = [
    'is_active' => 'boolean',
    'due_at' => 'datetime',
];

// Bad
protected $Guarded = ['id'];       // PascalCase

Database

Tables

  • snake_case, plural
// Good
users
tickets
mash_items
mash_categories
exercise_videos

// Bad
User                               // PascalCase, singular
MashItems                          // PascalCase

Columns

  • snake_case
  • Boolean: prefix with is_ or has_
  • Foreign keys: {model}_id
  • Timestamps: _at suffix
// Good
id
hash_id
user_id
category_id
is_active
has_subscription
created_at
due_at
next_reminder_at

// Bad
userId                             // camelCase
isActive                           // camelCase
active                             // Missing is_ prefix
createdAt                          // camelCase

Indexes

  • Named based on columns
// Good
$table->index(['user_id', 'is_active']);
$table->unique(['name', 'user_id']);

// Bad
$table->index(['user_id', 'is_active'], 'idx1');  // Non-descriptive name

Files

PHP Files

  • Match class name exactly
  • One class per file
// Good
CreateTicket.php      → class CreateTicket
TicketData.php        → class TicketData
HasHashIds.php        → trait HasHashIds

// Bad
create-ticket.php     // kebab-case
ticketData.php        // camelCase

Blade Views

  • kebab-case
// Good
resources/views/dashboard.blade.php
resources/views/components/primary-button.blade.php
resources/views/livewire/ticket-list.blade.php

// Bad
resources/views/Dashboard.blade.php
resources/views/components/primaryButton.blade.php

Migration Files

  • Laravel default format: {timestamp}_create_{table}_table.php
// Good
2024_01_15_000000_create_users_table.php
2024_01_15_000001_create_tickets_table.php
2024_01_16_000000_add_status_to_tickets_table.php

Routes

Route Names

  • snake_case or dot notation for resources
// Good
Route::get('/dashboard')->name('dashboard');
Route::get('/tickets')->name('tickets.index');
Route::post('/tickets')->name('tickets.store');

// Bad
Route::get('/dashboard')->name('Dashboard');
Route::get('/tickets')->name('ticketsList');

Translations

Translation Parameters

  • camelCase for parameter names
// Good
{{ __('orders.total', ['itemCount' => $count, 'totalPrice' => $total]) }}
{{ __('users.greeting', ['userName' => $user->name]) }}

// Bad
{{ __('orders.total', ['item_count' => $count, 'total_price' => $total]) }}