Skip to content

Naming Conventions

Overview

Consistent naming conventions improve code readability, maintainability, and team collaboration. This document defines the naming standards for the Laravel backend.


General Principles

Be Descriptive and Clear

php
// Bad - Unclear abbreviations
$u = User::find(1);
$dt = now();
$arr = [];

// Good - Clear and descriptive
$user = User::find(1);
$createdDate = now();
$activeUsers = [];

Use Pronounceable Names

php
// Bad
$usrCrtDt = now();
$prdCatMgr = new ProductCategoryManager();

// Good
$userCreatedDate = now();
$productCategoryManager = new ProductCategoryManager();

Avoid Mental Mapping

php
// Bad - What does 'i' represent?
for ($i = 0; $i < count($users); $i++) {
    // ...
}

// Good - Clear iteration
foreach ($users as $user) {
    // ...
}

File Names

Controllers

Format: [Singular]Controller.php
Examples:
  UserController.php
  PostController.php
  OrderController.php
  ProductCategoryController.php

Models

Format: [Singular].php
Examples:
  User.php
  Post.php
  Order.php
  OrderItem.php
  ProductCategory.php

Migrations

Format: yyyy_mm_dd_hhiiss_[action]_[table]_table.php
Examples:
  2024_01_01_000000_create_users_table.php
  2024_01_02_120000_add_phone_to_users_table.php
  2024_01_03_153000_create_posts_table.php
  2024_01_04_090000_add_indexes_to_posts_table.php

Seeders

Format: [Table]Seeder.php or [Purpose]Seeder.php
Examples:
  DatabaseSeeder.php
  UserSeeder.php
  PostSeeder.php
  RolePermissionSeeder.php

Requests

Format: [Action][Model]Request.php
Examples:
  StoreUserRequest.php
  UpdateUserRequest.php
  DeletePostRequest.php
  PublishPostRequest.php

Resources

Format: [Model]Resource.php or [Model]Collection.php
Examples:
  UserResource.php
  UserCollection.php
  PostResource.php
  OrderResource.php

Services

Format: [Model]Service.php or [Purpose]Service.php
Examples:
  UserService.php
  OrderService.php
  PaymentService.php
  NotificationService.php

Repositories

Format: [Model]Repository.php
Examples:
  UserRepository.php
  PostRepository.php
  OrderRepository.php

Jobs

Format: [VerbPhrase].php
Examples:
  ProcessPayment.php
  SendWelcomeEmail.php
  GenerateReport.php
  SyncUserData.php
  ExportOrdersToCSV.php

Events

Format: [ModelOrSubject][PastTense].php
Examples:
  UserRegistered.php
  OrderPlaced.php
  PaymentProcessed.php
  PostPublished.php
  EmailSent.php

Listeners

Format: [VerbPhrase].php
Examples:
  SendWelcomeEmail.php
  UpdateUserStatistics.php
  NotifyAdminOfNewOrder.php
  LogUserActivity.php

Middleware

Format: [PurposeOrAction].php
Examples:
  EnsureEmailIsVerified.php
  CheckUserRole.php
  LogApiRequests.php
  CheckSubscription.php
  ValidateApiKey.php

Traits

Format: [Descriptive][Trait optional].php
Examples:
  HasUuid.php
  Searchable.php
  Sluggable.php
  Taggable.php
  HasAvatar.php

Policies

Format: [Model]Policy.php
Examples:
  UserPolicy.php
  PostPolicy.php
  OrderPolicy.php

Exceptions

Format: [Description]Exception.php
Examples:
  UserNotFoundException.php
  PaymentFailedException.php
  InvalidCredentialsException.php
  ResourceNotFoundException.php

Class Names

General Rule: PascalCase (UpperCamelCase)

php
class UserController extends Controller { }
class PaymentService { }
class OrderRepository { }
class ProcessPayment implements ShouldQueue { }

Models

php
// Singular, descriptive nouns
class User extends Model { }
class Post extends Model { }
class Order extends Model { }
class OrderItem extends Model { }
class ProductCategory extends Model { }
class BlogPost extends Model { }

