Skip to content

Last updated:

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