Back to Blog

Understanding the Difference Between Repository and Service in Laravel

Julian Beaujardin
Julian Beaujardin November 6th, 2024

In Laravel, the concepts of "Repository" and "Service" are often used to organize code in a way that promotes separation of concerns and clean architecture. This article will walk you through the differences between a repository and a service in Laravel, and show you how to use each of these patterns with code examples.

Table of Contents

  1. What is a Repository?
  2. What is a Service?
  3. Differences Between a Repository and a Service
  4. When to Use a Repository or a Service
  5. Code Examples
  6. Conclusion

What is a Repository?

A repository is a design pattern used to separate the data layer (database logic) from the application layer. In Laravel, a repository abstracts the database interaction, making it easier to switch to a different data source (e.g., from a MySQL database to MongoDB) without modifying the application logic.

Repositories are typically interfaces and classes that provide an abstraction layer for querying and persisting data. They focus on CRUD operations (Create, Read, Update, Delete) and handle interactions with the model layer.

Benefits of Using Repositories

  • Decouples database logic from the application logic.
  • Promotes reusability of code.
  • Provides a single point of data access, which helps with maintaining code.

What is a Service?

A service is a class or module in Laravel that contains the business logic of an application. It organizes complex operations that involve multiple steps or conditions, which may require interacting with multiple models or external APIs.

Services are responsible for coordinating actions, processing data, and implementing business rules. They often interact with repositories to perform data operations and may also call other services.

Benefits of Using Services

  • Separates business logic from the controller.
  • Makes testing of business logic easier.
  • Facilitates modular and reusable code.

Differences Between a Repository and a Service

Aspect Repository Service
Purpose Data access and interaction with database or models. Business logic and application functionality.
Focus CRUD operations. Business processes and application workflows.
Dependency Often interacts with a model. May depend on repositories, other services, or APIs.
Responsibility Abstracts data access. Manages business rules and coordinates logic.
Reusability Reusable across different parts of the app. Tied to specific business operations.

When to Use a Repository or a Service

  • Use a Repository if:

    • You need to interact with the database directly.
    • You want to abstract database operations and make them reusable.
    • You might change the underlying data source in the future.
  • Use a Service if:

    • You have complex business logic that involves multiple operations.
    • You want to keep your controller actions clean.
    • You need to coordinate different models or external services.

Code Examples

To illustrate how repositories and services can work together, let’s look at a sample application that manages Post records with the following operations:

  • Repository: Manages CRUD operations for posts.
  • Service: Contains the business logic to create a post with specific validations and additional actions.

Step 1: Create a Repository Interface

First, define an interface for the repository in App\Repositories\PostRepositoryInterface.php.

<?php

namespace App\Repositories;

use App\Models\Post;

interface PostRepositoryInterface
{
    public function getAllPosts();
    public function getPostById($id);
    public function createPost(array $data);
    public function updatePost($id, array $data);
    public function deletePost($id);
}

Step 2: Implement the Repository

Now, create a repository class that implements this interface in App\Repositories\PostRepository.php.

<?php

namespace App\Repositories;

use App\Models\Post;

class PostRepository implements PostRepositoryInterface
{
    public function getAllPosts()
    {
        return Post::all();
    }

    public function getPostById($id)
    {
        return Post::findOrFail($id);
    }

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

    public function updatePost($id, array $data)
    {
        $post = Post::findOrFail($id);
        $post->update($data);
        return $post;
    }

    public function deletePost($id)
    {
        $post = Post::findOrFail($id);
        return $post->delete();
    }
}

Step 3: Create a Service

Now, create a service that depends on the repository to manage business logic in App\Services\PostService.php.

<?php

namespace App\Services;

use App\Repositories\PostRepositoryInterface;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;

class PostService
{
    protected $postRepository;

    public function __construct(PostRepositoryInterface $postRepository)
    {
        $this->postRepository = $postRepository;
    }

    public function createPost(array $data)
    {
        $validator = Validator::make($data, [
            'title' => 'required|string|max:255',
            'content' => 'required|string',
        ]);

        if ($validator->fails()) {
            throw new ValidationException($validator);
        }

        return $this->postRepository->createPost($data);
    }

    public function getAllPosts()
    {
        return $this->postRepository->getAllPosts();
    }

    // Other business logic methods as needed...
}

Step 4: Bind the Repository Interface to the Repository Implementation

In App\Providers\AppServiceProvider.php, register the repository binding in the register method so that Laravel knows which implementation to use.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Repositories\PostRepositoryInterface;
use App\Repositories\PostRepository;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(PostRepositoryInterface::class, PostRepository::class);
    }
}

Step 5: Use the Service in a Controller

Now, inject the service into a controller, and use it to perform actions in App\Http\Controllers\PostController.php.

<?php

namespace App\Http\Controllers;

use App\Services\PostService;
use Illuminate\Http\Request;

class PostController extends Controller
{
    protected $postService;

    public function __construct(PostService $postService)
    {
        $this->postService = $postService;
    }

    public function index()
    {
        $posts = $this->postService->getAllPosts();
        return response()->json($posts);
    }

    public function store(Request $request)
    {
        $post = $this->postService->createPost($request->all());
        return response()->json($post, 201);
    }
}

Conclusion

The Repository pattern abstracts data access, while the Service pattern organizes business logic. By using these patterns in Laravel, you can build applications that are modular, maintainable, and testable. Repositories focus on data access, while services handle complex workflows, enabling a clean separation of concerns within your application.