Mastering the Single Responsibility Principle in Laravel: Best Practices & Real-World Use Cases

#Laravel #SRP #laravel architecture

3 min read.

Mastering the Single Responsibility Principle in Laravel: Best Practices & Real-World Use Cases
Hamdaoui Wassim Avatar

Hamdaoui Wassim

1
0

As your Laravel project grows, managing and scaling code can become challenging. One of the most effective ways to keep your codebase clean, testable, and maintainable is to apply SOLID principles, starting with the Single Responsibility Principle (SRP).

In this article, we'll explain what SRP is, why it matters in Laravel, how to apply it effectively, and walk through a practical use case with clean architecture.

What is the Single Responsibility Principle?

Definition: A class should have only one reason to change, meaning it should only have one job or responsibility.

This principle is the "S" in SOLID, a foundational concept in object-oriented programming and clean architecture.

 

The Problem with Violating SRP :

A typical violation in Laravel might look like this:

<?php

class OrderController extends Controller
{
    public function store(Request $request)
    {
        $validated = $request->validate([...]);
        $order = Order::create($validated);
        Mail::to($order->user)->send(new OrderCreated($order));
        Log::info('Order created', $order->toArray());
    }
}
?>

Issues:

  • Validation

  • Business logic (creating the order)

  • Sending emails

  • Logging

All jammed into one controller method — violating SRP and making the code hard to test and maintain.

SRP Done Right in Laravel :

Let’s refactor the above example using SRP-friendly architecture.

Step 1: Form Request for Validation

php artisan make:request StoreOrderRequest
<?php
class StoreOrderRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'product_id' => ['required', 'exists:products,id'],
            'quantity' => ['required', 'integer', 'min:1'],
        ];
    }
}

?>

Step 2: Use a Service Class for Business Logic :

php artisan make:service OrderService
<?php
class OrderService
{
    public function createOrder(array $data): Order
    {
        $order = Order::create($data);

        event(new OrderCreated($order));

        return $order;
    }
}

?>

Step 3: Use Events to Decouple Side Effects :

php artisan make:event OrderCreated
php artisan make:listener SendOrderEmail
<?php
// In EventServiceProvider
protected $listen = [
    OrderCreated::class => [
        SendOrderEmail::class,
    ],
];

?>

Step 4: Simplify Controller :

<?php

class OrderController extends Controller
{
    public function store(StoreOrderRequest $request, OrderService $service)
    {
        $order = $service->createOrder($request->validated());

        return response()->json(['message' => 'Order placed successfully', 'order' => $order]);
    }
}


?>

Benefits of Applying SRP in Laravel :

Benefit Description
Testability Each class is easier to unit test in isolation
Reusability Logic can be reused in other parts (e.g., CLI, Jobs)
Maintainability Smaller classes are easier to change and refactor
Scalability

Clear separation of concerns supports growing features

Best Practices for SRP in Laravel :

 

Practice Tool
Use Form Requests For input validation
Use Service Classes For core business logic
Use Repositories For database interactions (optional)
Use Events & Listeners

For side effects like notifications, logs

Keep Controllers Thin

Delegate logic to dedicated services

Real-World Use Case: User Registration :

<?php

// Doing everything in a controller

?>

Split into:

  • RegisterUserRequest – for validation

  • UserService::register() – handles user creation

  • Registered event – for sending welcome email

  • SendWelcomeEmail listener

This makes your app clean, easy to test, and future-proof.

Conclusion :

The Single Responsibility Principle is not just a theoretical idea — it’s a powerful guideline for writing better Laravel applications. By giving each class one job, you gain clarity, flexibility, and long-term maintainability.

"Fat controllers and models are a sign of SRP violations — break them up before they break your app."

0 Comments