// Pivot models (optional)
class PostTag extends Model { }
class UserRole extends Model { }

Controllers

php
// Singular noun + "Controller"
class UserController extends Controller { }
class PostController extends Controller { }
class OrderController extends Controller { }

// Resource controllers
class Api\V1\UserController extends Controller { }
class Admin\DashboardController extends Controller { }

// Specific purpose controllers
class Auth\LoginController extends Controller { }
class Auth\RegisterController extends Controller { }

Services

php
// Purpose + "Service"
class UserService { }
class OrderService { }
class PaymentService { }
class NotificationService { }
class EmailService { }
class ReportService { }

Repositories

php
// Model + "Repository"
class UserRepository { }
class PostRepository { }
class OrderRepository { }
class ProductRepository { }

Resources (API Transformers)

php
// Model + "Resource"
class UserResource extends JsonResource { }
class PostResource extends JsonResource { }
class OrderResource extends JsonResource { }

// Collections
class UserCollection extends ResourceCollection { }

Method Names

General Rule: camelCase

php
public function getUserById(int $id): User { }
public function createNewPost(array $data): Post { }
public function updateOrderStatus(Order $order, string $status): void { }

CRUD Operations

php
// Create
public function create(array $data): Model
public function store(Request $request): Response
public function insert(array $data): bool

// Read/Retrieve
public function find(int $id): ?Model
public function get(): Collection
public function all(): Collection
public function show(Model $model): Response
public function index(): Response

// Update
public function update(Model $model, array $data): Model
public function save(Model $model): bool
public function patch(Model $model, array $data): Model

// Delete
public function delete(Model $model): bool
public function destroy(Model $model): Response
public function remove(int $id): bool
public function forceDelete(Model $model): bool

Boolean Methods

Use prefixes: is, has, can, should, will

php
// is - State check
public function isActive(): bool
public function isPublished(): bool
public function isAdmin(): bool
public function isEmpty(): bool

// has - Possession/existence
public function hasPermission(string $permission): bool
public function hasRole(string $role): bool
public function hasPosts(): bool
public function hasActiveSubscription(): bool

// can - Capability/permission
public function canEdit(): bool
public function canDelete(): bool
public function canPublish(): bool
public function canAccessResource(): bool

// should - Conditional logic
public function shouldNotify(): bool
public function shouldSendEmail(): bool
public function shouldRefresh(): bool

// will - Future action
public function willExpire(): bool
public function willAutoRenew(): bool

Action Methods

Use clear action verbs:

php
// Process/Handle
public function processPayment(array $data): PaymentResult
public function handleWebhook(Request $request): void
public function execute(): void

// Send/Notify
public function sendEmail(User $user): void
public function sendNotification(string $message): void
public function notifyUsers(Collection $users): void

// Generate/Build
public function generateReport(): Report
public function generateInvoice(Order $order): Invoice
public function buildQuery(): Builder

// Calculate/Compute
public function calculateTotal(Order $order): float
public function calculateDiscount(User $user): float
public function computeStatistics(): array

// Validate/Verify/Check
public function validateInput(array $data): bool
public function verifyEmail(string $token): bool
public function checkAvailability(): bool

// Transform/Convert
public function transformData(array $data): array
public function convertToArray(): array
public function toJson(): string

// Activate/Deactivate
public function activate(): void
public function deactivate(): void
public function enable(): void
public function disable(): void

// Approve/Reject
public function approve(): void
public function reject(string $reason): void

// Publish/Unpublish
public function publish(): void
public function unpublish(): void

// Archive/Restore
public function archive(): void
public function restore(): void

Controller Actions

php
// Standard resource methods
public function index(): Response         // List all
public function create(): Response        // Show create form
public function store(Request $request): Response    // Save new
public function show(Model $model): Response         // Display one
public function edit(Model $model): Response         // Show edit form
public function update(Request $request, Model $model): Response  // Update
public function destroy(Model $model): Response      // Delete

Scopes (Model)

