DEV Community

Cover image for How to Use Repository and Service Pattern in Laravel
Azmol Hossain
Azmol Hossain

Posted on

How to Use Repository and Service Pattern in Laravel

The Repository and Service Pattern is a powerful way to structure your Laravel applications. It promotes clean, maintainable, and testable code by separating concerns and decoupling your application logic. In this guide, we’ll walk through how to implement this pattern in Laravel with a simple CRUD example for managing products.

Step 1: Create Repository Interface

The first step is to define an interface for the repository. This ensures that the repository adheres to a contract, making it easier to swap implementations later.

Create the file app/Repositories/Interfaces/ProductRepositoryInterface.php:

namespace App\Repositories\Interfaces;

interface ProductRepositoryInterface
{
    public function getAll();
    public function findById($id);
    public function create(array $data);
    public function update($id, array $data);
    public function delete($id);
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Create Repository Implementation

Next, implement the repository interface. This class will handle all database interactions for the Product model.

Create the file app/Repositories/ProductRepository.php:

namespace App\Repositories;

use App\Models\Product;
use App\Repositories\Interfaces\ProductRepositoryInterface;

class ProductRepository implements ProductRepositoryInterface
{
    public function getAll()
    {
        return Product::all();
    }

    public function findById($id)
    {
        return Product::findOrFail($id);
    }

    public function create(array $data)
    {
        return Product::create($data);
    }

    public function update($id, array $data)
    {
        $product = Product::findOrFail($id);
        $product->update($data);
        return $product;
    }

    public function delete($id)
    {
        return Product::destroy($id);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Create Service Interface

The service layer acts as an intermediary between the controller and the repository. It contains the business logic of your application.

Create the file app/Services/Interfaces/ProductServiceInterface.php:

namespace App\Services\Interfaces;

interface ProductServiceInterface
{
    public function getAllProducts();
    public function getProductById($id);
    public function createProduct(array $data);
    public function updateProduct($id, array $data);
    public function deleteProduct($id);
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Create Service Implementation

Now, implement the service interface. This class will use the repository to perform operations.

Create the file app/Services/ProductService.php:

namespace App\Services;

use App\Repositories\Interfaces\ProductRepositoryInterface;
use App\Services\Interfaces\ProductServiceInterface;

class ProductService implements ProductServiceInterface
{
    protected $productRepository;

    public function __construct(ProductRepositoryInterface $productRepository)
    {
        $this->productRepository = $productRepository;
    }

    public function getAllProducts()
    {
        return $this->productRepository->getAll();
    }

    public function getProductById($id)
    {
        return $this->productRepository->findById($id);
    }

    public function createProduct(array $data)
    {
        return $this->productRepository->create($data);
    }

    public function updateProduct($id, array $data)
    {
        return $this->productRepository->update($id, $data);
    }

    public function deleteProduct($id)
    {
        return $this->productRepository->delete($id);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Bind Interfaces to Implementations

To make the repository and service injectable, bind the interfaces to their implementations in the AppServiceProvider.

Modify app/Providers/AppServiceProvider.php:

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Repositories\Interfaces\ProductRepositoryInterface;
use App\Repositories\ProductRepository;
use App\Services\Interfaces\ProductServiceInterface;
use App\Services\ProductService;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(ProductRepositoryInterface::class, ProductRepository::class);
        $this->app->bind(ProductServiceInterface::class, ProductService::class);
    }

    public function boot()
    {
        //
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Update the Controller

Now, update the ProductController to use the service layer. This keeps the controller lightweight and focused on handling HTTP requests.

Modify app/Http/Controllers/ProductController.php:

namespace App\Http\Controllers;

use App\Services\Interfaces\ProductServiceInterface;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    protected $productService;

    public function __construct(ProductServiceInterface $productService)
    {
        $this->productService = $productService;
    }

    public function index()
    {
        return response()->json($this->productService->getAllProducts());
    }

    public function show($id)
    {
        return response()->json($this->productService->getProductById($id));
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'name' => 'required|string|max:255',
            'price' => 'required|numeric',
            'stock' => 'required|integer',
        ]);
        return response()->json($this->productService->createProduct($data));
    }

    public function update(Request $request, $id)
    {
        $data = $request->validate([
            'name' => 'string|max:255',
            'price' => 'numeric',
            'stock' => 'integer',
        ]);
        return response()->json($this->productService->updateProduct($id, $data));
    }

    public function destroy($id)
    {
        return response()->json($this->productService->deleteProduct($id));
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 7: Define API Routes

Finally, define the API routes for the ProductController.

Modify routes/api.php:

use App\Http\Controllers\ProductController;

Route::prefix('products')->group(function () {
    Route::get('/', [ProductController::class, 'index']);
    Route::get('/{id}', [ProductController::class, 'show']);
    Route::post('/', [ProductController::class, 'store']);
    Route::put('/{id}', [ProductController::class, 'update']);
    Route::delete('/{id}', [ProductController::class, 'destroy']);
});
Enter fullscreen mode Exit fullscreen mode

Benefits of Using Repository and Service Pattern

  1. Decoupling: The service layer is independent of the repository implementation.

  2. Easy to Swap Implementations: You can switch to another repository (e.g., API-based repository) without changing the service or controller.

  3. Better Testing: You can mock the repository or service in unit tests.

  4. Cleaner Code: The controller is lightweight and follows SOLID principles.

Conclusion

By implementing the Repository and Service Pattern in Laravel, you can create a clean, maintainable, and scalable application. This pattern separates concerns, making your code easier to test and extend. In this guide, we walked through a simple CRUD example for managing products, but you can apply this pattern to any part of your application.

Next Steps

  • Explore advanced features like caching and pagination in the repository.

  • Implement validation and error handling in the service layer.

  • Use Dependency Injection to further decouple your application.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more