A Beginner's Guide to Laravel Repository Pattern

Dale LantoDale Lanto
3 min read

The repository pattern separates the data access logic from the business logic by providing a clean interface to interact with data sources, making it easier to manage, swap, or extend the data layer without affecting other parts of the application.

Real-world Laravel Example:

Imagine an E-commerce System where you need to manage products stored in different databases.


💡
This is only ideal for large complex systems because this will make the handling of data more complex and could overwhelm new devs.

Swapping out the database in Laravel with the repository pattern becomes simple because all the data access logic is isolated in repositories. To swap the data source, you just implement a new repository for the new data source without changing the business logic. Here's how you can do this:

Example: Switching from a MySQL Database to an External API

1. Create a Common Interface:

This interface ensures the same methods are used regardless of the data source.

interface ProductRepositoryInterface {
    public function all();
    public function find($id);
    public function create(array $data);
    public function update($id, array $data);
    public function delete($id);
}

2. Create the Original MySQL Repository:

This repository interacts with a MySQL database using Eloquent models.

class MySQLProductRepository implements ProductRepositoryInterface {
    protected $model;

    public function __construct(Product $model) {
        $this->model = $model;
    }

    public function all() {
        return $this->model->all();
    }

    public function find($id) {
        return $this->model->findOrFail($id);
    }

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

    public function update($id, array $data) {
        $product = $this->find($id);
        $product->update($data);
        return $product;
    }

    public function delete($id) {
        $product = $this->find($id);
        return $product->delete();
    }
}

3. Create the New External API Repository:

This repository interacts with an external API instead of a database.

class ApiProductRepository implements ProductRepositoryInterface {
    protected $apiClient;

    public function __construct(ApiClient $apiClient) {
        $this->apiClient = $apiClient;
    }

    public function all() {
        return $this->apiClient->get('products');
    }

    public function find($id) {
        return $this->apiClient->get("products/{$id}");
    }

    public function create(array $data) {
        return $this->apiClient->post('products', $data);
    }

    public function update($id, array $data) {
        return $this->apiClient->put("products/{$id}", $data);
    }

    public function delete($id) {
        return $this->apiClient->delete("products/{$id}");
    }
}

4. Switch Between Repositories Using Service Providers:

Example
this can be done in RouteServiceProvider as well inside boot()

You can easily swap the data source by binding the interface to the desired repository in a service provider.

For MySQL (default binding):

public function register() {
    $this->app->bind(ProductRepositoryInterface::class, MySQLProductRepository::class);
}

For External API (switch the repository):

public function register() {
    $this->app->bind(ProductRepositoryInterface::class, ApiProductRepository::class);
}

5. Use the Repository in the Controller:

The controller doesn't need to know if it's using MySQL or an external API, as the interface abstracts this detail.

class ProductController extends Controller {
    protected $productRepo;

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

    public function index() {
        $products = $this->productRepo->all();
        return view('products.index', compact('products'));
    }
}

How to Swap Data Sources:

To switch from MySQL to an external API, all you need to do is change the binding in the service provider, without touching the controller or the rest of your codebase. This makes your application more flexible and easier to maintain.

0
Subscribe to my newsletter

Read articles from Dale Lanto directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Dale Lanto
Dale Lanto

A passionate Full Stack and Backend Web Developer with 7+ years of experience, specializing in PHP, Laravel, and a range of modern web technologies. I enjoy solving complex problems, optimizing systems, and delivering efficient, maintainable code. Check out some of my work at dalelanto.netlify.app or explore my GitHub at github.com/dalelantowork.