php
// Prefix with "scope", use camelCase after
public function scopeActive($query)
public function scopePublished($query)
public function scopeRecent($query)
public function scopeByAuthor($query, User $author)
public function scopeWithComments($query)
public function scopePopular($query)

Variable Names

General Rule: camelCase

php
$userName = 'John Doe';
$userEmail = 'john@example.com';
$isActive = true;
$createdAt = now();
$totalAmount = 100.50;

Collections and Arrays

Use plural form:

php
// Collections
$users = User::all();
$posts = Post::where('status', 'published')->get();
$activeOrders = Order::active()->get();

// Arrays
$roles = ['admin', 'user', 'moderator'];
$permissions = ['create', 'read', 'update', 'delete'];
$errors = [];

Single Items

Use singular form:

php
$user = User::find(1);
$post = Post::first();
$order = Order::latest()->first();
$product = Product::findOrFail($id);

Boolean Variables

Use descriptive names with prefixes:

php
// is - State
$isActive = true;
$isPublished = false;
$isAdmin = $user->role === 'admin';
$isEmpty = count($items) === 0;

// has - Possession
$hasPermission = true;
$hasErrors = !empty($errors);
$hasPosts = $user->posts()->exists();

// can - Capability
$canEdit = $user->can('edit', $post);
$canDelete = false;

// should - Conditional
$shouldNotify = true;
$shouldSendEmail = $user->email_notifications;

Temporary Variables

php
// Use descriptive names even for temp variables
foreach ($users as $user) {
    foreach ($user->posts as $post) {
        // Good
        $publishedDate = $post->published_at;

        // Avoid
        $temp = $post->published_at;
    }
}

Constants

General Rule: UPPER_SNAKE_CASE

php
// Class constants
class Order
{
    const STATUS_PENDING = 'pending';
    const STATUS_PROCESSING = 'processing';
    const STATUS_COMPLETED = 'completed';
    const STATUS_CANCELLED = 'cancelled';

    const PAYMENT_METHOD_CARD = 'card';
    const PAYMENT_METHOD_CASH = 'cash';
    const PAYMENT_METHOD_TRANSFER = 'transfer';

    const MAX_ITEMS = 100;
    const DEFAULT_TAX_RATE = 0.15;
}

// Global constants (avoid if possible, use config instead)
define('APP_VERSION', '1.0.0');
define('MAX_UPLOAD_SIZE', 10240);

Configuration Keys

Use snake_case:

php
// config/app.php
return [
    'name' => env('APP_NAME', 'Laravel'),
    'env' => env('APP_ENV', 'production'),
    'debug' => env('APP_DEBUG', false),
    'url' => env('APP_URL', 'http://localhost'),
    'asset_url' => env('ASSET_URL', null),
    'timezone' => 'UTC',
    'locale' => 'en',
    'fallback_locale' => 'en',
    'max_upload_size' => 10240,
    'allowed_file_types' => ['jpg', 'png', 'pdf'],
];

Database Names

Tables

Use snake_case, plural:

users
posts
orders
order_items
product_categories
user_roles (pivot table)
post_tags (pivot table)

Columns

Use snake_case:

sql
id
name
email
email_verified_at
password
remember_token
created_at
updated_at
deleted_at

-- Multi-word columns
first_name
last_name
phone_number
birth_date
is_active
is_verified

Foreign Keys

Format: [singular_table]_id

sql
user_id
post_id
order_id
category_id
parent_id
author_id

Pivot Tables

Alphabetical order, singular, snake_case:

sql
post_tag (not tags_posts or posts_tags)
role_user (not users_roles)
category_product

Indexes

Format: [table]_[columns]_[type]

sql
-- Standard index
users_email_index
posts_created_at_index

-- Unique index
users_email_unique

-- Foreign key
posts_user_id_foreign

-- Composite
posts_user_id_created_at_index

Routes

Route Names

Use dot notation, snake_case:

php
// routes/api.php
Route::get('/users', [UserController::class, 'index'])->name('users.index');
Route::post('/users', [UserController::class, 'store'])->name('users.store');
Route::get('/users/{user}', [UserController::class, 'show'])->name('users.show');
Route::put('/users/{user}', [UserController::class, 'update'])->name('users.update');
Route::delete('/users/{user}', [UserController::class, 'destroy'])->name('users.destroy');

