Repository Design pattern in Laravel

The repository pattern is an essential architectural pattern in Laravel applications that promotes clean and maintainable code. By implementing this pattern, you can separate the data access logic from the business logic, leading to improved testability and flexibility. In this tutorial, we will walk you through a complete example of using the repository pattern in a Laravel application, including the controller and views.

Assuming you have the Laravel application installed and database configuration is already done. Let’s continue further from that. If you haven’t any application then create a new one.

Creating the Repository Interface

To begin, let’s create a repository interface that defines the contract for our user repository. In the app/Repositories directory, create a new file called UserRepositoryInterface.php with the following code:

<?php

namespace App\Repositories;

interface UserRepositoryInterface
{
    public function getById($id);

    public function getAll();

    public function create(array $data);

    public function update($id, array $data);

    public function delete($id);
}

Implementing the Repository

Next, let’s create an implementation of the repository using Laravel’s Eloquent ORM. In the app/Repositories directory, create a new file called EloquentUserRepository.php with the following code:

<?php

namespace App\Repositories;

use App\Models\User;

class EloquentUserRepository implements UserRepositoryInterface
{
    public function getById($id)
    {
        return User::findOrFail($id);
    }

    public function getAll()
    {
        return User::all();
    }

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

    public function update($id, array $data)
    {
        $user = User::findOrFail($id);
        $user->update($data);

        return $user;
    }

    public function delete($id)
    {
        $user = User::findOrFail($id);
        $user->delete();
    }
}

Binding the Repository Interface

To make the repository accessible throughout the application, open the AppServiceProvider.php file located in the app/Providers directory. In the register() method, add the following code:

$this->app->bind(
    \App\Repositories\UserRepositoryInterface::class,
    \App\Repositories\EloquentUserRepository::class
);

Creating the Controller

Let’s create a controller that will utilize the user repository to perform CRUD operations. Open the terminal and enter the below command into it:

php artisan make:controller UserController

It will create a new controller called UserController.php. Let’s modify it as per our example:

<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Repositories\UserRepositoryInterface;
use Illuminate\Http\Request;

class UserController extends Controller
{
    private $userRepository;

    public function __construct(UserRepositoryInterface $userRepository)
    {
        $this->userRepository = $userRepository;
    }

    public function index()
    {
        $users = $this->userRepository->getAll();
        return view('users.index', compact('users'));
    }

    public function create()
    {
        return view('users.create');
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required|min:6',
        ]);

        $this->userRepository->create($data);

        return redirect()->route('users.index')
            ->with('success', 'User created successfully.');
    }

    public function edit($id)
    {
        $user = $this->userRepository->getById($id);
        return view('users.edit', compact('user'));
    }

    public function update(Request $request, $id)
    {
        $data = $request->validate([
            'name' => 'required',
            'email' => 'required|email',
            'password' => 'required|min:6',
        ]);

        $this->userRepository->update($id, $data);

        return redirect()->route('users.index')
            ->with('success', 'User updated successfully.');
    }

    public function destroy(User $user)
    {
        $this->userRepository->delete($user->id);

        return redirect()->route('users.index')
            ->with('success', 'User deleted successfully.');
    }
}

n the above example, we have defined all necessary methods for performing CRUD operations. The __construct method will initialize a new object for our user repository.

Further, it will manage all operations related to user experiences like showing the view, and success-failure messages.

Creating the Views

Let’s create the views for the user management functionality. In the resources/views/users directory, create the following files:

The index.blade.php (listing all users):

@extends('layouts.app')

@section('content')
    <h1>Users</h1>

    @if(session('success'))
        <div class="alert alert-success">
            {{ session('success') }}
        </div>
    @endif

    <table class="table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Email</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            @foreach($users as $user)
                <tr>
                    <td>{{ $user->name }}</td>
                    <td>{{ $user->email }}</td>
                    <td>
                        <a href="{{ route('users.edit', $user->id) }}" class="btn btn-primary">Edit</a>
                        <form action="{{ route('users.destroy', $user->id) }}" method="POST" style="display: inline;">
                            @csrf
                            @method('DELETE')
                            <button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure?')">Delete</button>
                        </form>
                    </td>
                </tr>
            @endforeach
        </tbody>
    </table>

    <a href="{{ route('users.create') }}" class="btn btn-success">Add User</a>
@endsection

The create.blade.php (form for creating a new user):

@extends('layouts.app')

@section('content')
    <h1>Add User</h1>

    <form action="{{ route('users.store') }}" method="POST">
        @csrf
        <div class="form-group">
            <label for="name">Name</label>
            <input type="text" name="name" class="form-control" required>
        </div>
        <div class="form-group">
            <label for="email">Email</label>
            <input type="email" name="email" class="form-control" required>
        </div>
        <div class="form-group">
            <label for="password">Password</label>
            <input type="password" name="password" class="form-control" required>
        </div>
        <button type="submit" class="btn btn-primary">Add User</button>
    </form>
@endsection

The edit.blade.php (form for editing an existing user):

@extends('layouts.app')

@section('content')
    <h1>Edit User</h1>

    <form action="{{ route('users.update', $user->id) }}" method="POST">
        @csrf
        @method('PUT')
        <div class="form-group">
            <label for="name">Name</label>
            <input type="text" name="name" class="form-control" value="{{ $user->name }}" required>
        </div>
        <div class="form-group">
            <label for="email">Email</label>
            <input type="email" name="email" class="form-control" value="{{ $user->email }}" required>
        </div>
        <div class="form-group">
            <label for="password">Password</label>
            <input type="password" name="password" class="form-control" required>
        </div>
        <button type="submit" class="btn btn-primary">Update User</button>
    </form>
@endsection

Conclusion

In the above example, we have seen the implementation of a repository design pattern in the Laravel application. Here, we have performed the CRUD operation of a user using a repository design pattern.

By adopting the repository pattern, you can achieve cleaner code architecture, improved testability, and better code maintenance in your Laravel applications.