// Custom routes
Route::post('/users/{user}/activate', [UserController::class, 'activate'])
    ->name('users.activate');

Route::get('/posts/published', [PostController::class, 'published'])
    ->name('posts.published');

URL Paths

Use kebab-case, plural for resources:

php
/api/v1/users
/api/v1/posts
/api/v1/product-categories
/api/v1/order-items

// Actions
/api/v1/users/{user}/activate
/api/v1/posts/{post}/publish
/api/v1/orders/{order}/cancel

View/Blade Files

File Names

Use kebab-case:

user-profile.blade.php
post-list.blade.php
order-details.blade.php
email-verification.blade.php

Directories

resources/views/
  auth/
    login.blade.php
    register.blade.php
  users/
    index.blade.php
    show.blade.php
    edit.blade.php
  posts/
    index.blade.php
    show.blade.php
  emails/
    welcome.blade.php
    order-confirmation.blade.php

Namespaces

Format: Pascal Case with backslashes

php
namespace App\Http\Controllers;
namespace App\Http\Controllers\Api\V1;
namespace App\Services\User;
namespace App\Repositories;
namespace App\Models;
namespace App\Events;
namespace App\Listeners;
namespace App\Jobs;
namespace App\Mail;
namespace App\Exceptions;
namespace App\Exceptions\Domain;

Environment Variables

Format: UPPER_SNAKE_CASE

env
APP_NAME=Laravel
APP_ENV=production
APP_KEY=base64:...
APP_DEBUG=false
APP_URL=https://api.example.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=root
DB_PASSWORD=secret

CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis

MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=noreply@example.com
MAIL_FROM_NAME="${APP_NAME}"

SENTRY_LARAVEL_DSN=
STRIPE_KEY=
STRIPE_SECRET=

Enums (PHP 8.1+)

Enum Names: PascalCase

php
// app/Enums/OrderStatus.php
namespace App\Enums;

enum OrderStatus: string
{
    case PENDING = 'pending';
    case PROCESSING = 'processing';
    case SHIPPED = 'shipped';
    case DELIVERED = 'delivered';
    case CANCELLED = 'cancelled';
}

// app/Enums/UserRole.php
enum UserRole: string
{
    case ADMIN = 'admin';
    case USER = 'user';
    case MODERATOR = 'moderator';
}

// app/Enums/PaymentMethod.php
enum PaymentMethod: string
{
    case CARD = 'card';
    case CASH = 'cash';
    case BANK_TRANSFER = 'bank_transfer';
}

Test Names

Test Classes

Format: [ClassName]Test.php

php
// tests/Unit/UserServiceTest.php
class UserServiceTest extends TestCase { }

// tests/Feature/UserControllerTest.php
class UserControllerTest extends TestCase { }

// tests/Feature/Api/V1/PostTest.php
class PostTest extends TestCase { }

Test Methods

Format: test_[what_it_does]

php
public function test_user_can_be_created()
public function test_user_email_must_be_unique()
public function test_user_can_update_profile()
public function test_user_cannot_delete_other_users()
public function test_returns_404_when_user_not_found()
public function test_validates_required_fields()

Summary Table

ElementConventionExample
ClassesPascalCaseUserController, OrderService
MethodscamelCasegetUserById, createOrder
VariablescamelCase$userName, $isActive
ConstantsUPPER_SNAKE_CASEMAX_ATTEMPTS, STATUS_ACTIVE
Tablessnake_case, pluralusers, order_items
Columnssnake_casecreated_at, first_name
Routes (names)dot.snake_caseusers.index, posts.show
URLskebab-case/product-categories, /order-items
FilesPascalCase.phpUserController.php, User.php
Blade fileskebab-caseuser-profile.blade.php
Env variablesUPPER_SNAKE_CASEAPP_NAME, DB_HOST
Config keyssnake_caseapp.name, database.default
NamespacesPascalCase\With\BackslashApp\Http\Controllers

CPR - Clinical Patient Records